feat(storage): Add HDFS support via opendal services-hdfs-native - #3111
feat(storage): Add HDFS support via opendal services-hdfs-native#3111mixermt wants to merge 9 commits into
Conversation
Adds an opendal-hdfs-native cargo feature plus OpenDalStorageFactory::Hdfs and OpenDalStorage::Hdfs variants in iceberg-storage-opendal, using OpenDAL's services-hdfs-native (pure-Rust HDFS RPC, no JNI/libhdfs). The NameNode for a path resolves as: the hdfs.name-node property when set (comma-separated endpoints enable HA failover), otherwise the path authority. hadoop.-prefixed properties are forwarded to the HDFS client configuration, overriding values loaded from $HADOOP_CONF_DIR. Operators are cached per effective NameNode since each holds live RPC connections. Revives and updates PR apache#2441 (by @jordepic) against the current storage layer and opendal 0.58, where name_node became mandatory and the comma list is the HA mechanism. Closes apache#2440 Co-authored-by: Jordan Epstein <jordepic@users.noreply.github.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
blackmwk
left a comment
There was a problem hiding this comment.
I found two correctness issues that need to be addressed before merge: malformed hdfs: URLs can panic, and bulk deletion can conflate NameNodes running on different ports. Details and suggested regression coverage are inline. Please also resolve the two existing review threads.
This review was drafted by an AI-assisted tool and confirmed by an Apache Iceberg Rust maintainer. After you've addressed the points above and pushed an update, an Apache Iceberg Rust maintainer — a real person — will take the next look at the PR. The findings cite the project's review criteria; if you think one of them is mis-applied, please reply on the PR and a maintainer will weigh in.
More on how Apache Iceberg Rust handles maintainer review: CONTRIBUTING.md.
…S CI special-casing - HdfsConfig is now pub(crate) and parsed via #[derive(Properties)] (key/prefix attributes) instead of hand-written TryFrom + TypedBuilder. - HDFS integration tests are no longer #[ignore]d and the dedicated CI step is gone; they run under the default nextest invocation since make docker-up already starts the fixture and the Tests job is Linux-only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…eat-storage-hdfs-native
…effective NameNode - Url::parse accepts non-hierarchical forms like `hdfs:x`; the byte-7 slice then panicked. Require the literal `hdfs://` prefix instead. - batch_key_for_path grouped by URL host only, so NameNodes differing by port shared one deleter; key by the effective NameNode (configured hdfs.name-node, else authority incl. port), matching the operator cache. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # Cargo.lock
…sConfig Per review: the opendal module, its functions and the storage/factory variants are now hdfs_native-prefixed (leaving room for a libhdfs-backed variant, see apache#1130), and the never-consumed HdfsConfig struct is removed from the core crate — config/hdfs.rs keeps only the property constants that iceberg-storage-opendal uses. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Which issue does this PR close?
This revives #1131's successor #2441 by @jordepic (closed by the stale bot after a first review round), rebased onto the current
Storage-trait layout and updated for opendal 0.58, whereservices-hdfs-nativechanged behavior in ways that required design changes (details below).What changes are included in this PR?
Adds an
opendal-hdfs-nativecargo feature toiceberg-storage-opendal, withOpenDalStorageFactory::HdfsNative/OpenDalStorage::HdfsNativevariants andhdfs://routing inOpenDalResolvingStorage. The backend uses OpenDAL'sservices-hdfs-native(pure-Rust HDFS RPC viahdfs-native— no JNI/libhdfs). The feature is experimental and not part ofopendal-all, matchingopendal-oss/opendal-azdls.NameNode resolution (differs from #2441, forced by opendal 0.58 where
name_nodeis mandatory and its comma-split list is the HA mechanism):hdfs.name-nodeproperty when set — a single endpoint or a comma-separated list for HA failover (newHDFS_NAME_NODE/HDFS_HADOOP_CONF_PREFIXconstants iniceberg::io).hdfs://host:port/path).fs.defaultFS).hadoop.-prefixed properties pass through to the HDFS client config, overriding$HADOOP_CONF_DIRvalues (mirroring thehadoop.catalog-property convention of the Java integrations);hdfs-nativestill loadscore-site.xml/hdfs-site.xmlfrom$HADOOP_CONF_DIR/$HADOOP_HOMEfor everything else, and Kerberos works vialibgssapi_krb5(runtime dlopen). Operators are cached per effective NameNode since each holds live RPC connections.Relative paths are returned opendal-style without a leading
/—opendal::Deleter::delete(used bydelete_stream) rejects leading slashes, which an integration test caught.Test infrastructure: single-node HDFS docker fixture (
apache/hadoop:3.5.0, host networking — required becausehdfs-nativedials DataNodes by their registered IP, unroutable on a bridge). The DataNode healthcheck gates on NameNode registration so--waitmeans writable. Tests are#[ignore]d (host networking is Linux-only); CI opts in viacargo nextest --run-ignored=only -E 'test(file_io_hdfs)'.Are these changes tested?
iceberg::io.hdfs://, and the HA flow (logical authority in the path +hdfs.name-nodeproperty). All 12 verified green from a cold cluster locally; the suite runs in CI on Linux.make check, full-workspace--all-featureslib tests, and the existing s3/gcs/resolving integration suites pass;public-api.txtregenerated for both crates.AI Disclosure
Developed with AI assistance (Claude Code): drafting code/tests/fixtures starting from #2441, and cross-checking the design against the vendored opendal 0.58.1 / hdfs-native 0.14.5 sources. I reviewed the implementation and ran all verification locally. Areas worth reviewer attention: the NameNode-resolution semantics above (opendal's synthetic-nameservice behavior constrains what
hdfs://<nameservice>paths can do without the property), and the Windows--all-featuresbuild ofhdfs-native, which I could only verify via CI.🤖 Generated with Claude Code