#object-storage #high-performance #storage #daos

daoxide

High-performance Rust library for DAOS (Distributed Asynchronous Object Storage)

3 unstable releases

Uses new Rust 2024

0.2.0 Apr 13, 2026
0.1.1 Apr 11, 2026
0.1.0 Apr 10, 2026

#399 in Filesystem

GPL-3.0-only

240KB
5K SLoC

daoxide

Caution: This repo was created using vibe coding

High-performance Rust library for accessing DAOS (Distributed Asynchronous Object Storage).

This crate provides a safe wrapper around daos-rs bindings, with an ergonomic Rust-style API.

Overview

daoxide wraps the low-level DAOS C APIs into safe Rust interfaces:

  • RAII handle management: Pool, Container, and Object handles are automatically released on Drop
  • Type safety: strongly typed keys, object IDs, and flags to prevent runtime errors
  • Builder pattern: fluent chained calls instead of complex initialization code
  • Transaction support: marker-based Tx types ensure correct transaction handling
  • Unified error handling: DaosError enum instead of raw integer error codes

Feature Flags

Feature Enabled by Default Description
tracing Yes Tracing observability support
serde Yes Serialization/deserialization support
async No Async runtime support (Tokio)
mock No Mock testing utilities
[dependencies]
daoxide = { version = "0.2", features = ["async"] }

Quick Start

High-Level API (Facade)

Use DaosClient::builder() to connect to DAOS quickly:

use daoxide::prelude::*;

fn main() -> daoxide::Result<()> {
    let client = DaosClient::builder()
        .pool_label("mypool")
        .container_label("mycontainer")
        .build()?;

    let oid = client.alloc_oid(
        ObjectType::KvHashed,
        ObjectClass::UNKNOWN,
        ObjectClassHints::NONE,
    )?;

    client.put(oid, b"dkey1", b"akey1", b"hello world")?;

    let mut buffer = vec![0u8; 1024];
    client.get(oid, b"dkey1", b"akey1", &mut buffer[..11])?;

    println!("Retrieved: {:?}", String::from_utf8_lossy(&buffer[..11]));
    Ok(())
}

Mid-Level API (Pool/Container/Object)

Use PoolBuilder and Container APIs directly:

use daoxide::pool::{PoolBuilder, flags::POOL_CONNECT_NONE};
use daoxide::container::{ContainerOpen, flags::CONT_OPEN_RW};

fn main() -> daoxide::Result<()> {
    let runtime = daoxide::runtime::DaosRuntime::new()?;

    let pool = PoolBuilder::new()
        .label("mypool")
        .system("daos_server")
        .flags(POOL_CONNECT_NONE)
        .build()?;

    let container = pool.create_container("testcontainer")?;
    let info = container.query()?;
    println!("Container UUID: {:?}", info.uuid);

    Ok(())
}

Low-Level API (Object I/O)

Use DKey/AKey/IoBuffer for key-value operations:

use daoxide::io::{DKey, AKey, IoBuffer, Iod, IodSingleBuilder, Sgl};
use daoxide::prelude::*;

let object = client.object_builder()
    .open(oid, ObjectOpenMode::ReadWrite)?;

let dkey = DKey::new(b"my_dkey")?;
let akey = AKey::new(b"my_akey")?;
let value = IoBuffer::from_slice(b"hello world");

let iod = Iod::Single(
    IodSingleBuilder::new(akey.clone())
        .value_len(value.len())
        .build()?,
);
let sgl = Sgl::builder().push(value).build()?;

object.update(&Tx::none(), &dkey, &iod, &sgl)?;

Examples

Example File Description
Minimal client examples/minimal_client.rs Facade API demo
Object operations examples/object_io.rs Object read/write and key-value operations
Pool/container management examples/pool_container.rs Pool/Container lifecycle

Run examples:

cargo run --example minimal_client
cargo run --example object_io
cargo run --example pool_container

Documentation

Document Contents
docs/MIGRATION.md Complete guide for migrating from daos-rs to daoxide
RELEASE.md Release strategy, versioning, and quality gates

Quality Check Commands

# Code formatting check
cargo fmt --all -- --check

# Clippy check
cargo clippy --workspace --all-targets --all-features -- -D warnings

# Tests (must use --test-threads=1)
cargo test --workspace --all-features -- --test-threads=1

# Documentation build
cargo doc --workspace --all-features --no-deps

# MSRV verification
cargo +1.85 build --release

Feature Matrix Validation

# No default features
cargo check --no-default-features

# Check each feature independently
cargo check --features mock
cargo check --features async

# All features
cargo check --all-features

Known Limitations

1. OIT (Object Instance Tracking) is unavailable

daos_oit_* FFI functions are not exported by daos-rs, so crate::oit remains a stub.

Workaround: use object enumeration in the crate::iter module.

2. Async event queue is limited

daos_progress is not exposed in daos-rs. The async feature currently provides a spawn_blocking wrapper rather than native async progress.

3. Parallel testing caveat

test_runtime_init_and_fini may fail under parallel test execution because DAOS uses global state (RUNTIME_REFCOUNT).

Solution: run tests with --test-threads=1.

cargo test --workspace --all-features -- --test-threads=1

This is a pre-existing test infrastructure issue and does not affect library correctness.

Public Module Architecture

daoxide
├── error      - Error types
├── facade     - High-level API (DaosClient)
├── runtime    - Runtime management
├── pool       - Pool operations
├── container  - Container operations
├── object     - Object operations
├── tx         - Transaction management
├── io         - I/O operations (DKey/AKey/IoBuffer)
├── query      - Query operations
├── iter       - Iterator utilities
├── oit        - Object instance tracking (currently unavailable)
└── prelude    - Common exports

MSRV (Minimum Supported Rust Version)

  • MSRV: Rust 1.85
  • Edition: 2024

License

GPL-3.0-only

Dependencies

~5–11MB
~133K SLoC