Crates.io | bathroom |
lib.rs | bathroom |
version | 0.0.1 |
created_at | 2025-03-05 20:31:11.039311+00 |
updated_at | 2025-03-05 20:31:11.039311+00 |
description | Implementation of the Bathroom Model hash table algorithm |
homepage | |
repository | https://github.com/minikin/bathroom |
max_upload_size | |
id | 1579570 |
size | 113,021 |
⚠️ IMPORTANT NOTICE:
- Status: This project is currently a work in progress (WIP) and highly experimental
- Production Readiness: Not recommended for production use at this moment
- Development Timeline: Ongoing development with no specific timeframe for production readiness
- Current Limitations: Performance testing incomplete, API may change significantly
- Usage: Recommended for research, experimentation, and feedback only
- Progress: Track development on the Issues page
A Rust implementation of the Bathroom Model for hash map optimization, featuring adaptive probing strategies inspired by real-world bathroom stall selection behavior.
This implementation is based on two groundbreaking research papers:
The Bathroom Model draws inspiration from human behavior when selecting bathroom stalls. Just as people dynamically adjust their search strategy based on occupancy patterns when looking for an available stall, this hash table implementation adaptively modifies its probing sequence based on observed data distribution patterns.
ElasticHashMap
: Single-threaded implementation with optimal lookup performanceConcurrentElasticMap
: Thread-safe implementation using atomic operationsAdd this to your Cargo.toml
:
[dependencies]
bathroom = "0.0.1"
use bathroom::ElasticHashMap;
// Create a new hash map
let mut map = ElasticHashMap::new();
// Insert values
map.insert("apple".to_string(), 1);
map.insert("banana".to_string(), 2);
map.insert("cherry".to_string(), 3);
// Retrieve values
assert_eq!(map.get("apple"), Some(&1));
// Update values
map.insert("apple".to_string(), 10);
assert_eq!(map.get("apple"), Some(&10));
// Remove values
map.remove("apple");
assert_eq!(map.get("apple"), None);
// Check if key exists
assert!(map.contains_key("banana"));
// Get all keys or values
let keys = map.keys();
let values = map.values();
use bathroom::ConcurrentElasticMap;
use std::sync::Arc;
use std::thread;
// Create a shared hash map
let map = Arc::new(ConcurrentElasticMap::new());
// Clone references for different threads
let map1 = Arc::clone(&map);
let map2 = Arc::clone(&map);
// Spawn threads that modify the map concurrently
let t1 = thread::spawn(move || {
for i in 0..100 {
map1.insert(format!("key-{}", i), i);
}
});
let t2 = thread::spawn(move || {
for i in 100..200 {
map2.insert(format!("key-{}", i), i);
}
});
// Wait for threads to complete
t1.join().unwrap();
t2.join().unwrap();
// The map now contains all inserted values
assert_eq!(map.len(), 200);
The Bathroom Model introduces a novel approach to hash table probing that outperforms traditional methods:
Dynamic Step Size Adjustment: Unlike fixed-step probing methods (linear, quadratic), the step size dynamically changes based on what we observe during probing:
Occupancy-Based Decisions: The algorithm tracks consecutive occupied slots and adjusts its strategy based on observed density, similar to how people might skip a crowded section of bathroom stalls.
Tombstone Optimization: Deleted slots (tombstones) are tracked and reused efficiently during insertion.
The name "Bathroom Model" comes from the real-world analogy of finding an empty bathroom stall:
This intuitive human behavior, when formalized and applied to hash table probing, results in significantly improved performance.
This approach overcomes the "coupon collector" bottleneck that limits traditional uniform probing, which requires Ω(log δ⁻¹) probes on average. The Bathroom Model achieves:
These bounds are optimal for hash tables that do not reorder elements.
Both implementations offer configuration options to tune performance:
// For ElasticHashMap
let mut map = ElasticHashMap::new();
map.set_load_factor_threshold(80); // Set maximum load factor to 80%
map.set_occupancy_threshold(3); // Set consecutive occupancy threshold to 3
map.set_step_size_range(2, 128); // Configure min and max step sizes
// For ConcurrentElasticMap
let map = ConcurrentElasticMap::new();
map.set_load_factor_threshold(0.8); // Set maximum load factor to 80%
map.set_occupancy_threshold(3); // Set consecutive occupancy threshold to 3
map.set_step_size_range(2, 128); // Configure min and max step sizes
Tuning these parameters can significantly impact performance based on your specific workload:
Contributions are welcome! Please feel free to submit a Pull Request.
Licensed under either of Apache License, Version 2.0 or MIT license at your option.