graph_api_benches/index/vertex_hash/
mod.rs

1use criterion::{BenchmarkGroup, measurement::WallTime};
2use graph_api_derive::{EdgeExt, VertexExt};
3
4use graph_api_lib::Graph;
5#[cfg(feature = "element-removal")]
6use graph_api_lib::SupportsElementRemoval;
7use std::fmt::Debug;
8use uuid::Uuid;
9
10// Define a model with ONLY hash indexes (no label, range, or fulltext indexes)
11#[derive(Debug, Clone, VertexExt)]
12pub enum Vertex {
13    Person {
14        #[index(hash)]
15        name: String,
16        age: u64,
17        unique_id: Uuid,
18        username: String,
19        biography: String,
20    },
21    Project {
22        #[index(hash)]
23        name: String,
24    },
25    Rust,
26}
27
28#[derive(Debug, Clone, EdgeExt)]
29pub enum Edge {
30    Knows { since: i32 },
31    Created,
32    Language { name: String },
33}
34
35// Generate test data with the HashVertex and HashEdge models
36pub fn populate_test_data<G>(graph: &mut G) -> (G::VertexId, G::VertexId, Uuid)
37where
38    G: Graph<Vertex = Vertex, Edge = Edge>,
39{
40    // Create a specific vertex we'll search for
41    let bryn_id = Uuid::new_v4();
42    let bryn = graph.add_vertex(Vertex::Person {
43        name: "Bryn".to_string(),
44        age: 45,
45        unique_id: bryn_id,
46        username: "bryn".to_string(),
47        biography: "Test biography".to_string(),
48    });
49
50    // Add some other vertices
51    for i in 0..100 {
52        graph.add_vertex(Vertex::Person {
53            name: format!("Person{}", i),
54            age: 25 + (i % 50) as u64,
55            unique_id: Uuid::new_v4(),
56            username: format!("user{}", i),
57            biography: format!("Bio for person {}", i),
58        });
59    }
60
61    // Add a project vertex
62    let project = graph.add_vertex(Vertex::Project {
63        name: "TestProject".to_string(),
64    });
65
66    (bryn, project, bryn_id)
67}
68
69// Individual benchmark functions
70
71#[cfg(feature = "vertex-hash-index")]
72pub fn bench_lookup<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
73where
74    G: Graph<Vertex = Vertex, Edge = Edge> + graph_api_lib::SupportsVertexHashIndex,
75{
76    // Benchmark hash property index lookup
77    group.throughput(criterion::Throughput::Elements(1));
78    group.bench_function("vertex_hash_name_lookup", |b| {
79        // Setup: Create graph with test data
80        let mut graph = setup();
81        let (_, _, _) = populate_test_data(&mut graph);
82
83        b.iter(|| {
84            // Query by hash property (name)
85            let results = graph
86                .walk()
87                .vertices(Vertex::person_by_name("Bryn"))
88                .collect::<Vec<_>>();
89
90            assert!(!results.is_empty());
91            results
92        })
93    });
94}
95
96#[cfg(not(feature = "vertex-hash-index"))]
97pub fn bench_lookup<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
98where
99    G: Graph<Vertex = Vertex, Edge = Edge>,
100{
101    // No-op when feature is disabled
102}
103
104#[cfg(feature = "vertex-hash-index")]
105pub fn bench_insertion<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
106where
107    G: Graph<Vertex = Vertex, Edge = Edge> + graph_api_lib::SupportsVertexHashIndex,
108{
109    // Benchmark insertion with hash index
110    group.bench_function("vertex_hash_insertion", |b| {
111        let mut graph = setup();
112        let mut counter = 0;
113
114        b.iter(|| {
115            counter += 1;
116
117            graph.add_vertex(Vertex::Person {
118                name: format!("Test{}", counter),
119                age: 30,
120                unique_id: Uuid::new_v4(),
121                username: format!("test_user{}", counter),
122                biography: "Test biography".to_string(),
123            })
124        })
125    });
126}
127
128#[cfg(not(feature = "vertex-hash-index"))]
129pub fn bench_insertion<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
130where
131    G: Graph<Vertex = Vertex, Edge = Edge>,
132{
133    // No-op when feature is disabled
134}
135
136#[cfg(all(feature = "vertex-hash-index", feature = "element-removal"))]
137pub fn bench_removal<G>(group: &mut BenchmarkGroup<WallTime>, setup: impl Fn() -> G + Clone)
138where
139    G: Graph<Vertex = Vertex, Edge = Edge>
140        + graph_api_lib::SupportsVertexHashIndex
141        + SupportsElementRemoval,
142{
143    // Benchmark removal with hash index
144    group.bench_function("vertex_hash_removal", |b| {
145        // Setup: Create a new graph for each iteration
146        b.iter_with_setup(
147            || {
148                let mut graph = setup();
149                let unique_id = Uuid::new_v4();
150                let vertex_id = graph.add_vertex(Vertex::Person {
151                    name: "HashRemoveMe".to_string(),
152                    age: 25,
153                    unique_id,
154                    username: "hash_remove_user".to_string(),
155                    biography: "To be removed".to_string(),
156                });
157                (graph, vertex_id)
158            },
159            |(mut graph, vertex_id)| {
160                graph.remove_vertex(vertex_id);
161            },
162        )
163    });
164}
165
166#[cfg(not(all(feature = "vertex-hash-index", feature = "element-removal")))]
167pub fn bench_removal<G>(_group: &mut BenchmarkGroup<WallTime>, _setup: impl Fn() -> G + Clone)
168where
169    G: Graph<Vertex = Vertex, Edge = Edge>,
170{
171    // No-op when features are disabled
172}