Packages
reckon_db
5.5.3
5.11.0
5.10.4
5.10.3
5.10.1
5.10.0
5.9.1
5.9.0
5.8.3
5.8.2
5.8.1
5.8.0
5.7.0
5.6.1
5.6.0
5.5.5
5.5.4
5.5.3
5.5.2
5.5.1
5.5.0
5.4.0
5.2.2
5.2.1
5.2.0
5.1.0
5.0.0
4.0.0
3.1.2
3.1.1
3.0.0
2.3.7
2.3.6
2.3.5
2.3.4
2.3.3
2.3.2
2.3.1
2.3.0
2.2.2
2.2.0
2.1.4
2.1.3
2.1.2
2.1.1
2.1.0
2.0.0
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.3
1.0.2
1.0.1
1.0.0
BEAM-native Event Store built on Khepri/Ra with Raft consensus. Event sourcing, persistent subscriptions, snapshots, and automatic cluster formation via UDP multicast discovery. Ships embedded Rust NIFs for 3-15x acceleration of crypto, hashing, compression, aggregation, filter matching, and grap...
Current section
Files
Jump to
Current section
Files
native/reckon_db_hash_nif/src/lib.rs
//! NIF optimizations for reckon-db hashing operations.
//!
//! This module provides high-performance hash implementations:
//! - xxHash64: Extremely fast 64-bit hash
//! - xxHash3: Even faster, modern 64-bit hash
//! - Partition hash: For consistent stream/subscription routing
//!
//! These NIFs are optional - the Erlang wrapper falls back to pure Erlang
//! implementations when the NIF is not available (community edition).
use rustler::{Binary, NifResult};
use xxhash_rust::xxh3::xxh3_64;
use xxhash_rust::xxh64::xxh64;
// ============================================================================
// xxHash64 - Fast 64-bit hash
// ============================================================================
/// Compute xxHash64 of binary data.
///
/// xxHash64 is an extremely fast non-cryptographic hash function.
/// Ideal for hash tables, checksums, and data fingerprinting.
///
/// Arguments:
/// - data: The data to hash (binary)
///
/// Returns:
/// - 64-bit hash value as unsigned integer
#[rustler::nif]
fn nif_xxhash64(data: Binary) -> u64 {
xxh64(data.as_slice(), 0)
}
/// Compute xxHash64 with a seed.
///
/// Arguments:
/// - data: The data to hash (binary)
/// - seed: Seed value for the hash
///
/// Returns:
/// - 64-bit hash value as unsigned integer
#[rustler::nif]
fn nif_xxhash64_seed(data: Binary, seed: u64) -> u64 {
xxh64(data.as_slice(), seed)
}
// ============================================================================
// xxHash3 - Modern, faster 64-bit hash
// ============================================================================
/// Compute xxHash3 (64-bit) of binary data.
///
/// xxHash3 is the latest generation of xxHash, even faster than xxHash64
/// especially for small inputs. Uses SIMD when available.
///
/// Arguments:
/// - data: The data to hash (binary)
///
/// Returns:
/// - 64-bit hash value as unsigned integer
#[rustler::nif]
fn nif_xxhash3(data: Binary) -> u64 {
xxh3_64(data.as_slice())
}
// ============================================================================
// Partition Hashing - For consistent routing
// ============================================================================
/// Hash data and map to a partition number.
///
/// This is used for consistent routing of streams/subscriptions to workers.
/// Uses xxHash3 for speed, then modulo for partition mapping.
///
/// Arguments:
/// - data: The data to hash (binary)
/// - partitions: Number of partitions (must be > 0)
///
/// Returns:
/// - Partition number (0 to partitions-1)
#[rustler::nif]
fn nif_partition_hash(data: Binary, partitions: u32) -> NifResult<u32> {
if partitions == 0 {
return Err(rustler::Error::Term(Box::new("partitions must be > 0")));
}
let hash = xxh3_64(data.as_slice());
Ok((hash % partitions as u64) as u32)
}
/// Hash a tuple of {StoreId, StreamId} for stream routing.
///
/// Optimized for the common case of routing streams to workers.
/// Combines both IDs efficiently before hashing.
///
/// Arguments:
/// - store_id: The store identifier (binary)
/// - stream_id: The stream identifier (binary)
/// - partitions: Number of partitions
///
/// Returns:
/// - Partition number (0 to partitions-1)
#[rustler::nif]
fn nif_stream_partition(store_id: Binary, stream_id: Binary, partitions: u32) -> NifResult<u32> {
if partitions == 0 {
return Err(rustler::Error::Term(Box::new("partitions must be > 0")));
}
// Combine store_id and stream_id with a separator
let mut combined = Vec::with_capacity(store_id.len() + stream_id.len() + 1);
combined.extend_from_slice(store_id.as_slice());
combined.push(0); // Separator byte
combined.extend_from_slice(stream_id.as_slice());
let hash = xxh3_64(&combined);
Ok((hash % partitions as u64) as u32)
}
// ============================================================================
// Batch Hashing - For bulk operations
// ============================================================================
/// Hash multiple binaries and return their partition assignments.
///
/// More efficient than calling partition_hash repeatedly due to
/// reduced NIF call overhead.
///
/// Arguments:
/// - items: List of binaries to hash
/// - partitions: Number of partitions
///
/// Returns:
/// - List of partition numbers in same order as input
#[rustler::nif]
fn nif_partition_hash_batch(items: Vec<Binary>, partitions: u32) -> NifResult<Vec<u32>> {
if partitions == 0 {
return Err(rustler::Error::Term(Box::new("partitions must be > 0")));
}
let results: Vec<u32> = items
.iter()
.map(|item| {
let hash = xxh3_64(item.as_slice());
(hash % partitions as u64) as u32
})
.collect();
Ok(results)
}
// ============================================================================
// FNV Hash - Fast for small keys
// ============================================================================
/// Compute FNV-1a hash of binary data.
///
/// FNV-1a is particularly fast for small keys (< 32 bytes).
/// Good for hash tables with small keys like atoms or short strings.
///
/// Arguments:
/// - data: The data to hash (binary)
///
/// Returns:
/// - 64-bit hash value
#[rustler::nif]
fn nif_fnv1a(data: Binary) -> u64 {
use std::hash::Hasher;
let mut hasher = fnv::FnvHasher::default();
hasher.write(data.as_slice());
hasher.finish()
}
// ============================================================================
// Comparison with phash2
// ============================================================================
/// Hash data similar to erlang:phash2/2 but faster.
///
/// This provides a drop-in replacement for phash2 with better performance.
/// Uses xxHash3 internally but maps to the same range as phash2.
///
/// Arguments:
/// - data: The data to hash (binary)
/// - range: Maximum value (exclusive), like phash2's second argument
///
/// Returns:
/// - Hash value in range [0, range)
#[rustler::nif]
fn nif_fast_phash(data: Binary, range: u32) -> NifResult<u32> {
if range == 0 {
return Err(rustler::Error::Term(Box::new("range must be > 0")));
}
let hash = xxh3_64(data.as_slice());
Ok((hash % range as u64) as u32)
}
rustler::init!("reckon_db_hash_nif");