mpchash 2.0.10

A space-efficient (no need for vnodes) multi-probe consistent hashing algorithm
Documentation
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is a Rust implementation of Multi-probe consistent hashing, a space-efficient variant of consistent hashing that eliminates the need for virtual nodes. The library provides `O(n)` space complexity while achieving balanced key distribution with a peak-to-average load ratio of `1 + ε` using just `1 + 1/ε` lookups per key. It uses a lock-free skip list for thread-safe operations.

## Development Commands

### Building and Testing
```bash
# Build the library
cargo build

# Build with release optimizations
cargo build --release

# Run all tests (unit tests in src/ and integration tests in tests/)
cargo test

# Run a specific test
cargo test test_name

# Run tests with output
cargo test -- --nocapture

# Run only integration tests
cargo test --test hashring
cargo test --test partitioner
```

### Code Quality
```bash
# Run clippy for linting (project forbids unsafe code)
cargo clippy -- -D warnings

# Format code (uses custom rustfmt.toml configuration)
cargo fmt

# Check formatting without applying changes
cargo fmt -- --check

# Generate and open documentation
cargo doc --open
```

### Publishing
```bash
# Check if package is ready to publish
cargo publish --dry-run

# Publish to crates.io
cargo publish
```

## Architecture

### Core Components

**HashRing** (`src/lib.rs`): The main consistent hashing data structure. Uses `crossbeam_skiplist::SkipMap` for lock-free, thread-safe node management. The ring assigns nodes to positions and routes keys to their owning nodes through multi-probe hashing.

**Partitioner** (`src/partitioner.rs`): Responsible for mapping hashable objects to ring positions. The default implementation (`Xxh3Partitioner`) uses XXH3 hashing with double-hashing for probe generation. The `Partitioner` trait allows custom hashing strategies.

**RingToken** (`src/token.rs`): A wrapper around skiplist entries representing a node's position on the ring. Provides convenient access to both the position (u64) and the node itself. Tokens are returned when querying the ring for key ownership.

**KeyRange** (`src/range.rs`): Represents half-open intervals `[start..end)` on the ring. Handles wraparound semantics when `start >= end`, representing the union of `[start..MAX]` and `[0..end)`. Used for determining which key ranges a node owns during rebalancing operations.

**HashRingIter** (`src/iter.rs`): Iterator implementation for traversing the ring in both clockwise and counter-clockwise directions with wraparound support.

### Multi-probe Hashing Algorithm

Unlike traditional consistent hashing, this implementation doesn't use virtual nodes. Instead:

1. Nodes are assigned single positions on the ring based on their hash
2. For each key, multiple probe positions are generated using double-hashing
3. The probe with minimal distance to any node wins
4. The key is assigned to the first node clockwise from that winning probe

This approach balances the load without requiring extra memory for virtual nodes. The default probe count is 23 (`DEFAULT_PROBE_COUNT`).

### Thread Safety

The ring uses `Arc<SkipMap<RingPosition, N>>` internally, allowing it to be cloned and shared across threads safely. All operations (add, remove, queries) are lock-free and thread-safe.

## Code Constraints

- **No unsafe code**: The crate uses `#![forbid(unsafe_code)]` to ensure memory safety
- **RingNode trait**: Node types must implement `Hash + Send + 'static`
- **Key types**: Any type implementing `Hash` can be used as a key for lookups
- **RingPosition**: Type alias for `u64` representing positions on the ring

## Testing Strategy

- Unit tests are embedded in source files using `#[cfg(test)]` modules
- Integration tests in `tests/` verify end-to-end functionality
- Tests use random node generation to ensure robustness
- Key test scenarios:
  - Basic add/remove operations
  - Replica selection with replication factors
  - Ring wraparound behavior
  - Key range calculations for rebalancing
  - Token traversal in both directions

## rustfmt Configuration

The project uses custom rustfmt settings in `rustfmt.toml`:
- Requires unstable features (`unstable_features = true`)
- Enforces import grouping and ordering
- Normalizes comments and doc attributes
- Uses field init shorthand and try operator shorthand