refactor(cloud): split cloud object store integration into a vortex-cloud crate - #8999
Merged
Merged
Conversation
…d DuckDB URL-to-ObjectStore resolution had grown three independent implementations: `vortex-python`'s `Registry`, `vortex-jni`'s `make_object_store`, and `vortex-duckdb`'s two-scheme match. Only the first knew about the OpenDAL-backed schemes, and it was `pub(crate)`, so no Rust consumer could reach it. Hoist that registry into `vortex-io::object_store::Registry` as public API and point the bindings at it: - `vortex-python` drops its private copy and uses the shared one. - `vortex-duckdb` replaces its `file`/`s3`-only match (no caching, no credentials beyond `from_env`) with the registry, gaining Azure, GCS, HTTP and per-bucket client reuse. - `vortex-jni` keeps its property-driven builders, which have S3 behaviour the registry does not reproduce, but now asks `supports_scheme` instead of hard-coding `"cos"`. The registry lives behind a new `object_store_registry` feature so that plain file IO does not pull in the cloud HTTP stack: `vortex-file` with `object_store` still resolves zero `reqwest` in its dependency tree. Alibaba Cloud OSS support is added alongside the existing COS support, behind per-service `cos` and `oss` features on `vortex-object-store-opendal`, which is now publishable so that published crates can depend on it. The crate is split into per-service modules and gains `supports_scheme` / `SUPPORTED_SCHEMES` so callers stop matching scheme strings themselves. OSS reads `ALIBABA_CLOUD_*` (with the underscore) and has no `disable_config_load`; its nearest knob, `skip_signature`, is exposed for public buckets. Store construction no longer depends on ambient process state in tests: the registry takes its configuration from an injected source, replacing the three `unsafe std::env::set_var` blocks the moved tests used. The suite now passes with a deliberately hostile environment set. Signed-off-by: "Claude" <robert@spiraldb.com>
Merging this PR will not alter performance
Comparing Footnotes
|
I, Claude <robert@spiraldb.com>, hereby add my Signed-off-by to this commit: c85a848 Signed-off-by: Claude <robert@spiraldb.com>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Resolves the modify/delete conflict on vortex-python's registry.rs: this branch hoists that file into vortex-io, while #8733 fixed a percent-encoding bug in it on develop. Keeps the deletion and ports the fix into the hoisted registry: - `resolve` saturates the segment-count subtraction. A percent-encoded segment (`refs%2Fconvert%2Fparquet`) counts as one raw URL segment but decodes to three, so the subtraction underflowed and panicked. - `path_suffix` joins the segments and percent-decodes them through `Path::from_url_path` instead of `PathPart::parse` per segment. - Adds the regression test, using the injected `EnvSource` rather than the process environment. Signed-off-by: "Claude" <robert@spiraldb.com>
…crate Moves the URL -> ObjectStore registry out of vortex-io and folds vortex-object-store-opendal into the same crate, so all cloud object store integration lives in one place. - vortex-cloud owns the registry (`registry` feature) and the OpenDAL-backed services, now an `opendal` module behind per-service `cos` / `oss` features. - vortex-object-store-opendal is deleted; its files move with history. - vortex-io drops its `object_store_registry` and `opendal` features and its `url` dependency, keeping only the generic object_store adapters. - The facade exposes `vortex::cloud`, and vortex-python, vortex-jni and vortex-duckdb resolve through it. The registry no longer depends on vortex-io at all. Inside the `opendal` module the external crate is spelled `::opendal` to disambiguate it from the module of the same name. Signed-off-by: "Claude" <robert@spiraldb.com>
…w-1h8f3a' into claude/opendal-integration-review-1h8f3a
vortex-object-store-opendal was excluded from the wasm32 build because it defaulted to `cos` + `oss`, pulling opendal and reqwest, neither of which builds for wasm32-unknown-unknown. vortex-cloud replaces it with `default = []`, so a default-feature build pulls neither: `cargo tree --workspace --target wasm32-unknown-unknown` resolves no opendal at all, and `cargo check -p vortex-cloud --target wasm32-unknown-unknown` succeeds. Nothing enables the service features by default, so the exclusion is no longer needed and the stale crate name would have silently matched nothing. Signed-off-by: "Claude" <robert@spiraldb.com>
Docs: - Record vortex-io and vortex-cloud in the repository layout, so the crate map reflects where object store code now lives. - Drop a duplicated section from the OpenDAL store page: "Passing a store object directly" repeated the CosStore + `store=` example already shown under "Reading from COS", down to the same code block. Manifests: - vortex-cloud gates `parking_lot` behind `registry` and `tracing` behind the service features, the only configurations that use them. A featureless build now resolves neither as a direct dependency. - Drop `dep:vortex-cloud` where a `vortex-cloud/<feature>` entry sits beside it; the latter already activates the optional dependency. - vortex-jni selects the OpenDAL services in its `opendal` feature rather than pinning them on the dependency line, matching vortex-python. The hand-written `py:class` directive for CosStore stays as it is: the docs build compiles vortex-python without the `opendal` feature, so the class is absent and `autoclass` cannot resolve it the way the sibling store pages do. Signed-off-by: "Claude" <robert@spiraldb.com>
Two failures on f1b94b1, both mine. `Rust (docs)`: the crate-level docs linked the `opendal` module and the registry module linked `crate::opendal`, but that module is feature-gated on `cos`/`oss`. The workspace docs build enables `registry` (vortex-duckdb asks for `vortex/object_store_registry`) while leaving the services off, so both links dangled and `-D warnings` turned `rustdoc::broken_intra_doc_links` into an error. The overview now names the two feature-gated items in code spans instead of linking them, which holds for every feature combination. `lint-toml`: `taplo.toml` sets `reorder_keys = true` for `dependencies`, and `vortex-cloud` was inserted positionally rather than alphabetically in vortex-jni and vortex. Fixed by `taplo fmt`. Verified with `cargo doc --no-deps --document-private-items` under `-D warnings` across every vortex-cloud feature combination (none, registry, cos, oss, cos+oss, all), and for vortex-cloud/vortex-io/vortex-file/vortex in the registry-on, services-off combination the docs job actually builds. `taplo fmt --check` is clean. DCO Remediation Commit for Claude <noreply@anthropic.com> I, Claude <noreply@anthropic.com>, hereby add my Signed-off-by to this commit: fa2251f I, Claude <noreply@anthropic.com>, hereby add my Signed-off-by to this commit: a34da0c I, Claude <noreply@anthropic.com>, hereby add my Signed-off-by to this commit: f1b94b1 Signed-off-by: Claude <noreply@anthropic.com>
I, Claude <robert@spiraldb.com>, hereby add my Signed-off-by to this commit: c85a848 Signed-off-by: Claude <robert@spiraldb.com>
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.
Rationale for this change
Follow-up to #8845, which added the OpenDAL-backed
cos://store.URL-to-
ObjectStoreresolution had grown three independent implementations:vortex-python'sRegistryvortex-jni'smake_object_storevortex-duckdb'sresolve_filesystemfrom_envonlyOnly the first knew about the OpenDAL-backed schemes, and it was
pub(crate), so no Rustconsumer could reach it. Adding a provider meant touching every caller — which is exactly what
#8845 had to do, and what the next provider would have to do again.
This also unblocks a concrete gap:
vortex-object-store-opendalwaspublish = false, so nopublished crate could depend on it.
What changes are included in this PR?
A new
vortex-cloudcrate owns all cloud object store integration. The registry and theOpenDAL-backed services now live together in one place:
vortex-python's privateRegistrymoves in and becomes publicvortex_cloud::Registry(309 lines deleted from the binding).
vortex-object-store-opendalis folded in as avortex_cloud::opendalmodule and deleted as astandalone crate. Files move with
git mv, so history follows.vortex-iosheds its registry, itsobject_store_registry/opendalfeatures, and itsurldependency. It keeps the three generic
object_storeadapters(
ObjectStoreFileSystem,ObjectStoreReadAt,ObjectStoreWrite), which are provider-agnostic —they serve
LocalFileSystemandInMemoryexactly as they serve S3 — andcompat/obj_store.rs,whose
impl ObjectStore for Compat<T>cannot move (orphan rule:Compatis defined invortex-io).vortex-clouddepends on nothing invortex-io, so the split adds no dependency edge tovortex-file,vortex-datafusion, or the benchmarks.The bindings resolve through the facade's new
vortex::cloud:vortex-duckdbreplaces itsfile/s3-only match with the registry, gaining Azure, GCS, HTTPand per-bucket client reuse.
vortex-jnikeeps its property-driven builders — they have S3 behaviour the registry does notreproduce — but asks
supports_schemeinstead of hard-coding"cos", so the call site stayscorrect as services are added.
Alibaba Cloud OSS, alongside COS, behind per-service
cos/ossfeatures. OSS readsALIBABA_CLOUD_*(with the underscore) and has nodisable_config_load; its nearest knob,skip_signature, is exposed for public buckets.Feature-gating. The registry sits behind
vortex-cloud/registryso plain file IO does not pullin the cloud HTTP stack:
vortex-filewithobject_storestill resolves zeroreqwest. Making theservices opt-in (
default = []) also made the crate wasm32-clean, which removed a CI exclusion —see below.
Remove ambient process state from tests. The registry takes its configuration from an injected
EnvSource, replacing threeunsafe std::env::set_varblocks.set_varbecameunsafein Rust2024 precisely because
cargo testruns tests on multiple threads in one process.Merge of
developresolves a modify/delete conflict against #8733, which fixed apercent-encoding bug in the file this PR hoists. The deletion is kept and the fix ported into
vortex-cloud:resolvesaturates the segment-count subtraction (a percent-encodedrefs%2Fconvert%2Fparquetis one raw URL segment but decodes to three, so the subtractionunderflowed and panicked), and
path_suffixdecodes throughPath::from_url_path. Verified byreverting the fix and watching
test_resolve_percent_encoded_pathpanic on subtract-overflow.datasets.pybuilds exactly that URL shape, so the fix is on the live HuggingFace path.What APIs are changed? Are there any user-facing changes?
New public Rust API:
vortex-cloud, re-exported asvortex::cloudunder theobject_store_registryfeature.vortex_cloud::Registry(+Registry::new), behindregistry.vortex_cloud::opendal::{supports_scheme, SUPPORTED_SCHEMES, COS_SCHEME, CosConfig, make_cos_store, OSS_SCHEME, OssConfig, make_oss_store, make_opendal_store, make_opendal_store_with_env, OpenDALStoreError}, behindcos/oss/opendal.vortex-duckdbgains anopendalfeature.Removed:
vortex-io'sobject_store_registryandopendalfeatures, and thevortex-object-store-opendalcrate (never published, so no released API is affected).No Python-facing API change:
vortex-pythonswaps a private implementation for the shared one.DuckDB users gain Azure/GCS/HTTP support that previously errored with
Unsupported URL scheme.One CI change worth a look
--exclude vortex-object-store-opendalwas added to the wasm32 build because that crate defaultedto
cos+ossand so pulled opendal and reqwest.vortex-clouddefaults to no services, so theexclusion is dropped rather than renamed. Verified:
cargo tree --workspace --target wasm32-unknown-unknownresolves noopendalat all, andcargo check -p vortex-cloud --target wasm32-unknown-unknownsucceeds. Left in place, the stale crate name would have silently matchednothing and the wasm32 job would have built
vortex-cloudunguarded.Checks
cargo test -p vortex-cloud --all-featurescargo test -p vortex-io --all-featurescargo test -p vortex-python --all-features --libcargo check -p vortex-cloud× {no-default, registry, cos, oss, all}cargo check -p vortex-io --all-featurescargo check -p vortex-file --all-featurescargo check -p vortex-python --all-features --all-targetscargo check -p vortex-jni --all-features --all-targetscargo check -p vortex --features files,tokio,object_store,object_store_registry,opendalcargo check --target wasm32-unknown-unknown -p vortex-cloud -p vortex-io -p vortex-filecargo clippy -p vortex-cloud -p vortex-io -p vortex-python -p vortex-jni --all-targets --all-featurescargo clippy -p vortex-cloud --no-default-featurescargo +nightly fmt --allcargo metadata --lockedCargo.lockup to dateyamllint --strict -c .yamllint.yaml .github/workflows/ci.ymluv run --all-packages make -C docs clean html--fail-on-warning)uv run --all-packages make -C docs clean doctestCould not run locally:
cargo check -p vortex-duckdb— the build script downloads DuckDB sourcefrom
github.com/duckdb/duckdb/archive, which returns 403 through this environment's proxy(
codeload.github.comtoo). Thevortex-duckdbchange is 2 files; I verified by inspection thatvortex::cloud::Registryis re-exported under the features the manifest requests, thatFrom<object_store::Error> for VortexErrorexists for the new?, and that no import becameunused. CI's DuckDB jobs will be the first real compile of it.
cargo denywas also not run (failed to build locally). The new OSS dependencies(
opendal-service-oss,reqsign-aliyun-oss) are both Apache-2.0, matching the COS equivalentsalready accepted in #8845.
🤖 Generated with Claude Code
https://claude.ai/code/session_012TyPy9MbKP2j546m1CaKLk