Skip to content

Commit be28b68

Browse files
konardclaude
andcommitted
Split benched.rs into separate Neo4j and Doublets modules
Addresses user feedback requesting clear separation of Neo4j and Doublets logic. The benched.rs file contained mixed implementations for both databases. Changes: - Removed rust/src/benched.rs (contained both Neo4j and Doublets impls) - Added rust/src/benched/mod.rs with common Benched trait - Added rust/src/benched/doublets_benched.rs with Doublets implementations - Added rust/src/benched/neo4j_benched.rs with Neo4j implementations This provides complete separation between Neo4j and Doublets code across all source files for easier side-by-side comparison. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent ea7fe0d commit be28b68

File tree

4 files changed

+250
-112
lines changed

4 files changed

+250
-112
lines changed

rust/src/benched.rs

Lines changed: 0 additions & 112 deletions
This file was deleted.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//! # Doublets Benched Implementations
2+
//!
3+
//! This module contains the [`Benched`] trait implementations for all Doublets
4+
//! storage backends.
5+
//!
6+
//! ## Storage Backends
7+
//!
8+
//! | Type | Storage | Description |
9+
//! |------------------------------|----------------|----------------------------------|
10+
//! | `unit::Store` + `FileMapped` | Non-volatile | Memory-mapped file storage |
11+
//! | `unit::Store` + `Alloc` | Volatile | In-memory storage |
12+
//! | `split::Store` + `FileMapped`| Non-volatile | Split data/index file storage |
13+
//! | `split::Store` + `Alloc` | Volatile | Split data/index in-memory |
14+
//!
15+
//! ## Implementation Details
16+
//!
17+
//! All Doublets implementations clean up by calling `delete_all()` in `unfork()`,
18+
//! which removes all links from the storage for the next benchmark iteration.
19+
20+
use std::alloc::Global;
21+
22+
use doublets::{
23+
data::LinkType,
24+
mem::{Alloc, FileMapped},
25+
split::{self, DataPart, IndexPart},
26+
unit::{self, LinkPart},
27+
Doublets,
28+
};
29+
30+
use super::Benched;
31+
use crate::map_file;
32+
33+
/// Doublets United (unit) store with non-volatile (file-mapped) storage.
34+
///
35+
/// ## Setup
36+
/// ```rust,ignore
37+
/// let store = unit::Store::<usize, FileMapped<LinkPart<_>>>::setup("united.links")?;
38+
/// ```
39+
///
40+
/// ## Cleanup
41+
/// Calls `delete_all()` to remove all links between iterations.
42+
impl<T: LinkType> Benched for unit::Store<T, FileMapped<LinkPart<T>>> {
43+
type Builder<'a> = &'a str;
44+
45+
fn setup(builder: Self::Builder<'_>) -> crate::Result<Self> {
46+
Self::new(map_file(builder)?).map_err(Into::into)
47+
}
48+
49+
unsafe fn unfork(&mut self) {
50+
let _ = self.delete_all();
51+
}
52+
}
53+
54+
/// Doublets United (unit) store with volatile (in-memory) storage.
55+
///
56+
/// ## Setup
57+
/// ```rust,ignore
58+
/// let store = unit::Store::<usize, Alloc<LinkPart<_>, Global>>::setup(())?;
59+
/// ```
60+
///
61+
/// ## Cleanup
62+
/// Calls `delete_all()` to remove all links between iterations.
63+
impl<T: LinkType> Benched for unit::Store<T, Alloc<LinkPart<T>, Global>> {
64+
type Builder<'a> = ();
65+
66+
fn setup(_: Self::Builder<'_>) -> crate::Result<Self> {
67+
Self::new(Alloc::new(Global)).map_err(Into::into)
68+
}
69+
70+
unsafe fn unfork(&mut self) {
71+
let _ = self.delete_all();
72+
}
73+
}
74+
75+
/// Doublets Split store with non-volatile (file-mapped) storage.
76+
///
77+
/// ## Setup
78+
/// ```rust,ignore
79+
/// let store = split::Store::<usize, FileMapped<_>, FileMapped<_>>::setup(
80+
/// ("split_index.links", "split_data.links")
81+
/// )?;
82+
/// ```
83+
///
84+
/// ## Cleanup
85+
/// Calls `delete_all()` to remove all links between iterations.
86+
impl<T: LinkType> Benched for split::Store<T, FileMapped<DataPart<T>>, FileMapped<IndexPart<T>>> {
87+
type Builder<'a> = (&'a str, &'a str);
88+
89+
fn setup((data, index): Self::Builder<'_>) -> crate::Result<Self> {
90+
Self::new(map_file(data)?, map_file(index)?).map_err(Into::into)
91+
}
92+
93+
unsafe fn unfork(&mut self) {
94+
let _ = self.delete_all();
95+
}
96+
}
97+
98+
/// Doublets Split store with volatile (in-memory) storage.
99+
///
100+
/// ## Setup
101+
/// ```rust,ignore
102+
/// let store = split::Store::<usize, Alloc<DataPart<_>, _>, Alloc<IndexPart<_>, _>>::setup(())?;
103+
/// ```
104+
///
105+
/// ## Cleanup
106+
/// Calls `delete_all()` to remove all links between iterations.
107+
impl<T: LinkType> Benched
108+
for split::Store<T, Alloc<DataPart<T>, Global>, Alloc<IndexPart<T>, Global>>
109+
{
110+
type Builder<'a> = ();
111+
112+
fn setup(_: Self::Builder<'_>) -> crate::Result<Self> {
113+
Self::new(Alloc::new(Global), Alloc::new(Global)).map_err(Into::into)
114+
}
115+
116+
unsafe fn unfork(&mut self) {
117+
let _ = self.delete_all();
118+
}
119+
}

