Skip to content

[feature](azure) Support native SAS and OAuth2 access with a typed FE-to-BE config - #69082

Open
xylaaaaa wants to merge 62 commits into
apache:masterfrom
xylaaaaa:refactor/be-obj-storage-client
Open

xylaaaaa wants to merge 62 commits into
apache:masterfrom
xylaaaaa:refactor/be-obj-storage-client

Conversation

@xylaaaaa

@xylaaaaa xylaaaaa commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: None

Related PR: #67470

Problem Summary:

Doris reads Azure Blob natively from BE, but only with SharedKey, and the whole path is shaped around S3:

  • FE sends Azure access to BE as an S3-style property map: provider=azure, the account in AWS_ACCESS_KEY and the key in AWS_SECRET_KEY. The map cannot carry a SAS token or Entra ID client credentials, and BE infers the authentication method from which keys are present.
  • FE offers no SAS option. OAuth2 storage access only works for OneLake through the Hadoop path; for a normal Azure Blob location the OAuth2 map is a Hadoop configuration that the BE FILE_S3 reader cannot use.
  • In BE, S3 and Azure share one flat S3ClientConf (Azure reuses ak/sk/bucket as account/key/container, next to S3-only fields such as region and role), one S3ClientFactory that builds both SDK clients and owns one shared cache, and an ObjClientHolder that merges a new conf field by field and reads its conf without the lock.

This PR adds native SAS and OAuth2 (client credentials) access for Azure end to end, together with the BE refactor it builds on. It is kept as one PR so the whole path can be tested end to end; it can be split into the BE refactor, the protocol/BE part and the FE part for merging.

1. BE object storage refactor

  • Typed configuration end to end; S3Conf and S3ClientConf are gone. io::ObjClientConfig holds shared connection options, a client usage (internal storage / external access) and exactly one backend, std::variant<S3ClientConfig, AzureClientConfig>; the Azure authentication is a variant as well (SharedKey, SAS, client secret). io::ObjStorageConfig (bucket, prefix, client config) replaces S3Conf.
  • ObjStorageConfigResolver is the only conversion point: from_properties() (FE AWS_* properties, formerly convert_properties_to_s3_conf), from_storage_param() (cold-storage resources) and from_object_store_info() (storage vaults), formerly S3Conf::get_s3_conf, plus from_azure_client_config() for the typed Azure input. The flat field mapping and validation are ported unchanged. merge_update() merges a refreshed resource or vault config with the flat-merge field rules; a different backend is rejected as a different storage target.
  • ObjClientFactory validates every request with the rules of its backend, then dispatches through std::visit (a new backend without a branch fails to compile). S3ClientProvider and AzureClientProvider each build and cache their clients outside the cache lock; one shared function applies the BE rate limiter. The Azure cache is bounded by azure_client_cache_capacity (default 256, mutable): expired SAS clients go first, then the least recently used; the capacity lives in the cache and changes take effect at once. S3ClientFactory is renamed to AwsSdkManager: it no longer builds clients and keeps only the AWS SDK lifetime and AWS helpers (client configuration, credentials, CA path), which Kinesis also uses.
  • Deferred completion (Hive writes stage files and the FE completes them at commit) is a client capability: FileWriterOptions::used_by_s3_committer is renamed to deferred_completion, and ObjStorageCapabilities::deferred_completion says what the coordinator must support (ANY_COORDINATOR for S3 multipart, NAMESPACED_BLOCK_IDS for Azure blocks). VHivePartitionWriter checks it against the coordinator's supports_deferred_azure_multipart instead of comparing providers.
  • ObjClientHolder (now io/obj_storage/obj_client_holder.{h,cpp}) owns an immutable ObjClientState (config, client, generation) and replaces it as a whole. A reset merged onto a state that another reset already replaced returns ABORTED instead of overwriting the newer update.
  • ObjStorageUri replaces S3URI: parse_s3() keeps the S3 rules (and takes container and key from native Azure locations), parse_azure() adds the Azure rules (below).
  • The common IO classes are renamed: ObjStorageFileSystem, ObjStorageFileReader, ObjStorageFileWriter (obj_storage_file_*.{h,cpp}), obj_storage_file_buffer_pool, display_path(), FileSystemType::OBJECT_STORAGE (same value). Only identifiers and comments changed: debug and sync point names are kept because regression tests trigger them by name. AWS residue left the common layer (the RFC 3986 encoding flag is set once at SDK init; reader 429 handling no longer uses AWS types). Internal metric variables are renamed to obj_storage_*; exposed metric names and config keys are kept for compatibility.

2. FE-to-BE protocol (gensrc)

TAzureClientConfig { endpoint, account_name, container, credential } with union TAzureCredential { shared_key, sas, client_secret }, carried by the new optional field TFileScanRangeParams.azure_client_config (id 42; ids 41/40 are the last ones on master and branch-4.2/4.1, branch-4.0/3.1 end lower, so 42 is unused everywhere). container is optional: BE takes it from each file location and rejects a configured container that differs.

The write sinks carry the same struct as a new optional azure_client_config: TIcebergTableSink (21), TIcebergDeleteSink (16), TIcebergMergeSink (26), THiveTableSink (15). Each id is one past the last id on master, and unused on branch-4.2/4.1/4.0/3.1.

The other entries that reach object storage carry it too: TParquetMetadataParams (7, parquet_meta), TResultFileSinkOptions (24, OUTFILE / EXPORT data and success files) and TTVFTableSink (17, TVF insert); TVF schema inference already received it and BE now copies it in fetch_file_schema. These ids are unused on every branch as well. Without the typed config BE falls back to the S3-style keys, which can express only SharedKey.

