Loading page…
Rust walkthroughs
Loading page…
The dashmap crate provides a blazingly fast concurrent HashMap for Rust. It uses sharding to achieve high performance under concurrent access, avoiding the bottleneck of a single lock. Instead of one lock for the entire map, DashMap divides the data into multiple shards, each with its own lock. This allows multiple threads to access different parts of the map simultaneously. It implements the standard HashMap API with additional methods for atomic operations like entry, get_or_insert, and compute_if_absent. DashMap is ideal for high-throughput concurrent applications like web servers, caches, and real-time data processing.
Key concepts:
# Cargo.toml
[dependencies]
dashmap = "5"use dashmap::DashMap;
use std::sync::Arc;
use std::thread;
fn main() {
// Create a concurrent HashMap
let map = Arc::new(DashMap::new());
// Spawn multiple threads
let handles: Vec<_> = (0..4)
.map(|i| {
let map = Arc::clone(&map);
thread::spawn(move || {
// Each thread can safely insert
map.insert(i, format!("value-{}", i));
// And read
if let Some(value) = map.get(&i) {
println!("Thread {} read: {}", i, value.value());
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
println!("Final map size: {}", map.len());
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
// Insert
map.insert("apple", 1);
map.insert("banana", 2);
map.insert("cherry", 3);
println!("Size: {}", map.len());
// Get
if let Some(value) = map.get(&"apple") {
println!("apple: {}", value.value());
}
// Contains
println!("Contains 'banana': {}", map.contains_key(&"banana"));
// Remove
let removed = map.remove(&"banana");
println!("Removed: {:?}", removed);
println!("Size after removal: {}", map.len());
// Clear
map.clear();
println!("Size after clear: {}", map.len());
}use dashmap::DashMap;
fn main() {
// Create with initial capacity
let map: DashMap<i32, String> = DashMap::with_capacity(100);
// Create with shard amount (must be power of 2)
let map: DashMap<i32, String> = DashMap::with_shard_amount(16);
// Create with both
let map: DashMap<i32, String> = DashMap::with_capacity_and_shard_amount(1000, 32);
println!("Map created with {} shards", map.shards().len());
}use dashmap::DashMap;
fn main() {
let map = DashMap::new();
map.insert("key1", "value1");
map.insert("key2", "value2");
// Get returns a reference guard
if let Some(refr) = map.get(&"key1") {
println!("Got key1: {}", refr.value());
println!("Key: {}, Value: {}", refr.key(), refr.value());
}
// Get key-value pair
if let Some((key, value)) = map.get_key_value(&"key2") {
println!("Key: {}, Value: {}", key, value);
}
// Try get (returns Option<Result>)
match map.try_get(&"key1") {
Some(result) => {
match result {
Ok(guard) => println!("Got: {}", guard.value()),
Err(_) => println!("Would block"),
}
}
None => println!("Key not found"),
}
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
map.insert("counter", 0);
// Get mutable reference
if let Some(mut value) = map.get_mut(&"counter") {
*value += 1;
}
println!("Counter: {:?}", map.get(&"counter"));
// Try get mutable
match map.try_get_mut(&"counter") {
Some(result) => {
match result {
Ok(mut guard) => *guard += 10,
Err(_) => println!("Would block"),
}
}
None => println!("Key not found"),
}
println!("Counter: {:?}", map.get(&"counter"));
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
// or_insert - insert if missing
map.entry("apple").or_insert(5);
println!("apple: {:?}", map.get(&"apple"));
// Value already exists, won't insert
map.entry("apple").or_insert(10);
println!("apple (unchanged): {:?}", map.get(&"apple"));
// or_insert_with - lazy insertion
map.entry("banana").or_insert_with(|| {
println!("Computing value for banana...");
42
});
println!("banana: {:?}", map.get(&"banana"));
// and_modify - modify existing value
map.entry("apple").and_modify(|v| *v *= 2);
println!("apple (doubled): {:?}", map.get(&"apple"));
// Complex entry operations
map.entry("cherry")
.or_insert(0)
.and_modify(|v| *v += 1);
println!("cherry: {:?}", map.get(&"cherry"));
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
// add - increment existing value
map.insert("counter", 10);
let prev = map.add("counter", 5);
println!("Previous value: {:?}", prev);
println!("New value: {:?}", map.get(&"counter"));
// add with missing key
let prev = map.add("new_key", 100);
println!("Previous for new key: {:?}", prev);
println!("New key value: {:?}", map.get(&"new_key"));
// compute_if_absent
let value = map.compute_if_absent("absent_key", |_| 42);
println!("Computed: {}", value);
// compute_if_present
map.compute_if_present("counter", |_, v| Some(v + 100));
println!("Counter updated: {:?}", map.get(&"counter"));
}use dashmap::DashMap;
fn main() {
let map: DashMap<i32, &str> = DashMap::new();
for i in 0..5 {
map.insert(i, &format!("value-{}", i));
}
// Immutable iteration
println!("Iterating:");
for entry in map.iter() {
println!(" {} -> {}", entry.key(), entry.value());
}
// Mutable iteration
println!("\nModifying values:");
for mut entry in map.iter_mut() {
*entry.value_mut() = &format!("modified-{}", entry.key());
}
// Check modified values
for entry in map.iter() {
println!(" {} -> {}", entry.key(), entry.value());
}
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
// Iterate over keys
println!("Keys:");
for key in map.iter().map(|e| e.key().clone()) {
println!(" {}", key);
}
// Iterate over values
println!("\nValues:");
for value in map.iter().map(|e| *e.value()) {
println!(" {}", value);
}
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
// Remove by key
let removed = map.remove(&"b");
println!("Removed: {:?}", removed);
// Remove if condition matches
map.remove_if("c", |_k, v| *v > 5);
println!("After remove_if (c not removed): {:?}", map.get(&"c"));
map.remove_if("c", |_k, v| *v == 3);
println!("After remove_if (c removed): {:?}", map.get(&"c"));
// Remove entry
let entry = map.entry("a");
entry.remove();
println!("After entry.remove: {:?}", map.get(&"a"));
}use dashmap::DashMap;
use std::sync::Arc;
use std::thread;
fn main() {
let counters = Arc::new(DashMap::new());
let handles: Vec<_> = (0..100)
.map(|i| {
let counters = Arc::clone(&counters);
thread::spawn(move || {
// Each thread increments multiple counters
for j in 0..10 {
let key = format!("counter-{}", j % 5);
counters.entry(key).and_modify(|v| *v += 1).or_insert(1);
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
// Print final counts
println!("Final counts:");
for entry in counters.iter() {
println!(" {} -> {}", entry.key(), entry.value());
}
// Verify total
let total: i32 = counters.iter().map(|e| *e.value()).sum();
println!("Total: {}", total);
}use dashmap::DashMap;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
struct CacheEntry {
value: String,
created_at: Instant,
ttl: Duration,
}
impl CacheEntry {
fn new(value: String, ttl: Duration) -> Self {
Self {
value,
created_at: Instant::now(),
ttl,
}
}
fn is_valid(&self) -> bool {
Instant::now().duration_since(self.created_at) < self.ttl
}
}
struct Cache {
data: DashMap<String, CacheEntry>,
default_ttl: Duration,
}
impl Cache {
fn new(default_ttl: Duration) -> Self {
Self {
data: DashMap::new(),
default_ttl,
}
}
fn get(&self, key: &str) -> Option<String> {
if let Some(entry) = self.data.get(key) {
if entry.value().is_valid() {
return Some(entry.value().value.clone());
}
}
None
}
fn set(&self, key: String, value: String) {
self.set_with_ttl(key, value, self.default_ttl);
}
fn set_with_ttl(&self, key: String, value: String, ttl: Duration) {
self.data.insert(key, CacheEntry::new(value, ttl));
}
fn invalidate(&self, key: &str) {
self.data.remove(key);
}
fn cleanup(&self) {
self.data.retain(|_, entry| entry.is_valid());
}
}
fn expensive_computation(key: &str) -> String {
thread::sleep(Duration::from_millis(100));
format!("result-for-{}", key)
}
fn main() {
let cache = Arc::new(Cache::new(Duration::from_secs(60)));
let handles: Vec<_> = (0..5)
.map(|i| {
let cache = Arc::clone(&cache);
thread::spawn(move || {
let key = format!("key-{}", i % 3);
// Try cache first
if let Some(value) = cache.get(&key) {
println!("Thread {} got cached: {}", i, value);
return;
}
// Compute and cache
let value = expensive_computation(&key);
cache.set(key.clone(), value.clone());
println!("Thread {} computed: {}", i, value);
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}use dashmap::DashMap;
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
struct RateTracker {
requests: DashMap<String, Vec<Instant>>,
max_requests: usize,
window: Duration,
}
impl RateTracker {
fn new(max_requests: usize, window: Duration) -> Self {
Self {
requests: DashMap::new(),
max_requests,
window,
}
}
fn is_allowed(&self, key: &str) -> bool {
let now = Instant::now();
let cutoff = now - self.window;
// Get or create entry
let mut entry = self.requests.entry(key.to_string()).or_insert_with(Vec::new);
// Remove old requests
entry.retain(|t| *t > cutoff);
// Check if under limit
if entry.len() < self.max_requests {
entry.push(now);
true
} else {
false
}
}
fn remaining(&self, key: &str) -> usize {
let now = Instant::now();
let cutoff = now - self.window;
if let Some(mut entry) = self.requests.get_mut(key) {
entry.retain(|t| *t > cutoff);
self.max_requests.saturating_sub(entry.len())
} else {
self.max_requests
}
}
}
fn main() {
let tracker = Arc::new(RateTracker::new(5, Duration::from_secs(60)));
let handles: Vec<_> = (0..10)
.map(|i| {
let tracker = Arc::clone(&tracker);
thread::spawn(move || {
let user = "user_123";
if tracker.is_allowed(user) {
println!("Request {} allowed (remaining: {})", i, tracker.remaining(user));
} else {
println!("Request {} rate limited!", i);
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}use dashmap::DashMap;
use std::sync::Arc;
use std::collections::HashSet;
struct PubSub {
// Map from topic to set of subscribers
subscriptions: DashMap<String, HashSet<String>>,
// Map from subscriber to their messages
messages: DashMap<String, Vec<String>>,
}
impl PubSub {
fn new() -> Self {
Self {
subscriptions: DashMap::new(),
messages: DashMap::new(),
}
}
fn subscribe(&self, topic: &str, subscriber: &str) {
self.subscriptions
.entry(topic.to_string())
.or_insert_with(HashSet::new)
.insert(subscriber.to_string());
println!("{} subscribed to {}", subscriber, topic);
}
fn unsubscribe(&self, topic: &str, subscriber: &str) {
if let Some(mut subs) = self.subscriptions.get_mut(topic) {
subs.remove(subscriber);
}
}
fn publish(&self, topic: &str, message: &str) {
if let Some(subs) = self.subscriptions.get(topic) {
for subscriber in subs.iter() {
self.messages
.entry(subscriber.clone())
.or_insert_with(Vec::new)
.push(format!("[{}] {}", topic, message));
}
}
}
fn get_messages(&self, subscriber: &str) -> Vec<String> {
if let Some(mut msgs) = self.messages.get_mut(subscriber) {
std::mem::take(&mut *msgs)
} else {
Vec::new()
}
}
}
fn main() {
let pubsub = Arc::new(PubSub::new());
// Subscribe
pubsub.subscribe("news", "alice");
pubsub.subscribe("news", "bob");
pubsub.subscribe("sports", "bob");
// Publish
pubsub.publish("news", "Breaking: Rust 2.0 released!");
pubsub.publish("sports", "Team wins championship!");
// Get messages
println!("\nAlice's messages: {:?}", pubsub.get_messages("alice"));
println!("Bob's messages: {:?}", pubsub.get_messages("bob"));
}use dashmap::DashMap;
fn main() {
let map: DashMap<i32, i32> = DashMap::new();
for i in 0..20 {
map.insert(i, i * i);
}
println!("Before retain: {}", map.len());
// Retain only entries where key is even and value > 100
map.retain(|k, v| k % 2 == 0 && *v > 100);
println!("After retain: {}", map.len());
for entry in map.iter() {
println!(" {} -> {}", entry.key(), entry.value());
}
}use dashmap::DashMap;
fn main() {
let map: DashMap<i32, String> = DashMap::with_shard_amount(16);
println!("Number of shards: {}", map.shards().len());
// Check shard capacity
for (i, shard) in map.shards().iter().enumerate() {
// Each shard is a RwLock<HashMap>
println!("Shard {} capacity: {}", i, shard.read().len());
}
// Insert some data
for i in 0..100 {
map.insert(i, format!("value-{}", i));
}
// Check distribution
println!("\nAfter inserting 100 items:");
for (i, shard) in map.shards().iter().enumerate() {
println!("Shard {} entries: {}", i, shard.read().len());
}
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
map.insert("counter", 0);
// Simulated compare-and-swap
fn cas(map: &DashMap<&str, i32>, key: &str, expected: i32, new: i32) -> bool {
if let Some(mut value) = map.get_mut(key) {
if *value == expected {
*value = new;
return true;
}
}
false
}
// Try to update from 0 to 10
println!("CAS 0->10: {}", cas(&map, "counter", 0, 10));
println!("Counter: {:?}", map.get("counter"));
// Try wrong expected value
println!("CAS 0->20: {}", cas(&map, "counter", 0, 20));
println!("Counter: {:?}", map.get("counter"));
// Correct expected value
println!("CAS 10->20: {}", cas(&map, "counter", 10, 20));
println!("Counter: {:?}", map.get("counter"));
}use dashmap::DashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
#[derive(Clone)]
struct Session {
user_id: String,
created_at: Instant,
expires_at: Instant,
data: std::collections::HashMap<String, String>,
}
impl Session {
fn new(user_id: String, ttl: Duration) -> Self {
let now = Instant::now();
Self {
user_id,
created_at: now,
expires_at: now + ttl,
data: std::collections::HashMap::new(),
}
}
fn is_valid(&self) -> bool {
Instant::now() < self.expires_at
}
}
struct SessionStore {
sessions: DashMap<String, Session>,
default_ttl: Duration,
}
impl SessionStore {
fn new(default_ttl: Duration) -> Self {
Self {
sessions: DashMap::new(),
default_ttl,
}
}
fn create_session(&self, user_id: String) -> String {
let session_id = format!("session-{}-{}", user_id, rand_id());
let session = Session::new(user_id, self.default_ttl);
self.sessions.insert(session_id.clone(), session);
session_id
}
fn get_session(&self, session_id: &str) -> Option<Session> {
self.sessions.get(session_id).and_then(|s| {
if s.value().is_valid() {
Some(s.value().clone())
} else {
None
}
})
}
fn set_data(&self, session_id: &str, key: String, value: String) -> bool {
if let Some(mut session) = self.sessions.get_mut(session_id) {
session.data.insert(key, value);
true
} else {
false
}
}
fn get_data(&self, session_id: &str, key: &str) -> Option<String> {
self.sessions.get(session_id).and_then(|s| {
s.value().data.get(key).cloned()
})
}
fn destroy_session(&self, session_id: &str) {
self.sessions.remove(session_id);
}
fn cleanup_expired(&self) {
self.sessions.retain(|_, session| session.is_valid());
}
}
fn rand_id() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos() as u64
}
fn main() {
let store = SessionStore::new(Duration::from_secs(3600));
// Create session
let session_id = store.create_session("user_123".to_string());
println!("Created session: {}", session_id);
// Set session data
store.set_data(&session_id, "theme".to_string(), "dark".to_string());
store.set_data(&session_id, "lang".to_string(), "en".to_string());
// Get session data
if let Some(session) = store.get_session(&session_id) {
println!("User: {}", session.user_id);
println!("Theme: {:?}", store.get_data(&session_id, "theme"));
println!("Lang: {:?}", store.get_data(&session_id, "lang"));
}
// Destroy session
store.destroy_session(&session_id);
println!("Session destroyed");
}use dashmap::DashMap;
fn main() {
let map: DashMap<&str, i32> = DashMap::new();
map.insert("a", 1);
map.insert("b", 2);
map.insert("c", 3);
// Length
println!("Length: {}", map.len());
// Is empty
println!("Is empty: {}", map.is_empty());
// Capacity
println!("Capacity: {}", map.capacity());
// Contains key
println!("Contains 'a': {}", map.contains_key(&"a"));
println!("Contains 'x': {}", map.contains_key(&"x"));
// Verify all entries
let mut count = 0;
for _ in map.iter() {
count += 1;
}
println!("Verified {} entries via iteration", count);
}use dashmap::DashMap;
fn main() {
let map1: DashMap<i32, &str> = DashMap::new();
map1.insert(1, "one");
map1.insert(2, "two");
// Clone
let map2 = map1.clone();
println!("Cloned map:");
for entry in map2.iter() {
println!(" {} -> {}", entry.key(), entry.value());
}
// Extend
let more = vec![(3, "three"), (4, "four")];
map1.extend(more);
println!("\nExtended map:");
for entry in map1.iter() {
println!(" {} -> {}", entry.key(), entry.value());
}
}use dashmap::DashMap;
use std::sync::Arc;
use std::thread;
#[derive(Clone)]
struct Metric {
name: String,
value: f64,
count: u64,
}
impl Metric {
fn new(name: String) -> Self {
Self { name, value: 0.0, count: 0 }
}
fn record(&mut self, value: f64) {
// Running average
self.count += 1;
self.value += (value - self.value) / self.count as f64;
}
}
struct MetricsCollector {
metrics: DashMap<String, Metric>,
}
impl MetricsCollector {
fn new() -> Self {
Self { metrics: DashMap::new() }
}
fn record(&self, name: &str, value: f64) {
self.metrics
.entry(name.to_string())
.and_modify(|m| m.record(value))
.or_insert_with(|| {
let mut m = Metric::new(name.to_string());
m.record(value);
m
});
}
fn get(&self, name: &str) -> Option<Metric> {
self.metrics.get(name).map(|m| m.value().clone())
}
fn all_metrics(&self) -> Vec<Metric> {
self.metrics.iter().map(|e| e.value().clone()).collect()
}
fn summary(&self) {
println!("Metrics Summary:");
for entry in self.metrics.iter() {
let m = entry.value();
println!(" {}: avg={:.2} (n={})", m.name, m.value, m.count);
}
}
}
fn main() {
let collector = Arc::new(MetricsCollector::new());
let handles: Vec<_> = (0..10)
.map(|i| {
let collector = Arc::clone(&collector);
thread::spawn(move || {
for j in 0..100 {
collector.record("response_time", (i * 10 + j) as f64);
collector.record("request_size", 100.0 + i as f64);
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
collector.summary();
}DashMap::new() creates a concurrent HashMapmap.insert(key, value) inserts a key-value pairmap.get(&key) returns a reference guard with key() and value() methodsmap.get_mut(&key) returns a mutable reference guardmap.entry(key) provides the entry API for conditional operationsmap.iter() and map.iter_mut() for iterationmap.retain(predicate) filters entries in placemap.remove(&key) removes an entryArc<DashMap> for sharing across threads