use graph_d::memory::allocator_safe::SafeMemoryManager;
use graph_d::memory::cache::{CacheConfig, NodeCache, RelationshipCache};
use graph_d::memory::interning::GraphStringInterner;
use graph_d::memory::{MemoryConfig, MemoryManager};
use graph_d::{Graph, Result};
use serde_json::json;
fn main() -> Result<()> {
println!("Graph Database Memory Management Example");
println!("========================================");
basic_memory_management()?;
safe_memory_allocators()?;
intelligent_caching()?;
string_interning_example()?;
Ok(())
}
fn basic_memory_management() -> Result<()> {
println!("\n1. Basic Memory Management");
println!("--------------------------");
let config = MemoryConfig {
max_memory_bytes: 1024 * 1024 * 1024, arena_size_bytes: 64 * 1024 * 1024, node_cache_capacity: 100_000, relationship_cache_capacity: 400_000, property_cache_capacity: 200_000, string_table_capacity: 50_000, };
let memory_manager = MemoryManager::new(config)?;
let mut graph = Graph::new()?;
println!("Creating nodes with memory tracking...");
let mut node_ids = Vec::new();
for i in 0..1000 {
let properties = [
("id".to_string(), json!(i)),
("name".to_string(), json!(format!("Node{}", i))),
("category".to_string(), json!(format!("cat_{}", i % 10))),
]
.into();
let node_id = graph.create_node(properties)?;
node_ids.push(node_id);
if i % 10 == 0 {
let node_data = format!("node_data_{i}").into_bytes();
memory_manager.cache_node(node_id, node_data);
}
}
let stats = memory_manager.memory_stats();
println!("Memory Statistics:");
println!(" Total allocated: {} bytes", stats.total_allocated);
println!(" Node cache: {} bytes", stats.node_cache_bytes);
println!(" Cache hit rate: {:.2}%", stats.cache_hit_rate * 100.0);
let handle = memory_manager.arena_alloc(vec![1, 2, 3, 4, 5]);
println!("Arena allocated data: {:?}", handle.get());
memory_manager.check_memory_pressure()?;
println!("Memory pressure check completed");
Ok(())
}
fn safe_memory_allocators() -> Result<()> {
println!("\n2. Safe Memory Allocators");
println!("-------------------------");
let memory_manager = SafeMemoryManager::new(1024 * 1024);
{
let mut node_buffer = memory_manager.acquire_node_buffer();
node_buffer
.get_mut()
.extend_from_slice(b"node_data_example");
println!("Node buffer contains: {} bytes", node_buffer.get().len());
let mut rel_buffer = memory_manager.acquire_relationship_buffer();
rel_buffer.get_mut().extend_from_slice(b"relationship_data");
println!(
"Relationship buffer contains: {} bytes",
rel_buffer.get().len()
);
}
let stats = memory_manager.stats();
println!("Safe Memory Statistics:");
println!(" Arena usage: {} bytes", stats.arena_usage);
println!(
" Node pool available: {}",
stats.node_pool.available_objects
);
println!(
" Relationship pool available: {}",
stats.relationship_pool.available_objects
);
memory_manager.arena().scoped(|| {
println!("Performing scoped operations...");
42
});
Ok(())
}
fn intelligent_caching() -> Result<()> {
println!("\n3. Intelligent Caching");
println!("----------------------");
let cache_config = CacheConfig {
hot_cache_size: 1000,
cold_cache_size: 10000,
promotion_threshold: 3,
..Default::default()
};
let node_cache = NodeCache::new(cache_config.clone())?;
let _rel_cache = RelationshipCache::new(cache_config)?;
println!("Simulating access patterns...");
for i in 0..100 {
let node_data = format!("node_{i}").into_bytes();
node_cache.put_node(i, node_data);
node_cache.put_property(i, "name".to_string(), json!(format!("Node{}", i)));
node_cache.put_property(i, "type".to_string(), json!("test"));
}
for _ in 0..5 {
for i in 0..10 {
if let Some(data) = node_cache.get_node(i) {
println!("Hot access: Node {} has {} bytes", i, data.len());
}
if let Some(name) = node_cache.get_property(i, "name") {
println!("Property access: name = {name}");
}
}
}
let (cache_stats, property_cache_size) = node_cache.stats();
println!("Node Cache Statistics:");
println!(" Hit rate: {:.2}%", cache_stats.hit_rate() * 100.0);
println!(" Hot hit rate: {:.2}%", cache_stats.hot_hit_rate() * 100.0);
println!(" Promotions: {}", cache_stats.promotions);
println!(" Property cache size: {property_cache_size}");
Ok(())
}
fn string_interning_example() -> Result<()> {
println!("\n4. String Interning");
println!("-------------------");
let interner = GraphStringInterner::new(10000);
let name_id = interner.intern("name");
let type_id = interner.intern("type");
let id_id = interner.intern("id");
println!("Interned common properties:");
println!(" 'name' -> ID {name_id}");
println!(" 'type' -> ID {type_id}");
println!(" 'id' -> ID {id_id}");
let name_id2 = interner.intern("name");
println!(
" 'name' again -> ID {} (same: {})",
name_id2,
name_id == name_id2
);
println!(" 'name' is common: {}", interner.is_common_string("name"));
println!(
" 'custom_prop' is common: {}",
interner.is_common_string("custom_prop")
);
for i in 0..100 {
let unique_value = format!("unique_value_{i}");
interner.intern(&unique_value);
}
let stats = interner.stats();
let savings = interner.savings();
println!("String Interning Statistics:");
println!(" Unique strings: {}", stats.interned_strings);
println!(" Utilization: {:.2}%", stats.utilization() * 100.0);
println!(" Total string bytes: {}", stats.total_string_bytes);
println!(" Memory savings: {} bytes", savings.bytes_saved);
println!(" Net beneficial: {}", savings.is_beneficial());
println!(" Compression ratio: {:.2}x", savings.compression_ratio());
Ok(())
}