3. BE

  • AzureAuthFactory builds SAS clients (token appended to the container URL) and client secret clients (Azure::Identity::ClientSecretCredential, sharing the blob transport and CA bundle; the SDK requests and refreshes the access token).
  • AzureConfigCodec decodes the Thrift config (exactly one credential); AzureConfigValidator checks the fields of the selected method and the account name against standard Azure hosts; AzureCredentialValidator parses the SAS se expiry and rejects an expired SAS. AzureClientProvider runs it on every client request, i.e. each reader open, never per range read.
  • io::ObjStorageUri parses a location by the Azure rules: abfs[s]://container@acct.dfs..., wasb[s]://container@acct.blob..., http(s)://acct.blob.../container/key and the legacy s3://container/key all become account, container and key, and the original location is kept untouched. The resolver rejects a location whose account differs from the one requests go to (account_name, or the account the endpoint names).
  • The FileFactory reader, create_fs and create_file_writer resolve a FILE_S3 location through one function: typed Azure access when FE sends it, the AWS_* properties otherwise. The scan readers copy the field from TFileScanRangeParams through one helper, io::azure_client_config_of(); the Iceberg table/delete/merge writers, the rewritable-delete reader and the Hive writer pass the sink's field to FileFactory.
  • Iceberg DELETE commits the original location. VIcebergDeleteSink used to report position delete and puffin files under output_path, the normalized form (s3://b/db/t/data for an oss:// or Azure table), so Iceberg metadata recorded the internal s3:// address. It now commits them under table_location, the raw data location, which every FE version sets to the same directory as output_path. Data files were already committed under original_output_path.

4. FE

  • New user property azure.sas_token (sensitive) with azure.auth_type = SAS; validation requires the token and an endpoint or account name. FE listing (AzureObjStorage) and the Hadoop ABFS map (fixed SAS token) support it too.
  • AzureFileSystemProperties.toMap() keeps its S3-style keys for old BEs and also writes neutral AZURE_* keys (AzureBackendPropertyKeys in fe-filesystem-api). SAS adds no legacy credential, so an old BE is never handed a wrong one. OAuth2 resolves the tenant as the FE SDK client already does and derives the authority host from azure.oauth2_server_uri; the FE SDK client now uses that authority host as well.
  • AzureThriftAdapter (fe-core) turns the neutral keys into TAzureClientConfig, and FileQueryScanNode sets it for FILE_S3 ranges. TVF scans and plugin-driven catalogs both build their location properties from the provider map, so both are covered. The TVF fetch-schema request, which BE serves before any scan, carries it too.
  • The old rule that azure.auth_type = OAuth2 is only accepted for an Iceberg REST catalog is removed: it existed because BE could only use OAuth2 through the Iceberg REST / OneLake Hadoop path.
  • Iceberg REST vended SAS: a catalog with vended credentials (e.g. Databricks Unity Catalog) returns adls.sas-token.<account host> and adls.sas-token-expires-at-ms.<account host> with each table. These keys used to be dropped by the vended-credential filter. IcebergAdlsVendedCredentials now turns them into Azure SAS properties (account and Blob endpoint from the host, token, expiry), so Iceberg scans and writes, which already overlay the vended properties, send them to BE as TAzureClientConfig. The expiry travels as TAzureSas.expires_at_ms. One storage account per table: tokens for several accounts are rejected with a message naming them.
  • PluginDrivenTableSink binds the typed config onto Iceberg and Hive sinks (AzureThriftAdapter.bindToWriteSink), from the backend properties the connector already put in the sink, so connectors are unchanged.
  • Connector scans and writes keep native Azure locations. Every path normalized through DefaultConnectorContext (Iceberg, Hive, Paimon, Hudi scan ranges and write paths) ends up in a request that carries typed Azure access, so it now uses LocationPath.ofAdaptersForNativeAccess: Azure locations are validated and kept as abfss://c@acct.dfs.core.windows.net/... instead of being rewritten to s3://c/..., which dropped the account; other storages are normalized as before. BE can then check every file's account, and Hive commits record the native location in HMS. Requests without typed access (Broker Load, Export, Outfile, backup, TVFs, streaming offsets) still get the s3:// form, which is all their BE entries parse. Paimon and Hudi JNI readers use raw paths and are unaffected; the FE Azure filesystem accepts the native forms for Hive multipart completion.
  • FileQueryScanNode binds the typed config even when a JNI scan already set the scan properties, which fixes SAS and OAuth2 reads of Iceberg position_deletes; the Iceberg plugins package the Azure FileIO dependencies.

Scope of this PR: reads of external tables and TVFs, and Iceberg/Hive writes. Outfile/Export, TVF insert, Broker Load, Resource and Storage Vault still use the S3-style properties, so SAS and OAuth2 are not available there yet.

Rolling upgrade: SharedKey reads keep working on old BEs through the S3-style keys. SAS and OAuth2 on FILE_S3 require every BE to be upgraded before they are used. Connector scans and writes send native abfss:// locations, which old BEs cannot parse, so BE must be upgraded before FE (the standard order). After the upgrade, the BE file cache keys and split affinity of Azure files change once, because their path strings change.

Outbound requests (SSRF surface): with OAuth2, BE now requests access tokens from the authority host derived from azure.oauth2_server_uri, in addition to the storage endpoint it already contacted. Both values come from catalog or TVF properties, so reaching them requires the privilege to create or alter the catalog, or to run the TVF.

Release note

Azure storage accessed through TVFs and external catalogs, including Iceberg and Hive writes, supports SAS tokens (azure.auth_type = SAS, azure.sas_token) and native BE OAuth2 client credentials, in addition to SharedKey. Iceberg REST catalogs that vend Azure SAS (such as Databricks Unity Catalog) can read and write their Azure data through the vended SAS. Iceberg position delete files are committed with the table's own location instead of the internal s3:// form. Upgrade all BEs before FE and before using SAS or OAuth2.

Check List (For Author)

  • Test

    • Unit Test (added; BE and FE were not built locally, results come from CI)
      • BE: obj_client_factory_test.cpp (resolver mapping from resource params, properties and vaults, backend-specific identity, masking, provider caching, validation, bounded Azure cache, holder snapshots, concurrent reset conflict, reset merge and backend change, expired SAS rejected before any client is built), obj_client_cache_test.cpp (LRU, expiry-first eviction, capacity changes racing with publishes), obj_storage_uri_test.cpp (the former S3URI cases), azure_typed_access_test.cpp (typed create_fs / create_file_writer) azure_config_test.cpp (codec, validator, SAS expiry parsing, resolver entry, ObjStorageUri location forms, account checks) and viceberg_delete_sink_test.cpp (delete/puffin commit path under table_location)
      • FE: AzureFileSystemPropertiesTest (native keys for SharedKey/SAS/OAuth2, SAS validation and Hadoop config, sensitive SAS key), IcebergAdlsVendedCredentialsTest (vended SAS translation, single-account rule), AzureThriftAdapterTest (including binding onto Iceberg/Hive sinks and SAS expiry) and StorageAdapterAzureNativeTest (OAuth2 outside Iceberg REST and SAS, through StorageAdapter)
    • Regression test: needs a real Azure storage account; manual end-to-end testing with SharedKey, SAS and OAuth2 is pending
    • Local checks: clang-format 16 and build-support/check-build-hygiene.sh passed
  • Behavior changed:

    • Yes. Azure FILE_S3 scans and Iceberg/Hive writes carry TAzureClientConfig and BE uses it; Iceberg writes go to the native Azure location; Iceberg delete files are committed under table_location; new SAS auth type; OAuth2 is accepted for TVFs and all catalogs, not only Iceberg REST; a reset racing with another reset on the same holder returns ABORTED; resetting a holder to another backend is rejected; flat Azure configs no longer need a placeholder region; FileSystemType prints OBJECT_STORAGE; new BE config azure_client_cache_capacity.
  • Does this need documentation?

    • Yes. azure.auth_type = SAS, azure.sas_token and the upgrade order; not included yet.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

### What problem does this PR solve?

Issue Number: None

Related PR: apache#67470

Problem Summary: BE creates every native object storage client from one flat
`S3ClientConf`. Azure reuses `ak/sk/bucket` as account/key/container, while
region, the AWS role and the AWS credential provider type sit in the same
struct and only mean something for S3. `S3ClientFactory` builds AWS and Azure
clients, owns one shared client cache, applies the rate-limit wrapper and
initializes the AWS SDK. `ObjClientHolder` keeps a mutable conf and client
side by side: `reset()` writes them under the lock, but `s3_client_conf()` and
`full_s3_path()` read the conf without it, and two concurrent resets that
both merged onto the same old conf silently overwrite each other.

This is the first step of the BE object storage refactor. It changes how
clients are configured and managed without changing any caller-facing input:

- Add `io::ObjStorageClientConfig` with shared connection options, a client
  usage (internal storage / external access) and exactly one backend
  alternative: `S3ClientConfig` or `AzureClientConfig`. Azure authentication is
  a variant of methods (SharedKey only today), so a new method is a new
  alternative instead of another loosely related field.
- Add `ObjStorageConfigResolver::from_client_conf()`, the single mapping from
  the legacy conf. All existing inputs (FE properties, `TS3StorageParam`,
  `ObjectStoreInfoPB`) still produce an `S3ClientConf` and reach the providers
  through it.
- Split construction into `S3ClientProvider` and `AzureClientProvider`, each
  with its own cache keyed by the full typed config, dispatched by
  `ObjStorageClientFactory`. SDK clients are still built outside the cache
  lock; a losing concurrent candidate is now released after unlocking. The
  BE rate-limit policy moves next to the factory and is applied by every
  provider in the same way.
- `S3ClientFactory` keeps its public API as a compatibility entry: it
  validates the legacy conf, keeps the test client hook, and still owns the
  AWS SDK lifetime, the CA certificate path and the AWS credential helpers.
- `ObjClientHolder` now owns an immutable `ObjClientState` (conf, client,
  generation) and replaces it as a whole. Readers take one snapshot, so the
  conf and client always come from the same generation. A reset is published
  only if no other publish happened since it read the state; otherwise it
  returns `ABORTED` and the holder keeps the newer state. Both callers
  (`update_s3_resource` and storage vault refresh) already handle a failed
  reset by logging a warning and keeping the existing file system.

Client identity now follows the selected backend: S3 clients are no longer
split by bucket (an AWS SDK client is not bound to a bucket), and Azure
clients are no longer split by region, token or AWS role fields that the
Azure client never read. The provider cache singleton is created after the
AWS SDK is initialized, so cached AWS clients are released before
`Aws::ShutdownAPI`.

Renaming `S3URI`, `S3FileSystem`, `S3FileReader` and `S3FileWriter`, and
migrating callers from `S3ClientConf` to the typed config, are left to
follow-up changes.

### Release note

None

### Check List (For Author)

- Test: Unit Test (added, not run)
    - Added `be/test/io/obj_storage/obj_storage_client_factory_test.cpp` for the
      resolver mapping, backend-specific identity, credential masking,
      provider caching, holder snapshots and the concurrent reset conflict.
    - Updated tests that assigned the holder's private client to use
      `set_client_for_test`.
    - BE was not compiled and unit tests were not run in this change;
      clang-format 16 and `build-support/check-build-hygiene.sh` passed.
- Behavior changed: Yes. S3 clients are shared across buckets with the same
  endpoint and credentials; Azure clients ignore S3-only fields for reuse; a
  reset that races with another reset on the same holder returns `ABORTED`
  instead of overwriting it.
- Does this need documentation: No
Copilot AI balanced review requested due to automatic review settings October 14, 2026 16:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@xylaaaaa

Copy link
Copy Markdown
Contributor Author

run buildall

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69082

Problem Summary: BE UT compilation failed with clang's
-Wmissing-designated-field-initializers (-Werror) because
ObjStorageConfigResolver::from_client_conf() built ObjStorageClientConfig
with a designated initializer that omitted `backend` and assigned it
afterwards. Build the backend alternative first and initialize all fields
in one designated initializer.

### Release note

None

### Check List (For Author)

- Test: No need to test (compile fix only; BE was not built locally,
  clang-format 16 and check-build-hygiene.sh passed)
- Behavior changed: No
- Does this need documentation: No
@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29368 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit ad388ff3d980eb96ea5518504f9984a9c608ebf7, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17584	5644	5581	5581
q2	2084	314	258	258
q3	10256	1413	836	836
q4	4680	471	341	341
q5	7435	823	532	532
q6	183	191	161	161
q7	767	823	621	621
q8	9239	1340	1091	1091
q9	5611	4321	4278	4278
q10	6832	1326	1031	1031
q11	448	257	244	244
q12	640	403	281	281
q13	18088	3644	3029	3029
q14	282	267	252	252
q15	q16	749	732	669	669
q17	1219	750	586	586
q18	7189	6249	6183	6183
q19	1250	958	622	622
q20	399	339	229	229
q21	5497	2279	2398	2279
q22	381	316	264	264
Total cold run time: 100813 ms
Total hot run time: 29368 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6171	6176	6169	6169
q2	716	577	566	566
q3	5226	5480	5016	5016
q4	2023	2156	1545	1545
q5	5269	5631	5986	5631
q6	251	195	150	150
q7	2410	2150	1933	1933
q8	3278	2949	2759	2759
q9	8192	8038	8141	8038
q10	3814	3678	3346	3346
q11	633	472	420	420
q12	675	711	519	519
q13	3618	3900	3402	3402
q14	311	302	290	290
q15	q16	714	742	674	674
q17	8355	7625	7399	7399
q18	13133	12273	13135	12273
q19	951	820	795	795
q20	2164	2151	1913	1913
q21	5880	4814	4850	4814
q22	507	448	400	400
Total cold run time: 74291 ms
Total hot run time: 68052 ms

@xylaaaaa

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 153478 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit ad388ff3d980eb96ea5518504f9984a9c608ebf7, data reload: false

query5	4314	583	461	461
query6	422	206	190	190
query7	4806	452	239	239
query8	322	182	156	156
query9	8741	4072	4050	4050
query10	450	312	247	247
query11	5993	3798	3531	3531
query12	143	97	88	88
query13	1267	471	330	330
query14	6063	4156	3918	3918
query14_1	3526	3510	3580	3510
query15	209	196	189	189
query16	945	438	418	418
query17	876	658	541	541
query18	2419	426	316	316
query19	195	166	138	138
query20	89	86	82	82
query21	211	144	118	118
query22	13118	13018	12880	12880
query23	13472	12948	12550	12550
query23_1	12528	12595	12636	12595
query24	7107	863	483	483
query24_1	485	483	480	480
query25	546	424	362	362
query26	1292	263	144	144
query27	2758	439	279	279
query28	4630	2002	1996	1996
query29	1558	609	458	458
query30	305	218	183	183
query31	1021	926	809	809
query32	150	96	92	92
query33	550	310	254	254
query34	946	849	512	512
query35	774	755	659	659
query36	864	807	713	713
query37	129	103	95	95
query38	1799	1747	1721	1721
query39	821	819	756	756
query39_1	746	732	747	732
query40	226	118	102	102
query41	74	68	70	68
query42	92	86	83	83
query43	381	390	335	335
query44	1383	715	714	714
query45	190	192	164	164
query46	857	966	580	580
query47	2989	2993	2937	2937
query48	301	343	214	214
query49	581	403	298	298
query50	687	294	228	228
query51	10635	10625	10682	10625
query52	79	83	76	76
query53	189	214	153	153
query54	252	216	184	184
query55	74	71	63	63
query56	238	211	209	209
query57	1616	1597	1551	1551
query58	283	269	258	258
query59	2104	2162	1982	1982
query60	274	245	231	231
query61	150	148	150	148
query62	393	336	290	290
query63	199	172	171	171
query64	2771	973	767	767
query65	3293	3282	3259	3259
query66	1781	429	323	323
query67	20144	20188	20015	20015
query68	3103	1025	622	622
query69	382	285	249	249
query70	890	801	787	787
query71	311	240	213	213
query72	2883	2531	2274	2274
query73	540	541	298	298
query74	4630	4469	4333	4333
query75	2364	2289	1989	1989
query76	2385	1044	633	633
query77	349	394	288	288
query78	9735	9645	9178	9178
query79	987	867	530	530
query80	1212	441	354	354
query81	589	312	281	281
query82	618	141	109	109
query83	309	204	181	181
query84	308	134	106	106
query85	873	418	383	383
query86	398	249	233	233
query87	2013	1965	1829	1829
query88	3687	2725	2696	2696
query89	341	300	258	258
query90	1914	191	181	181
query91	161	161	131	131
query92	96	92	83	83
query93	1060	1030	593	593
query94	626	313	282	282
query95	592	346	319	319
query96	667	541	237	237
query97	2467	2456	2338	2338
query98	166	153	146	146
query99	778	769	659	659
Total cold run time: 235965 ms
Total hot run time: 153478 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.56 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit ad388ff3d980eb96ea5518504f9984a9c608ebf7, data reload: false

query1	0.01	0.00	0.00
query2	0.11	0.05	0.04
query3	0.27	0.12	0.12
query4	1.61	0.12	0.13
query5	0.24	0.25	0.24
query6	1.18	0.69	0.67
query7	0.04	0.01	0.00
query8	0.05	0.04	0.04
query9	0.41	0.35	0.35
query10	0.62	0.57	0.60
query11	0.21	0.15	0.14
query12	0.19	0.15	0.14
query13	0.50	0.49	0.49
query14	1.04	1.01	1.01
query15	0.63	0.60	0.61
query16	0.36	0.37	0.31
query17	1.15	1.15	1.19
query18	0.23	0.21	0.21
query19	2.11	1.97	2.05
query20	0.02	0.01	0.01
query21	15.48	0.29	0.14
query22	4.47	0.06	0.05
query23	16.27	0.33	0.11
query24	2.73	0.71	0.44
query25	0.11	0.06	0.03
query26	1.38	0.25	0.15
query27	0.05	0.04	0.03
query28	2.00	0.59	0.41
query29	12.52	4.13	3.33
query30	0.28	0.14	0.14
query31	2.77	0.57	0.34
query32	3.22	0.61	0.54
query33	3.27	3.32	3.16
query34	15.50	4.03	3.39
query35	3.38	3.35	3.37
query36	0.55	0.45	0.42
query37	0.10	0.07	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.15	0.14
query41	0.10	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 95.51 s
Total hot run time: 24.56 s

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29722 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit a827621e1f08bc1dbff17bccd9e6df702031787b, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17595	5815	5705	5705
q2	2110	330	277	277
q3	10212	1514	870	870
q4	4680	486	343	343
q5	7449	832	531	531
q6	206	202	157	157
q7	827	822	594	594
q8	9242	1517	1217	1217
q9	5665	4448	4433	4433
q10	6846	1295	1034	1034
q11	439	253	236	236
q12	644	426	280	280
q13	18068	3626	2954	2954
q14	275	273	248	248
q15	q16	739	726	670	670
q17	1327	753	586	586
q18	6989	6219	6164	6164
q19	1096	1092	641	641
q20	400	345	223	223
q21	5026	2299	2449	2299
q22	381	321	260	260
Total cold run time: 100216 ms
Total hot run time: 29722 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6352	6303	6308	6303
q2	707	586	542	542
q3	5216	5378	4918	4918
q4	2095	2214	1536	1536
q5	5270	5705	5726	5705
q6	290	216	167	167
q7	2342	2028	1879	1879
q8	3276	2806	2891	2806
q9	7984	7950	8293	7950
q10	3822	3726	3355	3355
q11	684	451	426	426
q12	724	724	544	544
q13	3624	3977	3319	3319
q14	325	334	299	299
q15	q16	746	724	657	657
q17	8616	7695	7079	7079
q18	13233	12237	13121	12237
q19	1058	858	856	856
q20	2196	2192	1934	1934
q21	6081	4945	5053	4945
q22	517	461	416	416
Total cold run time: 75158 ms
Total hot run time: 67873 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 152943 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit a827621e1f08bc1dbff17bccd9e6df702031787b, data reload: false

query5	4330	592	441	441
query6	428	212	188	188
query7	4821	446	233	233
query8	342	166	154	154
query9	8753	3934	3952	3934
query10	476	311	279	279
query11	6033	3839	3544	3544
query12	141	90	87	87
query13	1240	449	343	343
query14	6112	4064	3758	3758
query14_1	3524	3560	3569	3560
query15	209	205	179	179
query16	943	437	409	409
query17	867	666	546	546
query18	2410	417	318	318
query19	208	164	134	134
query20	88	92	81	81
query21	218	132	114	114
query22	12993	13063	12815	12815
query23	13511	12872	12501	12501
query23_1	12498	12630	12789	12630
query24	7109	855	474	474
query24_1	486	487	492	487
query25	546	438	367	367
query26	1285	268	147	147
query27	2741	442	275	275
query28	4636	1974	1945	1945
query29	1540	599	449	449
query30	301	219	186	186
query31	1036	930	818	818
query32	142	105	96	96
query33	519	303	256	256
query34	920	860	496	496
query35	758	764	652	652
query36	815	815	780	780
query37	133	105	91	91
query38	1810	1720	1687	1687
query39	800	808	757	757
query39_1	742	743	754	743
query40	220	116	99	99
query41	73	69	71	69
query42	90	94	87	87
query43	363	382	334	334
query44	1288	708	733	708
query45	185	180	166	166
query46	852	966	566	566
query47	3023	3006	2941	2941
query48	306	304	215	215
query49	574	399	301	301
query50	706	279	211	211
query51	10603	10716	10609	10609
query52	82	78	70	70
query53	185	208	150	150
query54	259	194	173	173
query55	70	72	63	63
query56	225	218	213	213
query57	1627	1604	1559	1559
query58	289	261	251	251
query59	2118	2081	1905	1905
query60	297	241	226	226
query61	159	151	154	151
query62	386	338	290	290
query63	197	165	165	165
query64	2722	993	777	777
query65	3300	3247	3228	3228
query66	1787	410	309	309
query67	20131	20332	20413	20332
query68	3023	1000	618	618
query69	392	297	256	256
query70	838	816	809	809
query71	284	222	206	206
query72	2684	2575	2255	2255
query73	521	529	294	294
query74	4617	4494	4302	4302
query75	2341	2336	1928	1928
query76	2296	1024	596	596
query77	339	383	268	268
query78	9986	9666	9118	9118
query79	978	863	516	516
query80	856	413	346	346
query81	592	320	279	279
query82	578	141	116	116
query83	315	195	181	181
query84	320	120	105	105
query85	905	432	368	368
query86	355	246	233	233
query87	2014	1970	1833	1833
query88	3627	2705	2664	2664
query89	337	307	264	264
query90	1823	180	178	178
query91	161	148	126	126
query92	97	89	89	89
query93	1017	1001	578	578
query94	535	302	284	284
query95	577	365	379	365
query96	669	524	238	238
query97	2462	2425	2301	2301
query98	164	153	146	146
query99	775	766	653	653
Total cold run time: 235220 ms
Total hot run time: 152943 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.49 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit a827621e1f08bc1dbff17bccd9e6df702031787b, data reload: false

query1	0.00	0.00	0.00
query2	0.10	0.04	0.05
query3	0.27	0.12	0.12
query4	1.61	0.12	0.12
query5	0.27	0.25	0.26
query6	1.16	0.68	0.68
query7	0.03	0.01	0.01
query8	0.05	0.04	0.04
query9	0.42	0.34	0.34
query10	0.58	0.56	0.57
query11	0.21	0.15	0.14
query12	0.18	0.14	0.14
query13	0.49	0.48	0.48
query14	1.04	1.02	1.00
query15	0.65	0.61	0.61
query16	0.35	0.31	0.35
query17	1.17	1.16	1.13
query18	0.23	0.21	0.21
query19	2.09	1.92	2.03
query20	0.02	0.02	0.01
query21	15.48	0.25	0.14
query22	4.42	0.05	0.06
query23	16.25	0.33	0.12
query24	3.01	0.72	0.46
query25	0.11	0.06	0.06
query26	1.83	0.24	0.14
query27	0.05	0.04	0.03
query28	2.30	0.60	0.41
query29	12.47	4.11	3.29
query30	0.28	0.15	0.14
query31	2.77	0.57	0.34
query32	3.26	0.62	0.51
query33	3.15	3.19	3.25
query34	15.55	4.02	3.37
query35	3.34	3.34	3.33
query36	0.55	0.44	0.44
query37	0.10	0.07	0.06
query38	0.05	0.04	0.04
query39	0.03	0.03	0.03
query40	0.18	0.14	0.15
query41	0.07	0.03	0.03
query42	0.04	0.02	0.02
query43	0.04	0.04	0.04
Total cold run time: 96.25 s
Total hot run time: 24.49 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 98.59% (70/71) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.05% (35646/46261)
Line Coverage 62.32% (403326/647140)
Region Coverage 58.73% (340515/579838)
Branch Coverage 59.66% (156910/263021)

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69082

Problem Summary: Align the names introduced by this PR with the agreed design
for native Azure authentication, which uses the ObjClient* family next to the
existing ObjClientHolder:

- ObjStorageClientFactory -> ObjClientFactory (obj_client_factory.{h,cpp})
- ObjStorageClientConfig / ObjStorageClientConfigHash -> ObjClientConfig /
  ObjClientConfigHash
- ObjStorageClientCache -> ObjClientCache (obj_client_cache.h)
- obj_storage_client_factory_test.cpp -> obj_client_factory_test.cpp

ObjStorageClient (the shared object operation interface in common) and the
ObjStorage* IO types are unchanged. This is a pure rename with no behavior
change.

### Release note

None

### Check List (For Author)

- Test: No need to test (pure rename; BE was not built locally, clang-format 16
  and check-build-hygiene.sh passed)
- Behavior changed: No
- Does this need documentation: No
@xylaaaaa

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29594 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 90c15f1237bb15d3fc5475606f533145d26ed859, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17595	5619	5544	5544
q2	2140	300	245	245
q3	10249	1417	844	844
q4	4678	477	345	345
q5	7422	798	540	540
q6	186	191	158	158
q7	759	796	613	613
q8	9244	1375	1052	1052
q9	5638	4275	4266	4266
q10	6808	1314	1027	1027
q11	444	260	236	236
q12	644	402	287	287
q13	18092	3640	3037	3037
q14	282	263	249	249
q15	q16	742	734	656	656
q17	1198	743	585	585
q18	7028	6264	6204	6204
q19	1242	979	603	603
q20	380	335	219	219
q21	5483	2579	2693	2579
q22	400	377	305	305
Total cold run time: 100654 ms
Total hot run time: 29594 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6731	6595	6795	6595
q2	761	621	566	566
q3	5742	5833	5387	5387
q4	2065	2150	1557	1557
q5	5682	5615	5860	5615
q6	250	195	150	150
q7	2302	2087	1858	1858
q8	3129	2761	2760	2760
q9	8068	8152	7737	7737
q10	3644	3608	3264	3264
q11	599	400	368	368
q12	658	683	503	503
q13	3272	3560	2991	2991
q14	286	286	273	273
q15	q16	663	686	625	625
q17	7812	6975	6894	6894
q18	13107	12257	13012	12257
q19	913	783	792	783
q20	2169	2197	1931	1931
q21	5876	4787	4771	4771
q22	495	466	413	413
Total cold run time: 74224 ms
Total hot run time: 67298 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 152362 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 90c15f1237bb15d3fc5475606f533145d26ed859, data reload: false

query5	4316	581	465	465
query6	435	213	195	195
query7	4811	460	233	233
query8	325	182	157	157
query9	8771	3970	3935	3935
query10	459	315	269	269
query11	5978	3845	3526	3526
query12	147	94	88	88
query13	1256	444	333	333
query14	6089	4098	3781	3781
query14_1	3654	3525	3557	3525
query15	219	201	181	181
query16	960	448	427	427
query17	866	666	544	544
query18	2431	429	311	311
query19	200	170	145	145
query20	88	85	85	85
query21	213	134	111	111
query22	12956	13015	12884	12884
query23	13430	13030	12462	12462
query23_1	12579	12582	12529	12529
query24	7115	837	472	472
query24_1	482	474	473	473
query25	540	424	363	363
query26	1344	258	145	145
query27	2757	450	275	275
query28	4622	1943	1935	1935
query29	1614	613	452	452
query30	310	232	186	186
query31	1028	934	806	806
query32	164	97	93	93
query33	528	310	248	248
query34	912	879	497	497
query35	766	762	663	663
query36	807	828	738	738
query37	135	104	95	95
query38	1812	1815	1683	1683
query39	806	820	750	750
query39_1	740	737	761	737
query40	264	113	94	94
query41	68	63	63	63
query42	86	82	81	81
query43	364	378	338	338
query44	1276	692	701	692
query45	184	177	160	160
query46	839	965	573	573
query47	3010	2874	2868	2868
query48	290	307	213	213
query49	582	397	296	296
query50	683	285	213	213
query51	10658	10481	10390	10390
query52	79	81	70	70
query53	193	214	150	150
query54	247	194	180	180
query55	72	71	63	63
query56	238	225	202	202
query57	1603	1579	1576	1576
query58	294	255	253	253
query59	2147	2172	1906	1906
query60	287	242	220	220
query61	146	138	146	138
query62	389	344	283	283
query63	196	163	174	163
query64	2741	932	812	812
query65	3299	3230	3236	3230
query66	1781	417	308	308
query67	20559	20325	20150	20150
query68	3016	997	611	611
query69	386	290	242	242
query70	834	773	804	773
query71	291	250	206	206
query72	2796	2568	2334	2334
query73	516	529	300	300
query74	4576	4478	4299	4299
query75	2339	2312	1942	1942
query76	2331	1027	615	615
query77	339	396	274	274
query78	9714	9635	9144	9144
query79	968	894	523	523
query80	720	445	351	351
query81	543	315	271	271
query82	1037	133	106	106
query83	275	203	192	192
query84	322	122	103	103
query85	918	414	378	378
query86	345	234	241	234
query87	2010	1980	1811	1811
query88	3606	2706	2676	2676
query89	348	302	265	265
query90	1747	184	182	182
query91	160	155	130	130
query92	100	84	92	84
query93	1009	1008	581	581
query94	488	315	275	275
query95	592	396	321	321
query96	664	527	239	239
query97	2464	2436	2323	2323
query98	167	153	147	147
query99	781	769	646	646
Total cold run time: 235478 ms
Total hot run time: 152362 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.48 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 90c15f1237bb15d3fc5475606f533145d26ed859, data reload: false

query1	0.01	0.01	0.01
query2	0.12	0.05	0.05
query3	0.28	0.11	0.11
query4	1.61	0.13	0.13
query5	0.26	0.24	0.24
query6	1.16	0.68	0.68
query7	0.04	0.00	0.00
query8	0.05	0.04	0.04
query9	0.40	0.36	0.34
query10	0.58	0.54	0.60
query11	0.20	0.14	0.14
query12	0.18	0.14	0.14
query13	0.49	0.49	0.50
query14	1.03	1.01	1.00
query15	0.62	0.61	0.61
query16	0.35	0.34	0.31
query17	1.17	1.11	1.16
query18	0.23	0.22	0.20
query19	2.10	1.99	2.01
query20	0.02	0.02	0.01
query21	15.49	0.28	0.15
query22	4.48	0.06	0.06
query23	16.23	0.33	0.12
query24	2.91	1.04	0.40
query25	0.12	0.07	0.04
query26	1.56	0.24	0.14
query27	0.05	0.03	0.04
query28	2.25	0.57	0.38
query29	12.52	4.28	3.31
query30	0.28	0.14	0.13
query31	2.77	0.58	0.33
query32	3.21	0.62	0.52
query33	3.29	3.15	3.17
query34	15.39	4.04	3.42
query35	3.34	3.38	3.36
query36	0.55	0.46	0.43
query37	0.10	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.17	0.15	0.15
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.03
Total cold run time: 95.87 s
Total hot run time: 24.48 s

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69082

Problem Summary: ObjClientFactory::get_or_create() selected the client
provider with std::get_if<S3ClientConfig> and fell back to
std::get<AzureClientConfig>. Adding a third alternative to
ObjClientConfig::backend would still compile, and a config of the new type
would throw bad_variant_access at runtime. Dispatch through std::visit to
one private overload per backend instead, so a missing overload is a
compile error, as the hash and to_string helpers of ObjClientConfig already
do.

### Release note

None

### Check List (For Author)

- Test: No need to test (dispatch is equivalent for both existing
  alternatives and covered by obj_client_factory_test; BE was not built
  locally, clang-format 16 and check-build-hygiene.sh passed)
- Behavior changed: No
- Does this need documentation: No
@xylaaaaa

Copy link
Copy Markdown
Contributor Author

run buildall

…ntials

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69082

Problem Summary: FE passes Azure access to BE through the S3-style
properties map, reusing AWS_ACCESS_KEY / AWS_SECRET_KEY for the account and
key. That map cannot express a SAS token or Entra ID client credentials, so
the native BE Azure client only supports SharedKey, and OAuth2 storage
access only works for OneLake through the Hadoop path.

This change adds a typed FE-to-BE protocol and the BE side of it:

- gensrc: TAzureClientConfig with a TAzureCredential union (shared_key,
  sas, client_secret), carried by the new optional field
  TFileScanRangeParams.azure_client_config (id 42, unused on master and on
  branch-4.2/4.1/4.0/3.1).
- AzureAuthFactory builds SAS clients (token appended to the container
  URL) and client secret clients (Azure::Identity::ClientSecretCredential
  sharing the blob transport).
- AzureAuthConfig gains AzureSasConfig and AzureClientSecretConfig;
  hash/to_string cover them and keep secrets masked.
- AzureConfigCodec decodes TAzureClientConfig (exactly one credential;
  container from the file location unless configured, and both must
  match); AzureConfigValidator checks the fields of the selected method
  and the account against standard Azure hosts;
  AzureCredentialValidator parses the SAS "se" expiry and rejects an
  expired SAS. AzureClientProvider runs it on every client request, i.e.
  each reader open, never per range read.
- ObjStorageConfigResolver::from_azure_client_config() is the entry for
  the typed input. FileFactory uses it for FILE_S3 reads when the scan
  params carry azure_client_config, and ignores the S3-style keys then.
- ObjClientHolder now keeps the typed ObjClientConfig in its state, plus
  the legacy conf when built from one; a holder built from a typed config
  initializes through ObjClientFactory directly.
- The scan readers that build FileSystemProperties from
  TFileScanRangeParams copy azure_client_config.

### Release note

None

### Check List (For Author)

- Test: Unit Test (added, not run; BE was not built locally,
  clang-format 16 and check-build-hygiene.sh passed)
    - azure_config_test.cpp: codec, validator, SAS expiry parsing,
      expired SAS, resolver entry, masking and identity
    - obj_client_factory_test.cpp: typed holder initialization and an
      expired SAS rejected before any client is built
- Behavior changed: No for existing requests; only requests that carry
  the new field take the new path.
- Does this need documentation: No
### What problem does this PR solve?

Issue Number: None

Related PR: apache#69082

Problem Summary: FE hands Azure access to BE as an S3-style map
(AWS_ACCESS_KEY = account, AWS_SECRET_KEY = key). That map has no way to
carry a SAS token or Entra ID client credentials, so FE offered no SAS
option at all, and OAuth2 storage access to a normal Azure Blob location
reached BE as a Hadoop configuration it cannot use on the FILE_S3 path.

This change fills the new TAzureClientConfig from FE:

- New user property azure.sas_token (sensitive) with
  azure.auth_type = SAS; validation requires the token and an endpoint
  or account name. FE listing (AzureObjStorage) uses the SAS too, and the
  Hadoop map configures hadoop-azure's fixed SAS token for ABFS access.
- AzureFileSystemProperties.toMap() keeps its S3-style keys for old BEs
  (SAS adds no legacy credential, so an old BE is never handed a wrong
  one) and also writes neutral AZURE_* keys (AzureBackendPropertyKeys in
  fe-filesystem-api). OAuth2 resolves the tenant as the FE SDK client
  already does and derives the authority host from oauth2_server_uri; the
  FE SDK client now uses that authority host as well.
- AzureThriftAdapter (fe-core) is the only place that knows the Thrift
  shape: it turns the neutral keys into TAzureClientConfig.
  FileQueryScanNode sets it on TFileScanRangeParams for FILE_S3 ranges,
  which covers TVF scans and plugin-driven catalogs, since both build
  their location properties from the provider map.

Rolling upgrade: SharedKey keeps working on old BEs through the S3-style
keys. SAS and OAuth2 on FILE_S3 need every BE upgraded first.

Outbound requests: with OAuth2, BE now requests tokens from the
authority host derived from azure.oauth2_server_uri, in addition to the
storage endpoint. Both come from catalog/TVF properties, so reaching them
requires the privilege to create or alter that catalog, or to run the
TVF.

### Release note

Azure storage accessed through TVF or external catalogs supports SAS
tokens (azure.auth_type = SAS, azure.sas_token) and native BE OAuth2
client credentials, in addition to SharedKey. Upgrade all BEs before using
SAS or OAuth2.

### Check List (For Author)

- Test: Unit Test (added, not run; FE was not built locally)
    - AzureFileSystemPropertiesTest: native keys for SharedKey, SAS and
      OAuth2, SAS validation, SAS hadoop config, sensitive SAS key
    - AzureThriftAdapterTest: each credential, no native keys, unknown
      auth type
- Behavior changed: Yes. The Azure backend map carries AZURE_* keys and
  FILE_S3 scans carry TAzureClientConfig; new SAS auth type.
- Does this need documentation: Yes (azure.auth_type = SAS and
  azure.sas_token), not included in this change
@xylaaaaa

xylaaaaa commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

xylaaaaa added a commit to xylaaaaa/doris that referenced this pull request Nov 3, 2026
…onfiguration

Issue Number: None

Related PR: apache#69082

Problem Summary: Every BE object storage entry (FE properties, cold-storage resources, storage vaults) produced one flat `S3Conf` / `S3ClientConf` that carried all providers in a single shape: Azure reused ak/sk/bucket as account/key/container, while region, role_arn and the credential provider type only meant something for S3. `S3ClientFactory::create` then branched on the provider to build an S3 or an Azure client, and `ObjClientHolder` merged credential refreshes field by field into that flat struct. A backend-specific field could leak into the other backend's identity or validation (for example, an Azure configuration still needed a region), and adding an Azure authentication method would have meant more flat fields that S3 must ignore.

This is the first step of splitting apache#69082 (BE object storage refactor and native Azure SAS / OAuth2 access). It only restructures the BE; no FE change, no Thrift change, and Azure still supports only SharedKey.

- Typed configuration. `io::ObjClientConfig` holds the shared connection options, the client usage (internal storage / external access) and exactly one backend, `std::variant<S3ClientConfig, AzureClientConfig>`. The Azure authentication is a variant as well, with SharedKey as its only alternative for now. `io::ObjStorageConfig` (bucket, prefix, client) replaces `S3Conf`; `S3Conf` and `S3ClientConf` are removed.
- One conversion point. `ObjStorageConfigResolver::from_properties` (formerly `S3ClientFactory::convert_properties_to_s3_conf`), `from_storage_param` and `from_object_store_info` (formerly `S3Conf::get_s3_conf`) turn every source into the typed configuration. The flat field mapping and its validation are ported unchanged. `merge_update` merges a refreshed resource or vault configuration with the same field rules as the flat merge.
- Client construction by provider. `ObjClientFactory` validates every request with the rules of its backend (the checks `S3ClientFactory::create` applied) and dispatches through `std::visit`, so a backend without a branch fails to compile. `S3ClientProvider` and `AzureClientProvider` build and cache their clients outside the cache lock, and one shared function applies the BE rate limiter. `ObjClientFactory` also owns the test hook `set_client_creator_for_test`. `S3ClientFactory` keeps only the AWS SDK lifetime and the AWS helpers (client configuration, credentials provider, CA path), which Kinesis also uses.
- Holder. `ObjClientHolder` moves to `io/obj_storage/obj_client_holder.{h,cpp}` and owns an immutable `ObjClientState` (config, client, generation) that it replaces as a whole, so a reader never pairs a new config with an old client.
- Locations. `ObjStorageUri::parse_s3` replaces `S3URI` with the same rules. `FileFactory` resolves FILE_S3 locations through one function for the reader, `create_fs` and `create_file_writer`; the other callers (export, snapshot, connectivity test, cold storage, storage vaults, AI embed, Kinesis, benchmarks, spill) use the resolver.
- GCP IAM credentials (apache#68540) move with the S3 fields: `S3AuthConfig::credential` carries the provider-native `CredentialConfig`, the resolver parses and converts it for all three sources and validates it as before, `ObjClientFactory` validates it on every request, and `S3ClientProvider` builds the client through `make_s3_client` with the GCS V4 signed URL generator. A reset takes the vendor and credential from the update, as the flat merge does.
- The AWS SDK RFC 3986 encoding flag is set once at SDK initialization instead of in every reader and writer constructor, and the reader no longer uses AWS types for HTTP 429.

Behavior changes:
1. The S3 client cache no longer keys on the bucket: different buckets with the same endpoint, credentials and connection options share one client. Building an S3 client never used the bucket.
2. A holder reset merged onto a state that another reset already replaced returns `Aborted` instead of overwriting the newer update; the caller retries with its next refresh.
3. A holder can no longer be reset to another backend (InvalidArgument), which is a different storage target.
4. A flat Azure configuration no longer needs a region (FE sent a placeholder).

None

- Test: Unit Test (new obj_client_factory_test and obj_storage_uri_test, the latter porting the S3URI cases; existing users, including the GCP IAM cases of s3_client_factory_test, migrated, with test configs built through testutil/obj_storage_test_util.h). Not run locally; run in CI.
- Behavior changed: Yes, as listed above
- Does this need documentation: No
xylaaaaa added a commit to xylaaaaa/doris that referenced this pull request Nov 3, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#69605

Problem Summary: The holder tests in obj_client_factory_test call secret_key_of, but the helper was dropped together with an adjacent test when this PR was split from apache#69082, so the BE unit tests did not compile. The helper is restored.

### Release note

None

### Check List (For Author)

- Test: Unit Test (compiled and run in CI)
- Behavior changed: No
- Does this need documentation: No
…torage-client

master removed the legacy file scanner (apache#69723): be/src/exec/scan/file_scanner.{h,cpp} and the
V1 readers be/src/format/{csv/csv_reader,json/new_json_reader,orc/vorc_reader,
parquet/vparquet_reader,text/text_reader}.cpp. They are deleted here as in master.

- The V1 rejection of Azure SAS / OAuth2 (FileScanner::_check_storage_access and its test in
  file_scanner_v2_test.cpp) goes with the V1 scanner: every scan now runs on FileScannerV2,
  which serves typed Azure access.
- The V1 readers' copy of TFileScanRangeParams.azure_client_config has its counterpart on the V2
  paths: TableReader, fetch_file_schema (now used for every schema RPC format), the Iceberg
  reader's delete files, the deletion vector reader and parquet_meta all set it; the Iceberg
  delete file helper now reads through TableReader with the delete sink's scan params.

obj_storage_file_reader.cpp takes master's read IO trace (`s3_get` records with io_ctx) and
atomic statistics under the ObjStorageFileReader names.

Tests from master moved to the typed client API: s3_file_reader_test.cpp (ObjClientConfig,
set_client_for_test, ObjStorageFileReader, AwsSdkManager), json_reader_test.cpp and
csv_reader_test.cpp (ObjClientFactory::set_client_creator_for_test with ObjClientConfig).
@xylaaaaa

xylaaaaa commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

…tial check

Issue Number: None

Related PR: apache#69605

Problem Summary: The previous commit moved the Azure authentication model to common and also
made `S3Accessor::init` reject an Azure SharedKey configuration with only one of the account
name and the key. In non-vault mode a failed accessor init fails `InstanceRecycler::init`, so
one such storage entry would stop every recycle task of the instance, including the ones that
do not touch object storage, where before only that storage failed its requests. The meta
service already requires both values for Azure when it stores them, so the check guarded
nothing that can be stored.

Recycler now only shares the authentication type and `AzureAuthFactory` with BE and builds
the client exactly as before. `validate_azure_auth` stays the rule BE checks its inputs with;
its comment says that Recycler relies on the meta service validation instead. The BE test of
the common rules is renamed to `AzureAuthRulesLiveInCommon`.

None

- Test: No new test (Recycler behaves as before the previous commit; BE UT and cloud UT in CI)
- Behavior changed: No (restores the Recycler behavior)
- Does this need documentation: No
@xylaaaaa

xylaaaaa commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28903 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 0e1d5fa5f807a2149344d8a3285c2a46c1bfc90d, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17613	5167	5075	5075
q2	2125	349	262	262
q3	10136	1406	830	830
q4	4684	468	341	341
q5	7464	801	539	539
q6	183	188	152	152
q7	742	798	610	610
q8	9251	1353	1025	1025
q9	5695	4237	4236	4236
q10	6870	1293	1040	1040
q11	435	244	226	226
q12	644	394	273	273
q13	18110	4176	3052	3052
q14	283	274	251	251
q15	q16	736	732	678	678
q17	1241	762	583	583
q18	6985	6197	6146	6146
q19	1289	966	609	609
q20	403	352	234	234
q21	5508	2468	2516	2468
q22	377	343	273	273
Total cold run time: 100774 ms
Total hot run time: 28903 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6052	6000	6154	6000
q2	711	601	532	532
q3	5698	5853	5250	5250
q4	2001	2189	1560	1560
q5	6009	5688	5578	5578
q6	240	206	146	146
q7	2258	1984	1763	1763
q8	2978	2694	2684	2684
q9	7803	7453	7447	7447
q10	3673	3573	3123	3123
q11	575	442	394	394
q12	675	661	510	510
q13	3307	3636	3038	3038
q14	283	284	276	276
q15	q16	667	672	614	614
q17	7769	7031	7020	7020
q18	12905	12185	12873	12185
q19	921	781	776	776
q20	2159	2144	1949	1949
q21	5573	4618	4721	4618
q22	481	448	391	391
Total cold run time: 72738 ms
Total hot run time: 65854 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151736 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 0e1d5fa5f807a2149344d8a3285c2a46c1bfc90d, data reload: false

query5	4329	585	447	447
query6	431	206	206	206
query7	4821	445	236	236
query8	321	165	171	165
query9	8782	3223	3227	3223
query10	494	319	272	272
query11	5964	3854	3566	3566
query12	148	95	87	87
query13	1257	441	348	348
query14	6073	3940	3638	3638
query14_1	3411	3472	3453	3453
query15	205	200	181	181
query16	930	427	436	427
query17	823	648	521	521
query18	2409	411	299	299
query19	198	161	133	133
query20	84	80	80	80
query21	212	127	104	104
query22	13083	12971	12989	12971
query23	13532	12820	12415	12415
query23_1	12509	12601	12428	12428
query24	7367	833	479	479
query24_1	474	492	488	488
query25	515	399	343	343
query26	1270	253	138	138
query27	2789	435	272	272
query28	4605	2118	2101	2101
query29	1552	574	440	440
query30	293	212	180	180
query31	1011	923	808	808
query32	141	92	94	92
query33	576	290	241	241
query34	918	847	521	521
query35	719	740	632	632
query36	819	797	748	748
query37	115	93	84	84
query38	1773	1731	1693	1693
query39	800	794	741	741
query39_1	738	717	739	717
query40	215	112	91	91
query41	69	65	64	64
query42	85	81	79	79
query43	343	356	317	317
query44	1309	713	715	713
query45	176	180	164	164
query46	837	965	555	555
query47	2886	3075	2935	2935
query48	299	310	230	230
query49	574	403	292	292
query50	687	282	217	217
query51	10137	10494	10113	10113
query52	78	79	71	71
query53	187	207	152	152
query54	251	209	176	176
query55	70	66	66	66
query56	226	221	224	221
query57	1655	1611	1581	1581
query58	306	269	254	254
query59	2152	2224	1965	1965
query60	294	245	226	226
query61	151	146	149	146
query62	414	327	281	281
query63	192	157	159	157
query64	2721	935	740	740
query65	3321	3286	3299	3286
query66	1775	415	290	290
query67	20219	20109	19977	19977
query68	3245	1007	625	625
query69	410	294	243	243
query70	860	795	779	779
query71	301	234	203	203
query72	2817	2346	2468	2346
query73	526	546	306	306
query74	4591	4517	4343	4343
query75	2326	2290	1940	1940
query76	2374	1022	581	581
query77	362	383	292	292
query78	9664	9663	9186	9186
query79	866	900	542	542
query80	495	445	387	387
query81	523	327	271	271
query82	224	137	113	113
query83	211	212	193	193
query84	297	135	104	104
query85	848	497	447	447
query86	260	248	232	232
query87	2012	1986	1815	1815
query88	3855	2883	2896	2883
query89	316	288	245	245
query90	2068	172	165	165
query91	155	159	129	129
query92	101	91	92	91
query93	979	998	585	585
query94	461	301	279	279
query95	575	387	320	320
query96	703	494	245	245
query97	2445	2450	2321	2321
query98	159	155	147	147
query99	753	750	660	660
Total cold run time: 233639 ms
Total hot run time: 151736 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.45 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 0e1d5fa5f807a2149344d8a3285c2a46c1bfc90d, data reload: false

query1	0.00	0.00	0.00
query2	0.09	0.04	0.05
query3	0.26	0.09	0.08
query4	1.61	0.10	0.09
query5	0.23	0.23	0.24
query6	1.18	0.68	0.68
query7	0.04	0.01	0.01
query8	0.05	0.05	0.04
query9	0.40	0.35	0.34
query10	0.56	0.58	0.58
query11	0.19	0.13	0.14
query12	0.18	0.15	0.14
query13	0.48	0.50	0.49
query14	1.03	1.02	1.03
query15	0.63	0.60	0.60
query16	0.34	0.36	0.35
query17	1.14	1.17	1.15
query18	0.21	0.20	0.19
query19	2.04	2.01	1.97
query20	0.02	0.02	0.01
query21	15.54	0.20	0.13
query22	4.85	0.05	0.06
query23	16.28	0.31	0.13
query24	2.77	0.57	0.41
query25	0.12	0.06	0.06
query26	1.11	0.21	0.16
query27	0.05	0.05	0.03
query28	3.44	0.79	0.35
query29	12.49	4.16	3.26
query30	0.27	0.13	0.10
query31	2.77	0.55	0.32
query32	3.22	0.59	0.50
query33	3.20	3.24	3.37
query34	15.49	3.98	3.39
query35	3.32	3.34	3.34
query36	0.54	0.45	0.54
query37	0.10	0.07	0.07
query38	0.05	0.04	0.03
query39	0.04	0.03	0.04
query40	0.17	0.16	0.16
query41	0.09	0.03	0.03
query42	0.03	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.66 s
Total hot run time: 24.45 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 85.93% (116/135) 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69082

Problem Summary: Integrate apache/doris master through 7acfd9b.
Preserve the upstream header dependencies on the renamed object storage reader. Its implementation and test include the client holder directly. Apply the upstream reverse reach limit of 50 to the renamed filesystem header and retain all other upstream thresholds.

### Release note

None

### Check List (For Author)

- Test: Built BE (ASAN, Azure enabled) and FE. Ran the focused BE ASAN unit tests (87 passed, 1 JSON timing assertion failures, 0 skipped). Header hygiene, formatting and clang-tidy checks passed. Ran the build-support gate self-tests. Broader results and previously reported cache-fixture crashes were recorded separately.
- Behavior changed: No (merge conflict resolution).
- Does this need documentation: No.
morningman pushed a commit that referenced this pull request Nov 4, 2026
…on (#69392)

### What problem does this PR solve?

Issue Number: None

Related PR: #69082

Problem Summary:

**In short.** DELETE, UPDATE and MERGE on an Iceberg table recorded the
delete files they write (v2 position delete files and v3 deletion vector
files) under the internal `s3://` address BE writes them at, instead of
the table's own location (`oss://`, `s3a://`, `abfss://`, ...). Doris
could not always read such a table back, and other engines and
maintenance procedures resolved those files with the wrong file system.
This PR commits delete files under the table's location. It also makes
every Iceberg file Doris writes take both of its paths from one place in
BE and pass one check in FE, so the next writer cannot repeat the
mistake without failing.

#### Background

Every Iceberg sink FE sends carries two forms of the table's data
location:

- a normalized one BE can address the storage with (`output_path`): FE
rewrites `oss://`, `cos://`, `cosn://`, `obs://`, `bos://`, `gs://`,
`s3a://`, `s3n://` and Azure `abfs[s]://` / `wasb[s]://` locations
(except OneLake) to `s3://`;
- the raw one Iceberg metadata must record: `original_output_path` on
`TIcebergTableSink`, `table_location` on `TIcebergDeleteSink`, both on
`TIcebergMergeSink`.

BE writes each file under the first form and reports it in
`TIcebergCommitData.file_path`, which FE writes into the manifests as it
is. So the reported path must be in the second form.

#### The problem, and what it cost

Reproduce on an Iceberg table located at `oss://bucket/...`:

```sql
CREATE TABLE t (id INT, v STRING) PROPERTIES ('format-version' = '2');
INSERT INTO t VALUES (1, 'a'), (2, 'b'), (3, 'c');
DELETE FROM t WHERE id = 1;
SELECT file_path FROM t$delete_files;  -- s3://bucket/.../data/delete_pos_xxx.parquet
SELECT file_path FROM t$data_files;    -- oss://bucket/.../data/...
```

- Whether Doris can still read the table depends on the catalog and
storage binding. In a real Azure ADLS Hadoop catalog test with explicit
SharedKey, Doris SELECT failed with `No storage properties found for
schema: s3`, and Spark failed with `UnsupportedFileSystemException: No
FileSystem for scheme "s3"`.
- Other engines and maintenance operations such as `expire_snapshots` /
`remove_orphan_files` may resolve the wrong file system from the
recorded scheme, depending on the engine and FileIO. Doris's own
`remove_orphan_files` refuses to run on such a table (`Cannot determine
whether listed and reachable file locations are equivalent`).
- Cause: data files were written under `write_path` and committed under
`original_write_path` (`VIcebergPartitionWriter`), but
`VIcebergDeleteSink` had no such split; it reported the
`output_path`-based path it wrote.
- Why it went unnoticed: the two writers mapped the paths in different
ways, `VIcebergDeleteFileWriter` reported its write path by default, and
FE accepted any path. CI did run on such a location: the Iceberg REST
fixture's warehouse is `s3a://`, which FE normalizes to `s3://`. But the
DML suites only checked that delete file paths contain
`/data/delete_pos_`, and a stray
`test_iceberg_update_delete_basic.out.org` in the repository records the
wrong `s3://warehouse/wh/...` paths.

#### How this PR fixes it

1. `[fix](be) Commit Iceberg delete files under the table's own
location`, `[test](be) Verify Iceberg delete file commit paths` and
`[test](be) Initialize the Arrow memory pool in the Iceberg position
delete write test`: `VIcebergDeleteSink` writes under `output_path` and
commits position delete files and deletion vectors under
`table_location`. An FE unit test pins that both sinks carrying
`table_location` name the same directory as `output_path`, and
`DataSinks.thrift` documents the contract. The position delete write
test sets up the Arrow memory pool the Parquet writer allocates from, so
it also passes when run alone (CI review bot finding on this PR).
2. `[refactor](be) Take both paths of every Iceberg file from one output
location`:
- The new `IcebergOutputLocation` (header-only) holds one directory in
both forms and gives the write path and the commit path of a file name,
and of a partition subdirectory.
- The data writer (`VIcebergTableWriter` / `VIcebergPartitionWriter`),
the delete file writer and the Puffin path all take their paths from it.
`VIcebergDeleteFileWriter` now reports the commit path itself instead of
its write path.
- A table or delete sink without both location fields is rejected in
`open()` / `init_properties()` instead of committing a write path or a
relative path. The FE of every branch (3.1, 4.0, 4.1, 4.2, master) sets
both fields on every Iceberg sink.
   - Directories join file names with exactly one `/`.
3. `[improvement](fe) Reject Iceberg commit data reported outside the
sink's location`:
- `planWrite` registers on the transaction the raw location(s) each sink
it builds carries, read back from the built sink.
- `IcebergConnectorTransaction.addCommitData`, where every report from
every writer enters FE, rejects a file that is not under a registered
location, or has no path. FE then answers the report as not accepted,
and BE deletes the files under the paths it wrote them at and cancels
the query, so a wrong path fails the statement and leaves no orphan
files.
- Thrift comments state the contract, including that "the same
directory" can differ in more than the scheme (Azure moves the account
out of the authority). Comments only, no protocol change.
4. `[test](regression) Check that every Iceberg write records its files
under the table location`:
- The new `test_iceberg_write_file_locations` runs INSERT, INSERT
OVERWRITE PARTITION, branch INSERT, DELETE, UPDATE, MERGE and
`rewrite_data_files` on a v2 table, and INSERT, DELETE, UPDATE and MERGE
on a v3 table. After each operation every file in `$all_files` must
start with the table's LOCATION plus `/data/`. A new write operation
belongs in this suite too.
- `test_iceberg_update_delete_basic` checks the prefix of its delete
files as well, and the stray `.out.org` is removed.

| Scenario | Before | After |
| --- | --- | --- |
| DELETE / UPDATE / MERGE on a v2 table at `oss://`, `s3a://`,
`abfss://`, ... | position delete files recorded as `s3://...` |
recorded under the table's location |
| The same on a v3 table | deletion vector (Puffin) files recorded as
`s3://...` | recorded under the table's location |
| A BE writer reports a file outside the location its sink carries |
committed as reported | the statement fails; BE deletes the file |
| A sink plan without `original_output_path` / `table_location` (no
supported FE sends one) | data files committed as `/p=1/x.parquet`,
delete files as `s3://...` | rejected before any file is written |
| `write.data.path` ending with `/` | data files at
`.../data//p=1/x.parquet` | `.../data/p=1/x.parquet`, as Iceberg's own
location provider places them |

Delete files that an older version already committed with `s3://` keep
that address until they are rewritten or expired.

Upgrade BE before FE, as usual. An upgraded FE rejects the `s3://`
delete file paths that a BE without this fix reports, so until that BE
is upgraded, DELETE / UPDATE / MERGE on a table whose location FE
normalizes fails instead of committing the wrong path.

#### Classes, and how they call each other

- `IcebergWritePlanProvider.planWrite` (FE) builds the sink and
registers the raw location(s) it carries with the transaction
(`commitLocationsOf`).
- `IcebergConnectorTransaction.addCommitData` (FE) accepts a reported
file only under a registered location; `IcebergWriterHelper` then turns
the fragments into `DataFile` / `DeleteFile`.
- `IcebergOutputLocation` (BE, new) is one directory in its write form
and its commit form.
- `VIcebergTableWriter` builds the data location in `open()` and hands
each `VIcebergPartitionWriter` its partition directory
(`WriteInfo.location`). `VIcebergDeleteSink` writes position delete
files through `VIcebergDeleteFileWriter` and deletion vectors into one
Puffin file, both from its location. `VIcebergMergeSink` builds one of
each.

```
FE planWrite ── sink: output_path + raw location ──────────────► BE
  │ addCommitLocation(raw location)                              IcebergOutputLocation(output_path, raw location)
  ▼                                                                ├─ VIcebergTableWriter ─► VIcebergPartitionWriter   data files
IcebergConnectorTransaction                                        ├─ VIcebergDeleteSink ──► VIcebergDeleteFileWriter  position deletes
  ▲ addCommitData: file_path under a registered                    │                     └─► Puffin writer             deletion vectors
  │ location, else reject the report                               └─ VIcebergMergeSink ──► both of the above
  └──────────── TIcebergCommitData.file_path = commit path ◄───────┘
```

Not changed: Thrift fields (comments only), the scan side, and how FE
normalizes locations.
… writes to a reused vault id

Issue Number: None

Related PR: apache#69605

Problem Summary: Two regressions in how a BE applies a change of backend (S3 family to Azure
or back), plus the review's comment and test follow-ups.

A cold-storage resource: FE allows `ALTER RESOURCE` to change the provider even under a storage
policy, and `S3FileSystem::refresh` built a new file system for it. A remote rowset resolves its
file system once and keeps it, so rowsets bound before the change stayed on the old holder: after
a revert or a key rotation they kept failing with the old backend or the old key until BE
restart, while FE and the BE log reported success. `refresh` now keeps the file system while the
bucket and prefix stay, and rebinds its holder to a client built from the new configuration
(`ObjClientHolder::rebind`), so every rowset follows, as before the refactor. It builds a new file
system only when the bucket or prefix moves, which FE only allows without a storage policy. Every
backend change logs a WARNING with the resource id and both configurations, masked.

A storage vault: a vault's backend cannot be altered, but `drop_hdfs_vault` can drop an object
vault and the meta service can hand its id to the next vault. The vault refresh only reset the
holder, which refuses another backend, so loads for the new vault kept writing into the dropped
vault's bucket; before the refactor they failed. `S3FileSystem::refresh_vault` now takes the
holder out of service in that case (`ObjClientHolder::invalidate`). Every user shares the holder,
including `PackedFileManager`, so all of them fail with their existing "no client" errors until a
BE restart builds the new vault's file system. The invalidation is permanent: `reset`, `rebind`
and `init` return its reason, and `_publish` checks it under the lock before the generation, so
a refresh carrying an older configuration cannot bring the client back. The shared SDK client is
left alone, since other holders may use it. Because the client can now become null at runtime:
`S3FileWriter::_complete` takes it after waiting for the uploads, so that it no longer returns with
upload callbacks still running and sees an invalidation during the wait, and
`generate_presigned_url` checks it before its OSS branch, which would build a client of its own.

Limits, accepted here: a call already sent cannot be recalled, so a PutObject that took the client
may still succeed. Until the next vault sync (60s by default) a BE cannot know the id was reused.
A reused id on the same backend or between HDFS and S3 is not detected. These need the fix in the
meta service, which is handled separately.

Review follow-ups: the comments on why Recycler does not check the Azure key pair now give the
real reason (`S3Conf::from_obj_store_info` loads the pair complete or not at all; the meta service
only requires it when an entry is created). New tests pin which value becomes the Azure account
and which the key, in `AzureAuthFactory`, `AzureClientProvider` and Recycler's `S3Accessor`, without
an account. `ObjClientFactoryTest` cases that count builds use unique endpoints, so they can be
repeated in one process.

None

- Test: Unit Test (holder rebind across S3, Azure and back with a kept reader, vendor change inside
  the S3 family, invalidation and overlapping reset, vault refresh, presigned URL, writer timing
  with sync points, Azure credential wiring in BE and Recycler; BE UT and cloud UT in CI)
- Behavior changed: Yes. See the PR description, items 3 and 5.
- Does this need documentation: No
@xylaaaaa

xylaaaaa commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

…torage-client

# Conflicts:
#	be/src/exec/sink/viceberg_delete_sink.cpp
#	be/src/exec/sink/writer/iceberg/viceberg_partition_writer.cpp
#	fe/fe-connector/fe-connector-iceberg/src/test/java/org/apache/doris/connector/iceberg/IcebergWritePlanProviderTest.java
#	gensrc/thrift/DataSinks.thrift
#	gensrc/thrift/PlanNodes.thrift
@xylaaaaa

xylaaaaa commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69605

Problem Summary: `ObjStorageFileSystem::refresh` applies a refreshed cold-storage resource and can
return a new file system, while `refresh_vault` applies a refreshed storage vault and never
replaces the file system. The bare name read like a general version that a vault could use too, so
it is now `refresh_resource`. No behavior change.

### Release note

None

### Check List (For Author)

- Test: No need to test (rename; existing unit tests cover it, BE UT in CI)
- Behavior changed: No
- Does this need documentation: No
@xylaaaaa

xylaaaaa commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 100.00% (3/3) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 75.91% (2108/2777)
Line Coverage 65.78% (38833/59039)
Region Coverage 53.53% (36373/67950)
Branch Coverage 56.90% (11870/20862)

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29073 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit eb15c5a56ca095acf8a72d3876d61ed97ee2f726, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17626	5233	5129	5129
q2	2121	320	287	287
q3	10217	1409	842	842
q4	4683	460	337	337
q5	7426	804	526	526
q6	184	183	154	154
q7	773	813	608	608
q8	9257	1327	1089	1089
q9	5712	4223	4230	4223
q10	6844	1299	1014	1014
q11	446	255	235	235
q12	643	400	289	289
q13	18109	4328	3075	3075
q14	271	274	245	245
q15	q16	746	746	695	695
q17	1217	763	576	576
q18	7066	6181	6130	6130
q19	1144	959	608	608
q20	413	341	229	229
q21	5438	2509	2600	2509
q22	400	326	273	273
Total cold run time: 100736 ms
Total hot run time: 29073 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5990	5925	6130	5925
q2	719	649	584	584
q3	5649	5869	5320	5320
q4	2226	2206	1601	1601
q5	5740	5844	5578	5578
q6	235	191	149	149
q7	2231	2048	1801	1801
q8	3131	2640	2760	2640
q9	7931	7474	7514	7474
q10	3614	3614	3177	3177
q11	589	404	385	385
q12	667	714	539	539
q13	3390	3668	3092	3092
q14	286	294	256	256
q15	q16	649	669	630	630
q17	7840	7120	6982	6982
q18	12917	12120	12992	12120
q19	929	823	832	823
q20	2145	2135	1921	1921
q21	5924	4862	5050	4862
q22	514	481	422	422
Total cold run time: 73316 ms
Total hot run time: 66281 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151627 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit eb15c5a56ca095acf8a72d3876d61ed97ee2f726, data reload: false

query5	4307	610	454	454
query6	425	212	197	197
query7	4812	437	220	220
query8	315	160	149	149
query9	8770	3196	3193	3193
query10	465	305	259	259
query11	6029	3851	3588	3588
query12	157	94	90	90
query13	1250	458	340	340
query14	6151	3955	3603	3603
query14_1	3452	3408	3399	3399
query15	212	201	185	185
query16	950	449	441	441
query17	887	674	536	536
query18	2424	420	309	309
query19	207	169	146	146
query20	86	87	82	82
query21	219	125	104	104
query22	13132	13038	12743	12743
query23	13465	12880	12450	12450
query23_1	12534	12452	12523	12452
query24	7365	823	476	476
query24_1	487	485	500	485
query25	543	429	376	376
query26	1284	255	142	142
query27	2762	444	276	276
query28	4625	2075	2061	2061
query29	1584	643	459	459
query30	303	220	192	192
query31	1017	934	823	823
query32	153	101	92	92
query33	533	307	243	243
query34	916	853	498	498
query35	765	750	641	641
query36	840	812	719	719
query37	136	103	89	89
query38	1771	1709	1669	1669
query39	798	788	750	750
query39_1	731	735	729	729
query40	225	119	97	97
query41	72	69	72	69
query42	89	83	85	83
query43	345	357	316	316
query44	1374	734	719	719
query45	183	182	179	179
query46	902	966	585	585
query47	2923	3025	2897	2897
query48	297	310	226	226
query49	571	397	297	297
query50	690	290	217	217
query51	10522	10614	10496	10496
query52	77	82	69	69
query53	189	220	162	162
query54	263	208	191	191
query55	74	65	62	62
query56	238	215	230	215
query57	1698	1643	1532	1532
query58	283	264	254	254
query59	2163	2174	1971	1971
query60	297	245	232	232
query61	155	145	149	145
query62	393	343	287	287
query63	186	160	162	160
query64	2763	986	768	768
query65	3327	3283	3271	3271
query66	1772	417	330	330
query67	20157	20198	19922	19922
query68	3214	1025	617	617
query69	416	298	244	244
query70	857	771	778	771
query71	322	245	210	210
query72	2798	2598	2292	2292
query73	530	534	309	309
query74	4674	4598	4347	4347
query75	2347	2310	1950	1950
query76	2406	1018	604	604
query77	344	378	284	284
query78	9953	9689	9205	9205
query79	1035	861	551	551
query80	1220	440	351	351
query81	595	324	272	272
query82	615	138	104	104
query83	314	198	190	190
query84	313	124	105	105
query85	875	443	383	383
query86	416	247	225	225
query87	2003	1930	1801	1801
query88	3920	2833	2821	2821
query89	340	285	244	244
query90	1922	192	179	179
query91	163	149	129	129
query92	102	92	93	92
query93	1061	1029	582	582
query94	662	308	270	270
query95	584	394	308	308
query96	689	508	248	248
query97	2430	2429	2357	2357
query98	164	152	147	147
query99	765	762	668	668
Total cold run time: 236934 ms
Total hot run time: 151627 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.32 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit eb15c5a56ca095acf8a72d3876d61ed97ee2f726, data reload: false

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.26	0.08	0.09
query4	1.61	0.09	0.08
query5	0.28	0.24	0.25
query6	1.20	0.68	0.66
query7	0.04	0.00	0.00
query8	0.05	0.04	0.04
query9	0.40	0.35	0.35
query10	0.63	0.57	0.58
query11	0.20	0.15	0.14
query12	0.19	0.17	0.14
query13	0.49	0.48	0.51
query14	1.04	1.01	1.01
query15	0.64	0.62	0.61
query16	0.33	0.35	0.34
query17	1.15	1.10	1.14
query18	0.19	0.19	0.19
query19	2.05	1.96	2.01
query20	0.02	0.04	0.01
query21	15.48	0.18	0.14
query22	4.94	0.05	0.06
query23	16.28	0.32	0.13
query24	3.19	0.48	0.45
query25	0.11	0.06	0.04
query26	1.46	0.21	0.16
query27	0.05	0.05	0.05
query28	3.50	0.72	0.37
query29	12.46	4.09	3.26
query30	0.28	0.12	0.09
query31	2.77	0.55	0.32
query32	3.24	0.61	0.50
query33	3.11	3.21	3.15
query34	15.30	4.02	3.42
query35	3.33	3.35	3.32
query36	0.56	0.46	0.63
query37	0.12	0.08	0.07
query38	0.06	0.04	0.04
query39	0.04	0.02	0.03
query40	0.18	0.16	0.15
query41	0.08	0.03	0.03
query42	0.04	0.03	0.02
query43	0.04	0.04	0.03
Total cold run time: 97.5 s
Total hot run time: 24.32 s

…torage-client

# Conflicts:
#	be/src/exec/sink/writer/iceberg/viceberg_delete_file_writer.cpp
#	be/src/exec/sink/writer/iceberg/viceberg_partition_writer.cpp
#	be/src/exec/sink/writer/vhive_partition_writer.cpp
@xylaaaaa
xylaaaaa requested a review from Mryange as a code owner November 9, 2026 02:01
@xylaaaaa

xylaaaaa commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

xylaaaaa added a commit to xylaaaaa/doris that referenced this pull request Nov 9, 2026
…mment

### What problem does this PR solve?

Issue Number: None

Related PR: apache#69605, apache#69082

Problem Summary: The bulk rename of S3ClientFactory to AwsSdkManager also
rewrote a comment in obj_storage_config.cpp that names the function the
config checks came from, so it read "the former AwsSdkManager::create".
That function was S3ClientFactory::create; AwsSdkManager never had a
create method. Restore the original name. A scan of comments that name a
method of AwsSdkManager or the ObjStorage* classes found no other method
that does not exist.

### Release note

None

### Check List (For Author)

- Test: No need to test (comment only)
- Behavior changed: No
- Does this need documentation: No
chenjunwei added 2 commits November 9, 2026 14:44
### What problem does this PR solve?

Related PR: apache#69082, apache#69605

Problem Summary: Keep the integration branch aligned with the split BE
refactor. Include the bucket supplied by the legacy configuration sources
in the S3 client cache key and preserve it through refresh. This keeps
separate connection pools for otherwise identical configurations that
name different buckets.

### Release note

None

### Check List (For Author)

- Test: FE and ASAN BE builds passed. A local two-bucket S3 regression
  passed with cold and warm caches. BE logs confirmed two client builds,
  and SQL and an independent S3 client verified the exported data.
  Header hygiene, formatting and clang-tidy passed.
- Behavior changed: No (preserves the pre-refactor S3 cache behavior)
- Does this need documentation: No
### What problem does this PR solve?

Related PR: apache#69082

Problem Summary: Public URL generation assumed an S3 client whenever an
endpoint matched the OSS private endpoint suffix. A custom Azure endpoint
with that suffix would fail before signing. Rewrite the endpoint in a
copy of the configured backend so its own client signs the public URL.

### Release note

None

### Check List (For Author)

- Test: FE and ASAN BE builds passed. The file system and regression
  test compiled. The macOS BE UT target stopped at the pre-existing
  std::min type mismatch in binary_column_extract_iterator_test.cpp:74
  from apache#70212. Header hygiene, clang-format 16 and clang-tidy passed.
- Behavior changed: No (restores pre-refactor public URL generation).
- Does this need documentation: No
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants