fetch_ml/native_rust/queue_index/benches/queue_benchmark.rs
Jeremie Fraeys 6949287fb3
feat(native_rust): implement BLAKE3 dataset_hash and priority queue_index
Implements two production-ready Rust native libraries:

## dataset_hash (BLAKE3-based hashing)
- FFI exports: ds_hash_file, ds_hash_directory_batch, ds_hash_directory_combined
- BLAKE3 hashing for files and directory trees
- Hidden file filtering (respects .hidden and _prefix files)
- Prometheus-compatible metrics export
- Comprehensive integration tests (12 tests)
- Benchmarks: hash_file_1kb (~14µs), hash_file_1mb (~610µs), dir_100files (~1.6ms)

## queue_index (priority queue)
- FFI exports: 25+ functions matching C++ API
  - Lifecycle: qi_open, qi_close
  - Task ops: add_tasks, update_tasks, remove_tasks, get_task_by_id
  - Queue ops: get_next_batch, peek_next, mark_completed
  - Priority: get_next_priority_task, peek_priority_task
  - Query: get_all_tasks, get_tasks_by_status, get_task_count
  - Retry/DLQ: retry_task, move_to_dlq
  - Lease: renew_lease, release_lease
  - Maintenance: rebuild_index, compact_index
- BinaryHeap-based priority queue with correct Ord (max-heap)
- Memory-mapped storage with safe Rust wrappers
- Panic-safe FFI boundaries using catch_unwind
- Comprehensive integration tests (7 tests, 1 ignored for persistence)
- Benchmarks: add_100 (~60µs), get_10 (~24ns), priority (~5µs)

## Architecture
- Cargo workspace with shared common crate
- Criterion benchmarks for both crates
- Rust 1.85.0 toolchain pinned
- Zero compiler warnings
- All 19 tests passing

Compare: make compare-benchmarks (Rust/Go/C++ comparison)
2026-03-23 12:52:13 -04:00

71 lines
2.3 KiB
Rust

//! Benchmarks for queue_index
//!
//! Compares Rust implementation against theoretical Go/C++ performance
use criterion::{black_box, criterion_group, criterion_main, Criterion, BatchSize};
use queue_index::{QueueIndex, Task};
use tempfile::TempDir;
fn bench_add_tasks(c: &mut Criterion) {
c.bench_function("rust_queue_add_100", |b| {
b.iter_batched(
|| {
let temp = TempDir::new().unwrap();
QueueIndex::open(temp.path()).unwrap()
},
|mut index| {
let tasks: Vec<Task> = (0..100)
.map(|i| Task::new(&format!("task-{}", i), "bench-job"))
.collect();
black_box(index.add_tasks(&tasks).unwrap());
},
BatchSize::SmallInput,
);
});
}
fn bench_get_next_batch(c: &mut Criterion) {
c.bench_function("rust_queue_get_10", |b| {
let temp = TempDir::new().unwrap();
let mut index = QueueIndex::open(temp.path()).unwrap();
// Pre-populate with 1000 tasks
let tasks: Vec<Task> = (0..1000)
.map(|i| Task::new(&format!("task-{}", i), "bench-job"))
.collect();
index.add_tasks(&tasks).unwrap();
b.iter(|| {
black_box(index.get_next_batch(10).unwrap());
});
});
}
fn bench_priority_ordering(c: &mut Criterion) {
c.bench_function("rust_queue_priority", |b| {
b.iter_batched(
|| {
let temp = TempDir::new().unwrap();
let mut index = QueueIndex::open(temp.path()).unwrap();
// Add tasks with varying priorities
let mut low = Task::new("low", "job");
low.priority = 10;
let mut high = Task::new("high", "job");
high.priority = 100;
let mut medium = Task::new("medium", "job");
medium.priority = 50;
index.add_tasks(&[low, high, medium]).unwrap();
index
},
|mut index| {
black_box(index.get_next_batch(3).unwrap());
},
BatchSize::SmallInput,
);
});
}
criterion_group!(benches, bench_add_tasks, bench_get_next_batch, bench_priority_ordering);
criterion_main!(benches);