Repository navigation
Conversation
### 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
xylaaaaa
requested review from
Gabriel39,
gavinchou,
liaoxin01,
luwei16,
morningman and
yiguolei
as code owners
October 14, 2026 16:07
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
Contributor
TPC-H: Total hot run time: 29368 ms |
Contributor
Author
|
run buildall |
Contributor
TPC-DS: Total hot run time: 153478 ms |
Contributor
ClickBench: Total hot run time: 24.56 s |
Contributor
TPC-H: Total hot run time: 29722 ms |
Contributor
TPC-DS: Total hot run time: 152943 ms |
Contributor
ClickBench: Total hot run time: 24.49 s |
Contributor
BE Regression && UT Coverage ReportIncrement line coverage Increment coverage report
|
### 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
Contributor
Author
|
run buildall |
Contributor
TPC-H: Total hot run time: 29594 ms |
Contributor
TPC-DS: Total hot run time: 152362 ms |
Contributor
ClickBench: 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
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
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
Contributor
Author
|
run buildall |
Contributor
Cloud UT Coverage ReportIncrement line coverage Increment coverage report
|
Contributor
TPC-H: Total hot run time: 29073 ms |
Contributor
TPC-DS: Total hot run time: 151627 ms |
Contributor
ClickBench: 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
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
### 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
### What problem does this PR solve? Related PR: apache#69082 Problem Summary: When credentials were refreshed while a writer waited for its parts, CompleteMultipartUpload used the replacement client. Remember the holder state before waiting. After all upload callbacks finish, reject an invalidated holder and keep the original client when only authentication changed. Other configuration updates and resource backend rebinds still use the current client. ### Release note None ### Check List (For Author) - Test: ASAN BE and FE builds passed. The new writer test compiled. The macOS BE UT target still stops in the upstream segment test binary_column_extract_iterator_test.cpp:74 (apache#70212), before test execution. Header hygiene, clang-format 16 and clang-tidy passed. - Behavior changed: No (restores pre-refactor credential rotation). - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69082 Problem Summary: A holder refresh that changed a timeout or S3 addressing during multipart close routed CompleteMultipartUpload to the replacement client. Keep the client selected before waiting when only credentials, request or connection timeouts, or S3 addressing change. Check the live holder after all uploads finish and continue to honor vault invalidation and resource backend changes. ### Release note None ### Check List (For Author) - Test: Production FE and ASAN BE builds, formatting, header hygiene and clang-tidy passed. The equivalent writer regression passed on apache#69605. This branch's macOS BE UT build is blocked by the existing size_t / ordinal_t std::min mismatch in binary_column_extract_iterator_test.cpp. - Behavior changed: No (restores pre-refactor multipart close behavior for addressing and timeout updates). - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69082 Problem Summary: During a multipart close, the client selector compared individual configuration fields after waiting for the parts. A change of S3 vendor or Azure container switched the pending Complete to the refreshed client, even though the backend type stayed the same. Use the client captured before the wait for same-type refreshes, as on master. Recheck the live holder after draining callbacks so invalidation still blocks Complete, and use the current client after a cross-backend resource rebind. The test clients keep separate parts to check both selection and storage error propagation. ### Release note None ### Check List (For Author) - Test: FE and ASAN BE build, clang-format 16, clang-tidy and build hygiene. The macOS arm64 BE UT build stops in the upstream binary_column_extract_iterator_test.cpp:74 at std::min(size_t, ordinal_t), before any UT runs. - Behavior changed: Yes. Same-backend multipart completion preserves master's choice of client. - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69082 Problem Summary: With both AWS_ENDPOINT and AWS_REGION missing, flat FE property resolution reported the region first for S3 and Azure. Restore master's endpoint-first diagnostic at the properties entry point and cover both providers. Move the stateless key parser back into the source file's anonymous namespace, remove three unused headers and correct comments left behind by the holder migration. ### Release note When BE receives flat object storage properties without an endpoint or a region, it again reports the missing endpoint first. ### Check List (For Author) - Test: Built FE and ASAN BE with Azure enabled, and passed build hygiene, clang-format 16 and clang-tidy on the changed BE files. The macOS arm64 BE unit test build stopped before execution in binary_column_extract_iterator_test.cpp:74 at std::min(size_t, ordinal_t), from the master base. - Behavior changed: Yes. The diagnostic order for incomplete FE properties matches master. - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69082 Problem Summary: Migrating the BE storage binding from S3Conf dropped the sse_enabled value carried by ObjectStoreInfoPB. The previous BE included that value in vault creation and error diagnostics. Carry it on ObjStorageConfig, keep the original false default and print it in the storage and flat-source diagnostics. Client construction, caching and the upload path continue to use their existing inputs. ### Release note BE vault diagnostics retain the sse_enabled value from storage metadata. ### Check List (For Author) - Test: Built FE and the ASAN BE with Azure enabled. Build hygiene, clang-format 16 and clang-tidy passed. The macOS arm64 BE UT build stopped before execution in the upstream binary_column_extract_iterator_test.cpp:74 at std::min(size_t, ordinal_t). - Behavior changed: No relative to master. The refactored BE reports the vault SSE value again. - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69082, apache#69605 Problem Summary: The benchmark writer sets a 3000 ms S3 connection timeout. The reader at the merge base passed a property that the resolver ignored and inherited the SDK setting. Omit the reader override when converting the benchmark to typed client configuration so its read workload uses the same settings as before. ### Release note None ### Check List (For Author) - Test: clang-format 16, BE header hygiene and changed-file clang-tidy passed on this branch. The identical change on apache#69605 passed the default FE and ASAN BE build and 72 related BE tests. The optional tool on macOS still encounters the existing RapidJSON overload ambiguity when serializing released_elements. - Behavior changed: No relative to the merge base. - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69082 Problem Summary: The typed Azure file system test called the removed _get_key member and could not compile with Azure enabled. Open a reader through the file system for each supported location and assert its resolved path. A supplied file size avoids a metadata request. ### Release note None ### Check List (For Author) - Test: On macOS arm64 with Azure enabled, ASAN_UT compiled the updated Azure test. The normal test build then stopped at the independent std::min(size_t, ordinal_t) error in binary_column_extract_iterator_test.cpp before running tests. clang-format 16, clang-tidy and BE header hygiene passed. - Behavior changed: No - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69082, apache#69605 Problem Summary: Keep the behavior of the merge base when migrating object storage clients. Leave the file cache benchmark's read-side connection timeout property spelling and the vault sync warning's status argument as they were. Enable RFC 3986 encoding in the reader and writer constructors and remove the test for eager SDK encoding. ### Release note None ### Check List (For Author) - Test: Built FE and the Azure-enabled ASAN BE on macOS arm64 with PCH disabled. The standard BE UT build stops at the pre-existing std::min(size_t, ordinal_t) error in binary_column_extract_iterator_test.cpp before running tests. clang-format 16, clang-tidy and BE build hygiene passed. On apache#69605, separate fresh test processes called the encoding setter with false at SDK initialization and true from the respective reader and writer constructors. - Behavior changed: No relative to the master merge base for these three paths. - Does this need documentation: No
### What problem does this PR solve? Related PR: apache#69605, apache#69082 Problem Summary: The integration branch differed from the reviewed child PR in three places. The file cache benchmark reader passed an unrecognized connection timeout key. The vault sync warning used the status of fetching the vault list after a create or refresh failed. Requests sent before the first reader or writer could use a different path encoding. Pass the recognized benchmark key, log the failing operation status and enable RFC 3986 encoding through the AWS SDK initialization options. Restore the SDK initialization regression test. ### Release note The BE uses strict RFC 3986 path encoding from AWS SDK startup and reports the failing operation in vault sync warnings. The file cache benchmark applies its configured S3 connection timeout to reads. ### Check List (For Author) - Test: Compared all three code paths and the encoding regression test with apache#69605 at b6ac43e. The six changed C++ files passed clang-format 16, the changed-line clang-tidy check and BE build hygiene. - Behavior changed: Yes, as described in the release note. - Does this need documentation: No
…obench key as on master ### What problem does this PR solve? Issue Number: None Related PR: apache#69605 Problem Summary: Review asked to keep this refactor free of behavior changes and bug fixes. Three places still differed from master and are returned to it: - A failed vault create or refresh in `CloudStorageEngine::sync_storage_vault` logs the status of `get_storage_vault_info` again, as on master. - The object storage reader and writer constructors set `Aws::Http::SetCompliantRfc3986Encoding(true)` again, instead of `SDKOptions` before `InitAPI`. The test that asserted the flag after SDK initialization is removed with it. - The file cache microbench reader passes `AWS_CONNECT_TIMEOUT_MS` again, the key master uses. The fixes themselves will be sent separately. The six files are identical to the parent of `96f3b7ee9e3`. ### Release note None ### Check List (For Author) - Test: No need to test; the six files are identical to the parent of 96f3b7e. Build hygiene and clang-format 16 passed. Not compiled locally; CI compiles and runs the unit tests. - Behavior changed: No (returns these three places to master behavior) - Does this need documentation: No
Contributor
Author
|
run buildall |
### What problem does this PR solve? Related PR: apache#69605 Problem Summary: ObjClientHolder published a new state only when no other reset had published since the caller took its snapshot, and otherwise returned Aborted. Before the refactor the holder built the client outside the lock and the last reset to publish won, with both calls succeeding. The generation check did not add correctness: the merge keeps only the storage target, which no reset changes, so the published configuration is the same whichever state it was merged with, and the holder cannot tell which caller carries the newer configuration either way. Its only effect was a different arbitrary winner and a failed refresh for the other caller. Restore the previous behavior: _publish no longer takes the expected state, and it assigns the next generation under the lock. The check for an invalidated holder stays, so a client that was being built during invalidate() still cannot bring the holder back. A reset cannot overlap a rebind: resource updates run on a single worker thread, and vault syncs only reset or invalidate. ### Release note None ### Check List (For Author) - Test: Cherry-picked from apache#69605 (e0caadd); the change is identical apart from the ObjStorageFileSystem name in one comment. The unit test for overlapping resets expects both resets to succeed and the last one to stay. Not compiled locally; CI compiles and runs it. Build hygiene and clang-format 16 passed. - Behavior changed: No relative to master. Overlapping resets both succeed and the last one wins again. - Does this need documentation: No
Contributor
Author
|
run buildall |
…f AwsSdkManager ### What problem does this PR solve? Issue Number: None Related PR: apache#69605 Problem Summary: `AwsSdkManager` owns the AWS SDK lifetime, yet it still carried two Azure parts: its constructor set up the Azure SDK log, and `AzureClientProvider` called `AwsSdkManager::instance().ca_cert_file_path()` for its CA bundle. Review on apache#69605 pointed this out; this applies the same change here, where the class is already named `AwsSdkManager`. - `AwsSdkManager` keeps only the AWS SDK lifetime (`InitAPI` / `ShutdownAPI`), `getClientConfiguration` and `create_aws_credentials_provider`, which the S3 provider and Kinesis use. - The Azure SDK log setup moves unchanged into `init_azure_sdk_logging()` in `azure_client_provider`. `ObjClientFactory` calls it on construction, right after initializing the AWS SDK, and BE startup now constructs `ObjClientFactory` instead of `AwsSdkManager`, so both SDKs are still set up at startup in the same thread, and the AWS SDK is still shut down after the providers release their clients. - The CA bundle cache moves unchanged into `io/obj_storage/obj_client_ca.{h,cpp}` (`obj_client_ca_cert_file_path()`): the first valid path of `ca_cert_file_paths`, cached, looked up again while empty. Both providers and the AWS credentials provider use it, so the Azure provider no longer depends on an AWS class. `AwsSdkManager` still resolves it once on construction. The CA test uses a test hook instead of the removed private members. ### Release note None ### Check List (For Author) - Test: Unit Test (`S3ClientFactoryTest.RefreshCaCertForCredentialsProvider` now goes through the new hook). Ported from apache#69605 (61f6dec); apart from the class rename, which this branch already has, the change is identical. Not compiled locally; CI compiles and runs the unit tests. Build hygiene and clang-format 16 passed. - Behavior changed: No - Does this need documentation: No
Contributor
Author
|
run buildall |
### What problem does this PR solve? Issue Number: None Related PR: apache#69082, apache#69605 Problem Summary: Keep resource and vault updates on the original file system. Preserve the flat input fields that determine the effective storage target, credential validation, and cache identity across S3 and Azure. Keep the client captured before waiting for multipart completion. Defer the Azure client cache limit and eviction policy to a separate change. Native Azure access still checks SAS expiry before looking up a client and before publishing a newly built one. ### Release note None ### Check List (For Author) - Test: Built the Azure-enabled ASAN BE and FE locally on macOS arm64 with PCH disabled. Ran clang-format 16, clang-tidy and build hygiene. The standard ASAN_UT build stops at the upstream size_t/ordinal_t std::min call in binary_column_extract_iterator_test.cpp:74. The PR checklist records the separate object storage runs and S3 regression. - Behavior changed: Restore the legacy refresh, validation and cache behavior. Native Azure access keeps the integration PR's credential and expiry rules. - Does this need documentation: No
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What problem does this PR solve?
Issue Number: None
Related PR: #67470, #69605 (BE refactor subset)
Problem Summary:
Doris reads Azure Blob natively from BE, but only with SharedKey, and the whole path is shaped around S3:
provider=azure, the account inAWS_ACCESS_KEYand the key inAWS_SECRET_KEY. BE uses those keys to build a SharedKey client. The legacy map has no native BE representation for a SAS token or Entra ID client credentials.FILE_S3reader cannot use.S3ClientConf(Azure reusesak/sk/bucketas account/key/container, next to S3-only fields such as region and role), oneS3ClientFactorythat builds both SDK clients and owns one shared cache, and anObjClientHolderthat 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 the integration PR for end-to-end testing. The BE refactor is under review in #69605.
1. BE object storage refactor
S3ConfandS3ClientConfare gone.io::ObjClientConfigholds 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::ObjStorageConfigreplacesS3Confand carries the bucket, prefix, client configuration and the vault metadata flagsse_enabled. BE reports the flag in storage diagnostics, as on master.ObjStorageConfigResolverconverts legacy FE properties, resource parameters and vault metadata. An Azure client built from a flat input preserves the fields used for refresh, cache identity and validation, including the effective region. FE properties check the endpoint before the region. Resource and vault refreshes validate the merged target. The newfrom_azure_client_config()reads the native Thrift input, which expresses SharedKey, SAS or OAuth2 without a region.ObjClientFactoryvalidates every request with the rules of its backend, then dispatches throughstd::visit(a new backend without a branch fails to compile).S3ClientProviderandAzureClientProviderlook up and publish entries under the cache lock. They build the SDK client outside the lock on a miss. Both providers use the same BE rate-limit policy (obj_client_rate_limit) and the same CA bundle cache (obj_client_ca). The cache reuses clients by full config and has no capacity limit.S3ClientFactoryis renamed toAwsSdkManager: it no longer builds clients and keeps only the AWS SDK lifetime and AWS helpers (client configuration, credentials), which Kinesis also uses. The Azure SDK log setup that its constructor carried moves unchanged toinit_azure_sdk_logging()next toAzureClientProvider;ObjClientFactoryruns both SDK setups on construction, and BE startup constructs it in place ofS3ClientFactory.FileWriterOptions::used_by_s3_committeris renamed todeferred_completion, andObjStorageCapabilities::deferred_completionsays what the coordinator must support (ANY_COORDINATORfor S3 multipart,NAMESPACED_BLOCK_IDSfor Azure blocks).VHivePartitionWriterchecks it against the coordinator'ssupports_deferred_azure_multipartinstead of comparing providers.ObjClientHolderowns an immutable snapshot of the config, client and generation. Legacy resource and vault refreshes update the same file system and holder, including across S3/Azure changes. The merged client keeps the original endpoint, region and endpoint-override flag. The file system keeps its original bucket and prefix. A failed build leaves the current client in place. Of two successful overlapping resets, the last publication wins.ObjStorageUrireplacesS3URI:parse_s3()keeps the S3 rules (and takes container and key from native Azure locations),parse_azure()adds the Azure rules (below).ObjStorageFileSystem,ObjStorageFileReader,ObjStorageFileWriter(obj_storage_file_*.{h,cpp}),obj_storage_file_buffer_pool,display_path(),FileSystemType::OBJECT_STORAGE(same value). The renamed classes keep the debug and sync point names used by regression tests. The reader handles HTTP 429 without AWS types. Internal metric variables are renamed toobj_storage_*; exposed metric names and config keys are kept for compatibility.BE client behavior
-internal.aliyuncs.com, BE removes-internalfrom a copy of the endpoint and signs with the configured backend. Presigning test2. FE-to-BE protocol (gensrc)
TAzureClientConfig { endpoint, account_name, container, credential }withunion TAzureCredential { shared_key, sas, client_secret }, carried by the new optional fieldTFileScanRangeParams.azure_client_config(id 43). In the merge base, id 42 isexternal_search_request. Id 43 was also free on branch-4.2, branch-4.1, branch-4.0 and branch-3.1 when checked.containeris 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) andTTVFTableSink(17, TVF insert); TVF schema inference already received it and BE now copies it infetch_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
AzureAuthFactorybuilds 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).AzureConfigCodecdecodes the Thrift config (exactly one credential);AzureConfigValidatorchecks the fields of the selected method and the account name against standard Azure hosts; The common Azure auth code parses the SASseexpiry and takes the earlier of that expiry and an explicitexpires_at_mswhen both exist.AzureClientProvidercallsvalidate_azure_auth_expirybefore each cache lookup and again before publishing a newly built client. Range reads reuse the open client.io::ObjStorageUriparses a location by the Azure rules:abfs[s]://[email protected]...,wasb[s]://[email protected]...,http(s)://acct.blob.../container/keyand the legacys3://container/keyall 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).FileFactoryreader,create_fsandcreate_file_writerresolve aFILE_S3location through one function: typed Azure access when FE sends it, theAWS_*properties otherwise. The scan readers copy the field fromTFileScanRangeParamsthrough 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 toFileFactory.VIcebergDeleteSinkused to report position delete and puffin files underoutput_path, the normalized form (s3://b/db/t/datafor anoss://or Azure table), so Iceberg metadata recorded the internals3://address. It now commits them undertable_location, the raw data location, which every FE version sets to the same directory asoutput_path. Data files were already committed underoriginal_output_path.4. FE
azure.sas_token(sensitive) withazure.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 neutralAZURE_*keys (AzureBackendPropertyKeysin 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 fromazure.oauth2_server_uri; the FE SDK client now uses that authority host as well.AzureThriftAdapter(fe-core) turns the neutral keys intoTAzureClientConfig, andFileQueryScanNodesets it forFILE_S3ranges. 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.azure.auth_type = OAuth2is only accepted for an Iceberg REST catalog is removed: it existed because BE could only use OAuth2 through the Iceberg REST / OneLake Hadoop path.adls.sas-token.<account host>with a table and optionally provideadls.sas-token-expires-at-ms.<account host>. These keys used to be dropped by the vended-credential filter.IcebergAdlsVendedCredentialsnow 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 asTAzureClientConfig. The expiry travels asTAzureSas.expires_at_ms. One storage account per table: tokens for several accounts are rejected with a message naming them.PluginDrivenTableSinkbinds 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.DefaultConnectorContext(Iceberg, Hive, Paimon, Hudi scan ranges and write paths) ends up in a request that carries typed Azure access, so it now usesLocationPath.ofAdaptersForNativeAccess: Azure locations are validated and kept asabfss://[email protected]/...instead of being rewritten tos3://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. Other callers can still uses3://container/key. OUTFILE (also used by EXPORT) and FILE_S3 TVFs can carry typed Azure credentials alongside that path. Paimon and Hudi JNI readers use raw paths and are unaffected; the FE Azure filesystem accepts the native forms for Hive multipart completion.FileQueryScanNodebinds the typed config even when a JNI scan already set the scan properties, which fixes SAS and OAuth2 reads of Icebergposition_deletes; the Iceberg plugins package the Azure FileIO dependencies.Azure access by entry point
FE and BE carry typed Azure access for external table and TVF reads (including
parquet_meta), Iceberg and Hive writes, OUTFILE/EXPORT, and FILE_S3 TVF inserts. The result-file and TVF writers pass the optional config toFileFactory. Broker Load and backup repositories accept only SharedKey for Azure. Resources and storage vaults continue to use their existing metadata credentials.Rolling upgrade: SharedKey reads keep working on old BEs through the S3-style keys. SAS and OAuth2 on
FILE_S3require every BE to be upgraded before they are used. Connector scans and writes send nativeabfss://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, external catalogs, Iceberg and Hive writes, and OUTFILE/EXPORT 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 internals3://form. Upgrade all BEs before FE and before using SAS or OAuth2.Check List (For Author)
Test
f0b0c6b557on macOS arm64 with./build.sh --be --fe, Azure enabled and PCH disabled.build-support/check-build-hygiene.sh.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) andStorageAdapterAzureNativeTest(OAuth2 outside Iceberg REST and SAS, throughStorageAdapter)std::min(size_t, ordinal_t)call inbinary_column_extract_iterator_test.cpp:74. Clang deduces two distinct unsigned types. Upstream testmutex lock failed: Invalid argument.S3FileWriterTest.multi_part_io_error. The cache-disabled fixture followed by all 14 writer tests passed 15/15 before the same process-exit exception. All 42 spill tests passed in a separate process (exit 0).f0b0c6b557, ran the local S3-compatible regression through FE, BE and SeaweedFS. Using one endpoint and one set of credentials,SELECT INTO OUTFILEwrote one two-part object per bucket. SQL read back 128 rows per bucket and an independent S3 client verified the complete byte content of both objects.Behavior changed:
table_location.FileSystemTypeprintsOBJECT_STORAGE.Does this need documentation?
azure.auth_type = SAS,azure.sas_tokenand the upgrade order; not included yet.Check List (For Reviewer who merge this PR)