S3dlio

Latest version: v0.9.112

Safety actively analyzes 971914 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 1 of 11

192.168.1.109000

// Load URIs from configuration file (one per line)
load_uris_from_file("endpoints.txt")?;


**5. Statistics and Monitoring:**
rust
// Per-endpoint statistics (lock-free atomics)
let stats = store.get_endpoint_stats();
for (i, stat) in stats.iter().enumerate() {
println!("Endpoint {}: {} requests, {} bytes, {} active connections",
i, stat.requests, stat.bytes_transferred, stat.active_connections);
}

// Total aggregated statistics
let total = store.get_total_stats();
println!("Total: {} requests, {} bytes, {} errors",
total.total_requests, total.total_bytes, total.total_errors);


**6. Python API** - Zero-copy support via `BytesView`:
python
import s3dlio

Create multi-endpoint store
store = s3dlio.create_multi_endpoint_store(
uris=["s3://bucket-1/data", "s3://bucket-2/data", "s3://bucket-3/data"],
strategy="least_connections" or "round_robin"
)

Zero-copy data access (buffer protocol support)
data = store.get("s3://bucket-1/large-file.bin")
mv = memoryview(data) No copy!
array = np.frombuffer(mv, dtype=np.float32)

Template expansion
store = s3dlio.create_multi_endpoint_store_from_template(
template="s3://shard-{1...10}/dataset",
strategy="round_robin"
)

File-based configuration
store = s3dlio.create_multi_endpoint_store_from_file(
file_path="endpoints.txt",
strategy="least_connections"
)

Statistics
stats = store.get_endpoint_stats()
total = store.get_total_stats()


โœจ **Features**