rust/src/benched/mod.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//! # Benchmark Lifecycle Management
2+
//!
3+
//! This module defines the [`Benched`] trait that provides setup/teardown lifecycle
4+
//! for benchmark iterations. Both Neo4j and Doublets storage backends implement
5+
//! this trait to enable fair benchmarking.
6+
//!
7+
//! ## Module Structure
8+
//!
9+
//! The implementations are split into separate files for clear comparison:
10+
//!
11+
//! - **[`doublets_benched`]** - Doublets storage backend implementations
12+
//! - **[`neo4j_benched`]** - Neo4j storage backend implementations
13+
14+
mod doublets_benched;
15+
mod neo4j_benched;
16+
17+
use crate::Fork;
18+
19+
/// Trait for types that can be benchmarked.
20+
///
21+
/// Provides the setup/teardown lifecycle for benchmark iterations:
22+
/// - [`Benched::setup`] - Initialize the storage backend
23+
/// - [`Benched::fork`] - Create an isolated environment for a single iteration
24+
/// - [`Benched::unfork`] - Clean up after the iteration
25+
pub trait Benched: Sized {
26+
/// Builder parameter type for constructing this storage.
27+
type Builder<'params>;
28+
29+
/// Set up a new storage backend for benchmarking.
30+
fn setup<'a>(builder: Self::Builder<'a>) -> crate::Result<Self>;
31+
32+
/// Create a fork for a single benchmark iteration.
33+
///
34+
/// This allows each iteration to run in isolation without affecting others.
35+
fn fork(&mut self) -> Fork<Self> {
36+
Fork(self)
37+
}
38+
39+
/// Clean up after a benchmark iteration.
40+
///
41+
/// # Safety
42+
/// This method may perform unsafe operations like clearing all data.
43+
unsafe fn unfork(&mut self);
44+
}

rust/src/benched/neo4j_benched.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! # Neo4j Benched Implementations
2+
//!
3+
//! This module contains the [`Benched`] trait implementations for all Neo4j
4+
//! storage backends.
5+
//!
6+
//! ## Storage Backends
7+
//!
8+
//! | Type | Mode | Description |
9+
//! |-----------------------------|-----------------|----------------------------------|
10+
//! | `Exclusive<Client>` | Non-transaction | Direct HTTP API calls |
11+
//! | `Exclusive<Transaction>` | Transaction | Transaction wrapper (same impl) |
12+
//!
13+
//! ## Implementation Details
14+
//!
15+
//! Neo4j implementations clean up by executing:
16+
//! ```cypher
17+
//! MATCH (l:Link) DETACH DELETE l
18+
//! ```
19+
//!
20+
//! This removes all Link nodes from the database for the next benchmark iteration.
21+
22+
use doublets::data::LinkType;
23+
24+
use super::Benched;
25+
use crate::{Client, Exclusive, Fork, Sql, Transaction};
26+
27+
/// Neo4j client (non-transactional mode).
28+
///
29+
/// ## Setup
30+
/// ```rust,ignore
31+
/// let client = Exclusive::<Client<usize>>::setup(())?;
32+
/// ```
33+
///
34+
/// ## Fork Behavior
35+
/// Creates the schema (constraints/indexes) before each iteration.
36+
///
37+
/// ## Cleanup
38+
/// Executes `MATCH (l:Link) DETACH DELETE l` to remove all nodes.
39+
impl<T: LinkType> Benched for Exclusive<Client<T>> {
40+
type Builder<'a> = ();
41+
42+
fn setup(_: Self::Builder<'_>) -> crate::Result<Self> {
43+
unsafe { Ok(Exclusive::new(crate::connect()?)) }
44+
}
45+
46+
fn fork(&mut self) -> Fork<Self> {
47+
let _ = self.create_table();
48+
Fork(self)
49+
}
50+
51+
unsafe fn unfork(&mut self) {
52+
let _ = self.drop_table();
53+
}
54+
}
55+
56+
/// Neo4j transaction wrapper.
57+
///
58+
/// ## Setup
59+
/// ```rust,ignore
60+
/// let client = connect()?;
61+
/// let transaction = Exclusive::<Transaction<'_, usize>>::setup(&client)?;
62+
/// ```
63+
///
64+
/// ## Fork Behavior
65+
/// Cleans up any existing data before each iteration to ensure isolation.
66+
///
67+
/// ## Cleanup
68+
/// Executes `MATCH (l:Link) DETACH DELETE l` to remove all nodes.
69+
impl<'a, T: LinkType> Benched for Exclusive<Transaction<'a, T>> {
70+
type Builder<'b> = &'a Client<T>;
71+
72+
fn setup(builder: Self::Builder<'_>) -> crate::Result<Self> {
73+
let transaction = Transaction::new(builder)?;
74+
unsafe { Ok(Exclusive::new(transaction)) }
75+
}
76+
77+
fn fork(&mut self) -> Fork<Self> {
78+
// Clean up any existing data before benchmark to ensure isolation
79+
let _ = self.drop_table();
80+
Fork(self)
81+
}
82+
83+
unsafe fn unfork(&mut self) {
84+
// Clean up after benchmark iteration
85+
let _ = self.drop_table();
86+
}
87+
}

0 commit comments

Comments
 (0)