5 unstable releases
Uses new Rust 2024
| 0.3.0-heed+mdbx | Oct 29, 2025 |
|---|---|
| 0.2.0-heed | Oct 25, 2025 |
| 0.1.2 | Sep 18, 2025 |
| 0.1.1 | Sep 17, 2025 |
| 0.1.0 | Jul 4, 2025 |
#357 in Rust patterns
Used in v-common
130KB
2.5K
SLoC
v-storage
A flexible storage abstraction library for the Veda platform. Provides unified interface for different storage backends including memory, LMDB, MDBX, Tarantool, and remote storage.
๐ Features
- Multiple Storage Backends: Memory, LMDB, MDBX, Tarantool (TTStorage), Remote storage
- Unified API: Common
Storagetrait for all backends - Three Architecture Patterns: Dynamic dispatch, generic containers, enum dispatch
- Individual Support: Native support for Veda platform Individual objects
- Zero-cost Abstractions: Compile-time optimization options with minimal overhead
- Factory Patterns: Builder, Provider, and Config patterns for easy construction
- Error Handling: Comprehensive error types and result handling
- Backward Compatibility: Support for legacy API methods
๐ฆ Installation
Add this to your Cargo.toml:
[dependencies]
v-storage = "0.1.0"
# Optional features
v-storage = { version = "0.1.0", features = ["tt_2", "tokio_0_2"] }
Available Features
tt_2- Tarantool 2.x supporttt_3- Tarantool 3.x supporttokio_0_2- Tokio 0.2 runtime supporttokio_1- Tokio 1.x runtime support
๐ Quick Start
use v_storage::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create memory storage
let storage = VStorage::builder()
.memory()
.build()?;
let mut storage = VStorage::new(storage);
// Store Individual with semantic predicates
storage.put_value(StorageId::Individuals, "user:1", r#"{
"@": "user:1",
"rdf:type": [{"type": "Uri", "data": "foaf:Person"}],
"rdfs:label": [{"type": "String", "data": "John Smith - Software Engineer"}],
"foaf:name": [{"type": "String", "data": "John"}],
"foaf:familyName": [{"type": "String", "data": "Smith"}],
"foaf:age": [{"type": "Integer", "data": 30}],
"foaf:mbox": [{"type": "String", "data": "john.smith@example.com"}],
"veda:hasPosition": [{"type": "Uri", "data": "position:software_engineer"}],
"org:memberOf": [{"type": "Uri", "data": "org:development_team"}]
}"#)?;
// Retrieve Individual
if let StorageResult::Ok(data) = storage.get_value(StorageId::Individuals, "user:1") {
println!("User Individual: {} bytes", data.len());
}
Ok(())
}
๐๏ธ Architecture
Storage Types
| Type | Description | Dispatch | Use Case |
|---|---|---|---|
| VStorage | Dynamic dispatch with trait objects | Runtime | Maximum flexibility, runtime type selection |
| VStorageGeneric | Compile-time typed containers | Static | Type safety, known storage type |
| VStorageEnum | Static dispatch through enum | Static | Applications preferring enum dispatch |
Storage Backends
- Memory Storage - In-memory HashMap-based storage
- LMDB Storage - Lightning Memory-Mapped Database (heed 0.22.0)
- MDBX Storage - Modern fork of LMDB with improved performance (libmdbx 0.6.3)
- Tarantool Storage - In-memory NoSQL database
- Remote Storage - Network-based storage client
StorageId Types
- Individuals - Main Individual objects for Veda platform
- Tickets - System tickets and tasks
- Az - Authorization and permission data
๐ Usage Examples
Basic Operations
use v_storage::*;
// Create storage using Builder pattern
let storage = VStorage::builder()
.memory()
.build()?;
let mut storage = VStorage::new(storage);
// Basic operations with semantic Individual data
storage.put_value(StorageId::Individuals, "person:example", r#"{
"@": "person:example",
"rdf:type": [{"type": "Uri", "data": "foaf:Person"}],
"rdfs:label": [{"type": "String", "data": "Example Person"}],
"foaf:name": [{"type": "String", "data": "Example"}]
}"#)?;
storage.get_value(StorageId::Individuals, "person:example")?;
storage.remove_value(StorageId::Individuals, "person:example")?;
storage.count(StorageId::Individuals)?;
Factory Patterns
// Builder Pattern - LMDB
let storage = VStorage::builder()
.lmdb("/path/to/db", StorageMode::ReadWrite, None)
.build()?;
// Builder Pattern - MDBX (recommended)
let storage = VStorage::builder()
.mdbx("/path/to/db", StorageMode::ReadWrite, None)
.build()?;
// Provider Pattern
let storage = StorageProvider::memory();
let storage = StorageProvider::mdbx("/path/to/db", StorageMode::ReadWrite, None);
// Config Pattern
let config = StorageConfig::Memory;
let storage = VStorage::from_config(config)?;
// Config Pattern - MDBX
let config = StorageConfig::Mdbx {
path: "/path/to/db".to_string(),
mode: StorageMode::ReadWrite,
max_read_counter_reopen: None,
};
let storage = VStorage::from_config(config)?;
Working with Individual Objects
use v_individual_model::onto::individual::Individual;
let mut individual = Individual::default();
let result = storage.get_individual(
StorageId::Individuals,
"person:john",
&mut individual
);
match result {
v_result_code::ResultCode::Ok => {
println!("Individual loaded: {}", individual.get_id());
},
v_result_code::ResultCode::NotFound => {
println!("Individual not found");
},
_ => println!("Error loading individual"),
}
Static Dispatch Usage
// Use VStorageEnum for static dispatch
let mut storage = VStorageEnum::memory();
// Batch operations with semantic Individual data
for i in 0..1000 {
let individual_data = format!(r#"{{
"@": "person:{}",
"rdf:type": [{{"type": "Uri", "data": "foaf:Person"}}],
"rdfs:label": [{{"type": "String", "data": "Person {}"}}],
"foaf:name": [{{"type": "String", "data": "Person{}"}}],
"veda:index": [{{"type": "Integer", "data": {}}}]
}}"#, i, i, i, i);
storage.put_value(
StorageId::Individuals,
&format!("person:{}", i),
&individual_data
)?;
}
๐ฏ Design Patterns
Strategy Pattern
Unified Storage interface allows switching between different storage implementations:
fn process_data(storage: &mut dyn Storage) {
// Works with any storage implementation
storage.put_value(StorageId::Individuals, "person:demo", r#"{
"@": "person:demo",
"rdf:type": [{"type": "Uri", "data": "foaf:Person"}],
"rdfs:label": [{"type": "String", "data": "Demo Person"}]
}"#);
}
Builder Pattern
Fluent API for configuring storage:
let storage = VStorage::builder()
.memory()
.build()?;
Abstract Factory
Multiple ways to create storage instances:
// Through provider
let storage1 = StorageProvider::memory();
// Through config
let storage2 = VStorage::from_config(StorageConfig::Memory)?;
// Through builder
let storage3 = VStorage::builder().memory().build()?;
๐ Architecture Comparison
Theoretical dispatch overhead (in practice, database I/O dominates):
| Storage Type | Dispatch | Memory | Flexibility |
|---|---|---|---|
| VStorageEnum | Static (enum match) | Stack | Fixed set of types |
| VStorageGeneric | Static (monomorphization) | Direct | Compile-time known |
| VStorage | Dynamic (vtable) | Heap | Runtime selection |
Note: In real applications, storage backend (LMDB, Tarantool, network) dominates timing.
๐ง Configuration
Memory Storage
let storage = VStorage::builder()
.memory()
.build()?;
LMDB Storage
let storage = VStorage::builder()
.lmdb("/path/to/database", StorageMode::ReadWrite, Some(1000))
.build()?;
MDBX Storage
// Modern LMDB alternative with better performance
let storage = VStorage::builder()
.mdbx("/path/to/database", StorageMode::ReadWrite, None)
.build()?;
// Or use generic version for static dispatch
let storage = StorageProvider::mdbx_generic(
"/path/to/database",
StorageMode::ReadWrite,
None
);
Tarantool Storage
// Requires tt_2 or tt_3 feature
let storage = VStorage::builder()
.tarantool("127.0.0.1:3301", "username", "password")
.build()?;
Remote Storage
let storage = VStorage::builder()
.remote("127.0.0.1:8080")
.build()?;
๐ Examples
The examples/ directory contains comprehensive examples:
- basic_usage.rs - Basic operations and API usage
- storage_types.rs - Comparison of different storage types
- factory_patterns.rs - Various construction patterns
- individual_operations.rs - Working with Individual objects
- mdbx_usage.rs - MDBX storage usage patterns
Run examples:
cargo run --example basic_usage
cargo run --example storage_types
cargo run --example factory_patterns
cargo run --example individual_operations
cargo run --example mdbx_usage
๐ ๏ธ Development
Building
# Basic build
cargo build
# With all features
cargo build --features "tt_2 tokio_0_2"
# Release build
cargo build --release
Testing
# Run tests
cargo test
# Run tests with features
cargo test --features "tt_2 tokio_0_2"
# Run integration tests
cargo test --test integration_tests
Documentation
# Generate documentation
cargo doc --open
# Generate with examples
cargo doc --examples --open
๐ Error Handling
The library uses comprehensive error types:
match storage.get_value(StorageId::Individuals, "key") {
StorageResult::Ok(value) => println!("Value: {}", value),
StorageResult::NotFound => println!("Key not found"),
StorageResult::Error(e) => println!("Error: {}", e),
}
๐งช Testing
# Unit tests
cargo test
# Integration tests
cargo test --test integration_tests
# Example tests
cargo test --examples
# All tests with release optimization
cargo test --release
๐ Requirements
- Rust: 1.70 or higher
- Operating System: Linux, macOS, Windows
- Dependencies: See Cargo.toml
Optional Requirements
- LMDB: System LMDB libraries for LMDBStorage (heed 0.22.0)
- MDBX: libmdbx 0.6.3 for MDBXStorage - modern LMDB fork with better performance
- Tarantool: Running Tarantool instance for TTStorage
- Network: Connectivity for RemoteStorage
๐ค Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
- Clone the repository
- Install Rust 1.70+
- Run
cargo build - Run
cargo test - Check examples with
cargo run --example basic_usage
Code Style
- Use
cargo fmtfor formatting - Use
cargo clippyfor linting - Add tests for new features
- Update documentation
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Related Projects
- Veda Platform - Semantic data management platform
- v-individual-model - Individual object model
- LMDB - Lightning Memory-Mapped Database
- libmdbx - Modern LMDB fork with better performance and reliability
- Tarantool - In-memory database and application server
๐ก FAQ
Q: Which storage type should I choose?
A: Use VStorageEnum for applications preferring static dispatch, VStorageGeneric for type safety with known storage types, and VStorage for maximum flexibility.
Q: Can I switch storage backends at runtime?
A: Yes, with VStorage dynamic dispatch. Generic types require compile-time selection.
Q: Is the library thread-safe? A: Storage instances are not thread-safe by default. Use appropriate synchronization for concurrent access.
Q: How do I handle network failures with RemoteStorage?
A: The library returns StorageResult::Error for network issues. Implement retry logic in your application.
Q: Should I use LMDB or MDBX? A: MDBX is a modern fork of LMDB with improved performance, better reliability, and additional features. For new projects, MDBX is recommended. LMDB remains supported for compatibility with existing systems.
Built with โค๏ธ for the Veda platform
Dependencies
~21โ29MB
~506K SLoC