This is an automated email from the ASF dual-hosted git repository.
yihua pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hudi-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 8043ea15 build(ffi): forward the spill-rocksdb feature through
hudi-ffi (#849)
8043ea15 is described below
commit 8043ea15d2d1e61a2fbccd795feacda8b88001fb
Author: Y Ethan Guo <[email protected]>
AuthorDate: Wed Oct 28 11:45:54 2026 -0700
build(ffi): forward the spill-rocksdb feature through hudi-ffi (#849)
The C ABI crate took hudi with its defaults, so a consumer of the crate
got the merge map's on-disk tier (RocksDB, bindgen, libclang) with no way
to opt out, since a consumer can only drop a feature its direct dependency
exposes. Forward it the way hudi-datafusion and hudi do: default on,
hudi taken with default-features = false.
The no-spill-backend CI job now checks the crate without the feature and
includes it in the dependency-graph assertion.
---
.github/workflows/ci.yml | 16 +++++++++++-----
AGENTS.md | 15 ++++++++-------
crates/ffi/Cargo.toml | 8 +++++++-
3 files changed, 26 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 2b860c07..1e3f5712 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -116,6 +116,10 @@ jobs:
run: cargo check -p hudi --no-default-features
- name: Check the umbrella crate without the spill backend, with
datafusion
run: cargo check -p hudi --no-default-features --features datafusion
+ # The C ABI crate reaches hudi-core through hudi and must forward the
+ # opt-out the same way.
+ - name: Check the C ABI crate without the spill backend
+ run: cargo check -p hudi-ffi --no-default-features
# The steps above prove the opt-out COMPILES. This proves it actually
drops
# the dependency, and unlike them it does not rest on libclang being
absent,
# so it keeps working if this job ever gains a C++ toolchain.
@@ -130,8 +134,8 @@ jobs:
# Under defaults the tier must be reachable. If this ever stops
# holding, the absence checks below are asserting nothing.
- for args in "" "--features datafusion"; do
- if ! out=$(cargo tree -p hudi $args -i rocksdb 2>&1) \
+ for args in "-p hudi" "-p hudi --features datafusion" "-p hudi-ffi";
do
+ if ! out=$(cargo tree $args -i rocksdb 2>&1) \
|| ! printf '%s\n' "$out" | grep -q '^rocksdb'; then
echo "cargo tree did not find rocksdb under default features:
'$args'"
echo "so the absence checks below cannot tell an opt-out from a
broken command"
@@ -143,9 +147,11 @@ jobs:
# With the opt-out it must be gone — and gone because the package is
# absent from the graph, which cargo says in those words, not because
# the command failed for some other reason.
- for args in "--no-default-features" "--no-default-features
--features datafusion"; do
- if out=$(cargo tree -p hudi $args -i rocksdb 2>&1); then
- echo "rocksdb is still reachable from hudi with: $args"
+ for args in "-p hudi --no-default-features" \
+ "-p hudi --no-default-features --features datafusion" \
+ "-p hudi-ffi --no-default-features"; do
+ if out=$(cargo tree $args -i rocksdb 2>&1); then
+ echo "rocksdb is still reachable with: $args"
printf '%s\n' "$out"
exit 1
elif ! printf '%s\n' "$out" | grep -q 'did not match any
packages'; then
diff --git a/AGENTS.md b/AGENTS.md
index 090e4dbd..e2bfdf38 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -56,13 +56,14 @@ cargo test -p hudi-core --lib --no-default-features
toolchain in front of every consumer, for a tier that only engages when a
merge exceeds
`hoodie.memory.merge.max.size`.
-It is **default-on in `hudi-core`, `hudi-datafusion` and `hudi`**, and the
latter two forward it
-rather than taking `hudi-core` with its defaults: a consumer can only opt out
of a feature its
-direct dependency exposes, and unification through `hudi-datafusion` would
otherwise hand the tier
-back. The opt-out is therefore `default-features = false` on `hudi`, and it
holds with the
-`datafusion` feature on. **The Python wheel and the cxx bridge do not opt
out** — both take `hudi`
-with defaults and build RocksDB. Dropping the feature removes the tier, and a
merge past the budget
-then fails with a `CoreError::Unsupported` naming the config rather than
spilling, which is why the
+It is **default-on in `hudi-core`, `hudi-datafusion`, `hudi` and `hudi-ffi`**,
and the latter
+three forward it rather than taking their dependency with its defaults: a
consumer can only opt out
+of a feature its direct dependency exposes, and unification through
`hudi-datafusion` would
+otherwise hand the tier back. The opt-out is therefore `default-features =
false` on `hudi`, and it
+holds with the `datafusion` feature on; a consumer of `hudi-ffi` makes the
same call there.
+**The Python wheel and the cxx bridge do not opt out** — both take `hudi` with
defaults and build
+RocksDB. Dropping the feature removes the tier, and a merge past the budget
then fails with a
+`CoreError::Unsupported` naming the config rather than spilling, which is why
the
published artifacts keep it.
A test that needs the disk tier must be `#[cfg(feature = "spill-rocksdb")]`;
the
diff --git a/crates/ffi/Cargo.toml b/crates/ffi/Cargo.toml
index c9abb16a..0e218693 100644
--- a/crates/ffi/Cargo.toml
+++ b/crates/ffi/Cargo.toml
@@ -34,11 +34,17 @@ name = "hudi_ffi"
crate-type = ["cdylib", "rlib"]
[features]
+default = ["spill-rocksdb"]
+# Forwarded so a consumer of this crate can drop the merge map's on-disk tier
+# (and with it RocksDB, bindgen and libclang). A consumer can only opt out of a
+# feature its direct dependency exposes, so taking hudi with its defaults here
+# would hand the tier to every consumer with no way to decline it.
+spill-rocksdb = ["hudi/spill-rocksdb"]
# Exports a deliberately panicking function, so a caller can prove a panic does
# not cross the C ABI. Off by default: it must not exist in a shipped library.
ffi-test-hooks = []
[dependencies]
-hudi = { path = "../hudi", version = "0.6.0-dev" }
+hudi = { path = "../hudi", version = "0.6.0-dev", default-features = false }
arrow = { workspace = true, features = ["ffi"] }
tokio = { workspace = true }