**Architecture:**
- Thread-safe design with atomic statistics (no lock contention)
- Schema validation: all endpoints must use same URI scheme (s3://, az://, gs://, file://, direct://)
- Transparent ObjectStore implementation - works anywhere single store is expected
- Per-endpoint thread pool control for optimal resource utilization

**Performance:**
- Lock-free atomic counters for statistics (zero contention overhead)
- Round-robin: ~10ns overhead per request
- Least-connections: ~50ns overhead per request
- Zero-copy Python interface via `BytesView` (buffer protocol)
- Negligible overhead vs latency (< 0.01% for typical cloud requests)

**Use Cases:**
- **Distributed ML training**: Access sharded datasets across multiple S3 buckets
- **High-throughput benchmarking**: Aggregate bandwidth from multiple storage servers
- **Fault tolerance**: Continue operations if individual endpoints fail
- **Geographic distribution**: Route requests to regionally-optimal endpoints
- **Load testing**: Distribute synthetic workloads across multiple backends

๐Ÿ“ **Testing**

**Comprehensive Test Coverage:**
- 33 new tests (16 in `uri_utils`, 17 in `multi_endpoint`)
- Total test count: 141 tests (all passing)
- Zero-copy validation tests in Python suite
- Load balancing distribution tests
- Error handling and validation tests

**Python Test Suite** (`tests/test_multi_endpoint.py`):
- Store creation from URIs, templates, and files
- Zero-copy data access via `memoryview()`
- NumPy/PyTorch integration tests
- Load balancing statistics validation
- Error handling for invalid configurations

๐Ÿ”ง **API Reference**

**Rust API:**
rust
// Module exports
pub use multi_endpoint::{
MultiEndpointStore,
MultiEndpointStoreConfig,
EndpointConfig,
LoadBalanceStrategy,
EndpointStats,
TotalStats,
};

pub use uri_utils::{
expand_uri_template,
parse_uri_list,
load_uris_from_file,
infer_scheme_from_uri, // Now public for validation
};


**Python API:**
python
Factory functions
s3dlio.create_multi_endpoint_store(uris, strategy) -> PyMultiEndpointStore
s3dlio.create_multi_endpoint_store_from_template(template, strategy) -> PyMultiEndpointStore
s3dlio.create_multi_endpoint_store_from_file(file_path, strategy) -> PyMultiEndpointStore

PyMultiEndpointStore methods
store.get(uri) -> BytesView Zero-copy
store.get_range(uri, offset, length) -> BytesView Zero-copy
store.put(uri, data) -> None
store.list(prefix, recursive) -> List[str]
store.delete(uri) -> None
store.get_endpoint_stats() -> List[Dict]
store.get_total_stats() -> Dict


๐Ÿ“– **Documentation**

**New Documentation:**
- **[MULTI_ENDPOINT_GUIDE.md](MULTI_ENDPOINT_GUIDE.md)** - Comprehensive guide with:
- Architecture overview and design principles
- Load balancing strategy comparison
- Rust and Python API examples
- Configuration methods (URIs, templates, files)
- Performance tuning guidelines
- Best practices and use cases
- Advanced topics (NUMA affinity, monitoring)
- Troubleshooting guide

**Updated Documentation:**
- **[README.md](../README.md)** - Added multi-endpoint quick example in Python section
- **[docs/README.md](README.md)** - Added MULTI_ENDPOINT_GUIDE.md to Technical References

๐Ÿ”„ **Backward Compatibility**

โœ… **Zero Breaking Changes:**
- New optional feature - existing code unaffected
- Single-endpoint workflows continue working unchanged
- Can wrap single endpoint in multi-endpoint store for future flexibility

๐ŸŽฏ **Use Case Examples**

**1. Distributed ML Training:**
python
Access sharded training data across 10 S3 buckets
store = s3dlio.create_multi_endpoint_store_from_template(
template="s3://training-shard-{1...10}/data",
strategy="least_connections"
)

Zero-copy data loading
for uri in file_list:
data = store.get(uri)
tensor = torch.frombuffer(memoryview(data), dtype=torch.float32)


**2. High-Throughput Benchmarking:**
rust
// Aggregate bandwidth across 4 storage servers
let endpoints = vec![
"s3://benchmark-1/test", "s3://benchmark-2/test",
"s3://benchmark-3/test", "s3://benchmark-4/test",
];

// Round-robin for predictable load distribution
let config = MultiEndpointStoreConfig {
endpoints: endpoints.iter().map(|uri| EndpointConfig {
uri: uri.to_string(),
thread_count: Some(8),
..Default::default()
}).collect(),
strategy: LoadBalanceStrategy::RoundRobin,
..Default::default()
};


**3. Geographic Distribution:**
python
Route to fastest regional endpoint automatically
store = s3dlio.create_multi_endpoint_store(
uris=[
"s3://data-us-west-2/dataset",
"s3://data-us-east-1/dataset",
"s3://data-eu-west-1/dataset",
],
strategy="least_connections" Naturally favors lower-latency endpoints
)


๐Ÿ” **Implementation Details**

**Zero-Copy Design:**
- Python `get()` and `get_range()` return `PyBytesView` objects
- `PyBytesView` implements Python buffer protocol
- Allows `memoryview()` access without copying data
- Compatible with NumPy, PyTorch, and other buffer-aware libraries
- Maintains Arc-counted `Bytes` reference (cheap clone, automatic cleanup)

**Thread Safety:**
- All statistics use `AtomicU64` counters (lock-free)
- Endpoint selection protected by `Mutex` (minimal contention)
- Concurrent operations across different endpoints fully parallel
- No performance degradation under high concurrency

**Schema Validation:**
- All endpoints must use same URI scheme (enforced at creation)
- Prevents mixing incompatible backends (e.g., s3:// + file://)
- Clear error messages for configuration mistakes

๐Ÿ“Š **Performance Characteristics**

**Throughput Scaling:**
- 2 endpoints: 1.8-2.0ร— baseline throughput
- 4 endpoints: 3.5-4.0ร— baseline throughput
- 8 endpoints: 6.5-8.0ร— baseline throughput
- 16+ endpoints: 12-16ร— baseline throughput

**Overhead:**
- RoundRobin: ~10ns per request (atomic increment)
- LeastConnections: ~50ns per request (atomic read + compare)
- For typical cloud requests (1-100ms), overhead < 0.01%

๐Ÿ”ง **Configuration Examples**

**endpoints.txt** (file-based configuration):
text
Production multi-region setup
s3://prod-us-west-2/data
s3://prod-us-east-1/data
s3://prod-eu-west-1/data

Comments and blank lines ignored


**Template Patterns:**
rust
// Simple numeric range
"s3://bucket-{1...5}/data"

// Zero-padded range
"s3://bucket-{01...10}/data"

// IP addresses for direct I/O
"direct://192.168.1.{1...10}:9000"

// Multiple ranges (Cartesian product)
"s3://rack{1...3}-node{1...4}" // โ†’ 12 URIs


---

127.0.0.110000

sai3-bench util ls az://devstoreaccount1/testcontainer/

Multi-protocol proxy
export AZURE_STORAGE_ENDPOINT=http://localhost:9001
sai3-bench util ls az://myaccount/mycontainer/


**Custom Endpoint Support for Google Cloud Storage**
- Added environment variable support for custom GCS endpoints
- Primary: `GCS_ENDPOINT_URL` (e.g., `http://localhost:4443`)
- Alternative: `STORAGE_EMULATOR_HOST` (GCS emulator convention, `http://` prepended if missing)
- Enables use with fake-gcs-server or other GCS-compatible emulators/proxies
- Anonymous authentication used automatically for custom endpoints (typical for emulators)

Usage:
bash
fake-gcs-server (local emulator)
export GCS_ENDPOINT_URL=http://localhost:4443
sai3-bench util ls gs://testbucket/

Using STORAGE_EMULATOR_HOST convention
export STORAGE_EMULATOR_HOST=localhost:4443
sai3-bench util ls gs://testbucket/

Multi-protocol proxy
export GCS_ENDPOINT_URL=http://localhost:9002
sai3-bench util ls gs://testbucket/


๐Ÿ“ **Documentation**

- Updated `docs/api/Environment_Variables.md` with Azure and GCS endpoint configuration
- Added new constants in `src/constants.rs` for endpoint environment variable names:
- `ENV_AZURE_STORAGE_ENDPOINT`
- `ENV_AZURE_BLOB_ENDPOINT_URL`
- `ENV_GCS_ENDPOINT_URL`
- `ENV_STORAGE_EMULATOR_HOST`

โšก **Compatibility**

**Backwards Compatibility**: No breaking changes
- When environment variables are not set, behavior remains identical to previous versions
- Connects to public cloud endpoints by default (Azure Blob, GCS)
- S3 custom endpoint support via `AWS_ENDPOINT_URL` remains unchanged

**Related Issue**: https://github.com/russfellows/sai3-bench/issues/56

---

42.0

let arrays = vec![
("data", &data),
("labels", &labels),
("metadata", &metadata),
];

let npz_bytes = build_multi_npz(arrays)?;
// Write npz_bytes to file or object storage


**Python Interoperability:**

python
import numpy as np

Load multi-array NPZ created by Rust
data = np.load("dataset.npz")
print(data.files) ['data', 'labels', 'metadata']

images = data['data'] Shape: (224, 224, 3)
labels = data['labels'] Shape: (10,)
metadata = data['metadata'] Shape: (5,)


**Key Features:**
- **Zero-copy design**: Uses `Bytes` for efficient memory handling
- **Proper ZIP structure**: Compatible with NumPy's `np.load()`
- **Named arrays**: Custom names for each array in the archive
- **Type support**: f32 arrays (primary ML use case)
- **Comprehensive tests**: 5 new tests covering single/multi-array scenarios

**Use Cases:**
- AI/ML dataset generation (images + labels + metadata)
- Scientific computing (simulation results + parameters + timestamps)
- dl-driver workload generation (simplified from 150+ lines to 80 lines)

---

๐Ÿ”ง **TFRecord Index Generation API**

Exported `build_tfrecord_with_index()` function and `TfRecordWithIndex` struct for creating TFRecord files with accompanying index files, enabling compatibility with TensorFlow Data Service.

**New Exports:**

rust
use s3dlio::data_formats::{build_tfrecord_with_index, TfRecordWithIndex};

// Generate TFRecord with index in single pass
let raw_data = s3dlio::generate_controlled_data(102400, 1, 1);
let result = build_tfrecord_with_index(
100, // num_records
1024, // record_size
&raw_data
)?;

// result.data: Bytes containing TFRecord file
// result.index: Bytes containing index file (16 bytes per record)

// Write both files
store.put("dataset.tfrecord", &result.data).await?;
store.put("dataset.tfrecord.index", &result.index).await?;


**Index Format** (TensorFlow Data Service compatible):

For each record:
- offset: u64 (8 bytes, little-endian) - Byte offset in TFRecord file
- length: u64 (8 bytes, little-endian) - Record length in bytes
Total: 16 bytes per record


**Key Features:**
- **Zero overhead**: Index generated during TFRecord creation (single pass)
- **Standard format**: Compatible with TensorFlow Data Service expectations
- **Efficient**: Returns `Bytes` for zero-copy I/O
- **Documented**: Clear API for downstream tools (dl-driver, custom tools)

**Performance:**
- No additional I/O operations
- Minimal memory overhead (16 bytes per record)
- Example: 1000 records โ†’ 16KB index file

**Background:**

TensorFlow Data Service can leverage index files to optimize random access patterns and enable efficient dataset sharding across distributed workers. This API enables tools to generate properly formatted indices alongside TFRecord data files.

---

๐Ÿ”„ **Custom NPY/NPZ Implementation**

Previously in v0.9.16, replaced `ndarray-npy` dependency with custom 328-line implementation for better control, zero-copy performance, and elimination of version conflicts.

3.1c

| 3.1d | `src/checkpoint/reader.rs` (2 sites) | Distributed-checkpoint shard reads. |
| 3.1e | `src/azure_client.rs::upload_multipart_stream` | Azure block-upload path. |
| 3.1f | `src/range_engine_generic.rs::download_with_ranges` | Shared Azure/GCS range engine. Uses `FuturesOrdered` + bounded prime-and-refill pool to preserve short-read semantics and cap peak memory. |
| 3.1g | `src/s3_utils.rs::stat_object_many_async` | HEAD-batch stat. The trait-default `pre_stat_objects` cannot be spawn-based without breaking `dyn ObjectStore` compatibility; documented with a caveat and a pointer at `stat_object_many_async` as the pattern backends should copy. |
| 3.1h | `src/data_loader/s3_bytes.rs::ReaderMode::Range` | Same `FuturesOrdered` + bounded pool pattern as 3.1f. |

Phase 2 bug class B โ€” drop-doesn't-abort at short-circuit sites (4 sites)

Four sites that already used `tokio::spawn` correctly had the
`while let Some(res) = futs.next().await { out.push(res??); }` pattern โ€”
which returns from the outer function on the first error, dropping the
remaining `FuturesUnordered<JoinHandle<...>>`. Dropping a `JoinHandle`
*detaches* the task rather than aborting it, so the remaining in-flight
uploads/downloads keep running in the background after the caller has
already returned an error. Retrofitted to the drain-first-then-first-err
pattern from `object_store.rs::generic_upload_files` (which was already
correct). No in-flight task is ever detached.

Phase 4 โ€” streaming connector + centralized retry (2 sites)

**Streaming connector.** The reqwest connector previously fully
buffered every response body (`resp.bytes().await`) before handing it
to the SDK โ€” so the SDK saw byte one only after the last byte
arrived, and every body-transfer connection interruption had to be
recovered by the smithy retry loop instead of by re-streaming. Now
constructs `SdkBody::from_body_1_x(StreamBody::new(SyncStream::new(bytes_stream)))`
โ€” SDK sees byte one at the moment it arrives on the wire.

`SyncStream` from `sync_wrapper 1.x` provides `Sync` for the reqwest
stream (which is `Send` but not `Sync`) at zero runtime cost via Rust
aliasing rules. Cargo changes: promote `http-body`, `sync_wrapper`
(feature `futures`) to direct deps; enable `http-body-1-x` feature on
`aws-smithy-types`; add `stream` feature to `reqwest`. All four crates
were already transitive; only feature flags and direct-dep declarations
change.

**Centralized retry.** The streaming change means smithy's own retry
no longer covers body-transfer failures (smithy considers the request
done once `send()` returns headers). New shared helper
`crate::retry::retry_get_body<F, Fut, T, E>` bounded by
`max_retry_attempts()` with linear `100ms * attempt` backoff, wired
into four caller sites:

* `S3Ops::get_object` and `S3Ops::get_object_range` โ€” whole-object /
range GET. Fresh `Bytes` per attempt, trivially idempotent.
* `S3ObjectStore::get` and `S3ObjectStore::get_range` direct-client
paths โ€” same shape.
* `s3_utils::concurrent_range_get_impl` range-chunk task โ€” the audit
ยง2.4 silent-data-corruption gate. Retries stream directly into a
shared, pre-allocated `BytesMut` segment. Inline retry loop (not
`retry_get_body`) because the helper's `FnMut() โ†’ Fut` signature
can't share `&mut seg` across attempts. The
`attempt_range_chunk_fill` helper declares `written = 0` locally so
each retry starts writing at position 0 โ€” locked in by the
fault-injection regression test in
`tests/test_phase4_retry_fault_injection.rs`.

Note: a live end-to-end DLIO_local_changes `unet3d` smoke test against
the streaming-connector s3dlio hit **99.6% AU** with `train_au_meet_expectation:
success` โ€” proves the DLIO training path works cleanly with the new
wheel.

Fault-injection gate (audit ยง2.4 blocking requirement)

`tests/test_phase4_retry_fault_injection.rs::phase4_range_chunk_retry_resets_written_cursor_on_each_attempt`
locks in the invariant that each retry attempt starts with a fresh
`written = 0` cursor when writing streamed bytes into the shared range
segment. If `written` leaked across attempts, a partial failed stream's
bytes would remain at `seg[0..old_written]` mixed with successful
retry bytes โ€” length correct, content silently corrupt. This is the
class of bug the audit specifically flagged; the test proves the
implementation is not exposed to it.

RED-then-GREEN test coverage

Every phase landed with dedicated regression tests that fail against
pre-fix code and pass against fixed code, so the transitions are
bisectable:

| Phase | Regression test |
|---|---|
| 1 | `tests/test_phase1_zero_copy_assembly.rs` โ€” peak-memory-tracking allocator, โ‰ค 1.5ร— total_size |
| 2 site 3.1a | `tests/test_phase2_loader_parallelism.rs` โ€” 4 tests (parallelism, external cancel, drop-cancels, panic surfaces) |
| 2 site 3.1b/3.1d pattern | `tests/test_phase2_join_all_vs_spawn.rs` โ€” `join_all` serializes vs. `tokio::spawn` distributes |
| 2 bug class B | `tests/test_phase2_drain_first_err.rs` โ€” short-circuit vs. drain-first-then-error |
| 4 | `tests/test_phase4_retry_fault_injection.rs` โ€” audit ยง2.4 silent-data-corruption gate |

Zero warnings across `cargo clippy --lib --tests --no-deps -- -D warnings`
under default features, `--features backend-azure`, and
`--features full-backends`. `cargo fmt --check` clean. All shipped
pre-existing test-file clippy warnings across azure_blob_smoke,
test_azure_comprehensive, test_azure_range_engine_integration,
test_gcs_smoke, and test_range_engine_defaults resolved as part of the
release gate.

See [`docs/enhancement/PERF-CONCURRENCY-AUDIT-issue148.md`](enhancement/PERF-CONCURRENCY-AUDIT-issue148.md)
for the full audit and rationale;
[`docs/enhancement/PERF-CONCURRENCY-AUDIT-issue148_Bench-Results.md`](enhancement/PERF-CONCURRENCY-AUDIT-issue148_Bench-Results.md)
for reproducible before/after benchmark methodology and full raw
numbers.

---

3.1b

3.1a

Page 1 of 11

ยฉ 2026 Safety CLI Cybersecurity Inc. All Rights Reserved.