Skip to content

Commit 7fcdba1

Browse files
authored
Merge pull request #14 from linksplatform/issue-13-0b67341a17ae
Reorganize the code to make it crystal clear how the same logic is implemented in Doublets and Neo4j
2 parents 7e63193 + be28b68 commit 7fcdba1

30 files changed

+1640
-255
lines changed

rust/benches/bench.rs

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
#![feature(allocator_api)]
22

33
use benchmarks::{
4-
create_links, delete_links, each_all, each_concrete, each_identity, each_incoming,
5-
each_outgoing, update_links,
4+
// Neo4j benchmarks
5+
neo4j_create_links, neo4j_delete_links, neo4j_each_all, neo4j_each_concrete,
6+
neo4j_each_identity, neo4j_each_incoming, neo4j_each_outgoing, neo4j_update_links,
7+
// Doublets benchmarks
8+
doublets_create_links, doublets_delete_links, doublets_each_all, doublets_each_concrete,
9+
doublets_each_identity, doublets_each_incoming, doublets_each_outgoing, doublets_update_links,
610
};
711
use criterion::{criterion_group, criterion_main};
812

@@ -18,15 +22,30 @@ macro_rules! tri {
1822

1923
pub(crate) use tri;
2024

25+
// Neo4j benchmarks group
2126
criterion_group!(
22-
benches,
23-
create_links,
24-
delete_links,
25-
each_identity,
26-
each_concrete,
27-
each_outgoing,
28-
each_incoming,
29-
each_all,
30-
update_links
27+
neo4j_benches,
28+
neo4j_create_links,
29+
neo4j_delete_links,
30+
neo4j_each_identity,
31+
neo4j_each_concrete,
32+
neo4j_each_outgoing,
33+
neo4j_each_incoming,
34+
neo4j_each_all,
35+
neo4j_update_links
3136
);
32-
criterion_main!(benches);
37+
38+
// Doublets benchmarks group
39+
criterion_group!(
40+
doublets_benches,
41+
doublets_create_links,
42+
doublets_delete_links,
43+
doublets_each_identity,
44+
doublets_each_concrete,
45+
doublets_each_outgoing,
46+
doublets_each_incoming,
47+
doublets_each_all,
48+
doublets_update_links
49+
);
50+
51+
criterion_main!(neo4j_benches, doublets_benches);

rust/benches/benchmarks/create.rs renamed to rust/benches/benchmarks/doublets/create.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
1+
//! # Doublets Create Links Benchmark
2+
//!
3+
//! This benchmark measures the performance of creating new links in Doublets.
4+
//!
5+
//! ## Implementation
6+
//!
7+
//! Doublets creates links by:
8+
//! - Allocating next available ID from internal counter
9+
//! - Writing (id, id, id) tuple directly to memory/file
10+
//! - Updating source and target indexes
11+
//! - Time complexity: O(log n) for index updates
12+
113
use std::{
214
alloc::Global,
315
time::{Duration, Instant},
416
};
517

618
use criterion::{measurement::WallTime, BenchmarkGroup, Criterion};
719
use doublets::{
8-
data::LinkType,
920
mem::{Alloc, FileMapped},
1021
parts::LinkPart,
1122
split::{self, DataPart, IndexPart},
1223
unit, Doublets,
1324
};
14-
use linksneo4j::{bench, connect, Benched, Client, Exclusive, Fork, Transaction, LINK_COUNT};
25+
use linksneo4j::{bench, Benched, Fork, LINK_COUNT};
1526

1627
use crate::tri;
1728

18-
fn bench<T: LinkType, B: Benched + Doublets<T>>(
29+
/// Runs the create benchmark on a Doublets backend.
30+
fn bench<B: Benched + Doublets<usize>>(
1931
group: &mut BenchmarkGroup<WallTime>,
2032
id: &str,
2133
mut benched: B,
@@ -29,19 +41,10 @@ fn bench<T: LinkType, B: Benched + Doublets<T>>(
2941
});
3042
}
3143

44+
/// Creates benchmark for Doublets backends on link creation.
3245
pub fn create_links(c: &mut Criterion) {
3346
let mut group = c.benchmark_group("Create");
34-
tri! {
35-
bench(&mut group, "Neo4j_NonTransaction", Exclusive::<Client<usize>>::setup(()).unwrap());
36-
}
37-
tri! {
38-
let client = connect().unwrap();
39-
bench(
40-
&mut group,
41-
"Neo4j_Transaction",
42-
Exclusive::<Transaction<'_, usize>>::setup(&client).unwrap(),
43-
);
44-
}
47+
4548
tri! {
4649
bench(
4750
&mut group,
@@ -70,5 +73,6 @@ pub fn create_links(c: &mut Criterion) {
7073
split::Store::<usize, FileMapped<_>, FileMapped<_>>::setup(("split_index.links", "split_data.links")).unwrap()
7174
)
7275
}
76+
7377
group.finish();
7478
}

rust/benches/benchmarks/delete.rs renamed to rust/benches/benchmarks/doublets/delete.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
//! # Doublets Delete Links Benchmark
2+
//!
3+
//! This benchmark measures the performance of deleting links by ID in Doublets.
4+
//!
5+
//! ## Implementation
6+
//!
7+
//! Doublets deletes links by:
8+
//! - Looking up link by ID (O(1) array access)
9+
//! - Removing from source and target indexes
10+
//! - Marking slot as free for reuse
11+
//! - Time complexity: O(log n) for index updates
12+
113
use std::{
214
alloc::Global,
315
time::{Duration, Instant},
@@ -10,10 +22,11 @@ use doublets::{
1022
split::{self, DataPart, IndexPart},
1123
unit, Doublets,
1224
};
13-
use linksneo4j::{bench, connect, Benched, Client, Exclusive, Fork, Transaction, LINK_COUNT};
25+
use linksneo4j::{bench, Benched, Fork, LINK_COUNT};
1426

1527
use crate::tri;
1628

29+
/// Runs the delete benchmark on a Doublets backend.
1730
fn bench<B: Benched + Doublets<usize>>(
1831
group: &mut BenchmarkGroup<WallTime>,
1932
id: &str,
@@ -22,31 +35,20 @@ fn bench<B: Benched + Doublets<usize>>(
2235
group.bench_function(id, |bencher| {
2336
bench!(|fork| as B {
2437
use linksneo4j::BACKGROUND_LINKS;
25-
// Create additional links beyond background links to delete
2638
for _prepare in BACKGROUND_LINKS..BACKGROUND_LINKS + *LINK_COUNT {
2739
let _ = fork.create_point();
2840
}
29-
// Delete the links we just created (in reverse order)
3041
for id in (BACKGROUND_LINKS + 1..=BACKGROUND_LINKS + *LINK_COUNT).rev() {
3142
let _ = elapsed! {fork.delete(id)?};
3243
}
3344
})(bencher, &mut benched);
3445
});
3546
}
3647

48+
/// Creates benchmark for Doublets backends on link deletion.
3749
pub fn delete_links(c: &mut Criterion) {
3850
let mut group = c.benchmark_group("Delete");
39-
tri! {
40-
bench(&mut group, "Neo4j_NonTransaction", Exclusive::<Client<usize>>::setup(()).unwrap());
41-
}
42-
tri! {
43-
let client = connect().unwrap();
44-
bench(
45-
&mut group,
46-
"Neo4j_Transaction",
47-
Exclusive::<Transaction<'_, usize>>::setup(&client).unwrap(),
48-
);
49-
}
51+
5052
tri! {
5153
bench(
5254
&mut group,
@@ -75,5 +77,6 @@ pub fn delete_links(c: &mut Criterion) {
7577
split::Store::<usize, FileMapped<_>, FileMapped<_>>::setup(("split_index.links", "split_data.links")).unwrap()
7678
)
7779
}
80+
7881
group.finish();
7982
}

rust/benches/benchmarks/each/all.rs renamed to rust/benches/benchmarks/doublets/each/all.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
1+
//! # Doublets Each All Benchmark
2+
//!
3+
//! Measures the performance of iterating over ALL links in Doublets.
4+
//!
5+
//! ## Implementation
6+
//!
7+
//! Doublets iterates all links by:
8+
//! - Sequential iteration through internal link array
9+
//! - Skipping empty/deleted slots
10+
//! - Time complexity: O(n) where n = total links
11+
112
use std::{
213
alloc::Global,
314
time::{Duration, Instant},
415
};
516

617
use criterion::{measurement::WallTime, BenchmarkGroup, Criterion};
18+
use doublets::data::{Flow, LinkType};
719
use doublets::{
8-
data::{Flow, LinkType},
920
mem::{Alloc, FileMapped},
1021
parts::LinkPart,
1122
split::{self, DataPart, IndexPart},
1223
unit, Doublets,
1324
};
14-
use linksneo4j::{bench, connect, Benched, Client, Exclusive, Fork, Transaction};
25+
use linksneo4j::{bench, Benched, Fork};
1526

1627
use crate::tri;
1728

29+
/// Runs the each_all benchmark on a Doublets backend.
1830
fn bench<T: LinkType, B: Benched + Doublets<T>>(
1931
group: &mut BenchmarkGroup<WallTime>,
2032
id: &str,
@@ -28,19 +40,10 @@ fn bench<T: LinkType, B: Benched + Doublets<T>>(
2840
});
2941
}
3042

43+
/// Creates benchmark for Doublets backends on full table scan.
3144
pub fn each_all(c: &mut Criterion) {
3245
let mut group = c.benchmark_group("Each_All");
33-
tri! {
34-
bench(&mut group, "Neo4j_NonTransaction", Exclusive::<Client<usize>>::setup(()).unwrap());
35-
}
36-
tri! {
37-
let client = connect().unwrap();
38-
bench(
39-
&mut group,
40-
"Neo4j_Transaction",
41-
Exclusive::<Transaction<'_, usize>>::setup(&client).unwrap(),
42-
);
43-
}
46+
4447
tri! {
4548
bench(
4649
&mut group,
@@ -69,5 +72,6 @@ pub fn each_all(c: &mut Criterion) {
6972
split::Store::<usize, FileMapped<_>, FileMapped<_>>::setup(("split_index.links", "split_data.links")).unwrap()
7073
)
7174
}
75+
7276
group.finish();
7377
}

rust/benches/benchmarks/each/concrete.rs renamed to rust/benches/benchmarks/doublets/each/concrete.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
1+
//! # Doublets Each Concrete Benchmark
2+
//!
3+
//! Measures the performance of querying links by BOTH source AND target in Doublets.
4+
//!
5+
//! ## Implementation
6+
//!
7+
//! Doublets queries by source AND target using:
8+
//! - Uses source OR target index tree to find candidates
9+
//! - Filters by the other field
10+
//! - Time complexity: O(log n) for tree traversal
11+
112
use std::{
213
alloc::Global,
314
time::{Duration, Instant},
415
};
516

617
use criterion::{measurement::WallTime, BenchmarkGroup, Criterion};
18+
use doublets::data::{Flow, LinksConstants};
719
use doublets::{
8-
data::{Flow, LinksConstants},
920
mem::{Alloc, FileMapped},
1021
parts::LinkPart,
1122
split::{self, DataPart, IndexPart},
1223
unit, Doublets,
1324
};
14-
use linksneo4j::{bench, connect, Benched, Client, Exclusive, Fork, Transaction};
25+
use linksneo4j::{bench, Benched, Fork};
1526

1627
use crate::tri;
1728

29+
/// Runs the each_concrete benchmark on a Doublets backend.
1830
fn bench<B: Benched + Doublets<usize>>(
1931
group: &mut BenchmarkGroup<WallTime>,
2032
id: &str,
@@ -25,27 +37,17 @@ fn bench<B: Benched + Doublets<usize>>(
2537
group.bench_function(id, |bencher| {
2638
bench!(|fork| as B {
2739
use linksneo4j::BACKGROUND_LINKS;
28-
// Query all background links by concrete source/target
2940
for index in 1..=BACKGROUND_LINKS {
3041
elapsed! {fork.each_by([any, index, index], handler)};
3142
}
3243
})(bencher, &mut benched);
3344
});
3445
}
3546

47+
/// Creates benchmark for Doublets backends on composite index lookup.
3648
pub fn each_concrete(c: &mut Criterion) {
3749
let mut group = c.benchmark_group("Each_Concrete");
38-
tri! {
39-
bench(&mut group, "Neo4j_NonTransaction", Exclusive::<Client<usize>>::setup(()).unwrap());
40-
}
41-
tri! {
42-
let client = connect().unwrap();
43-
bench(
44-
&mut group,
45-
"Neo4j_Transaction",
46-
Exclusive::<Transaction<'_, usize>>::setup(&client).unwrap(),
47-
);
48-
}
50+
4951
tri! {
5052
bench(
5153
&mut group,
@@ -74,5 +76,6 @@ pub fn each_concrete(c: &mut Criterion) {
7476
split::Store::<usize, FileMapped<_>, FileMapped<_>>::setup(("split_index.links", "split_data.links")).unwrap()
7577
)
7678
}
79+
7780
group.finish();
7881
}

rust/benches/benchmarks/each/identity.rs renamed to rust/benches/benchmarks/doublets/each/identity.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
1+
//! # Doublets Each Identity Benchmark
2+
//!
3+
//! Measures the performance of looking up links by ID in Doublets.
4+
//!
5+
//! ## Implementation
6+
//!
7+
//! Doublets looks up by ID using:
8+
//! - Direct array index access: O(1)
9+
//! - Returns link at `links[id]` if it exists
10+
111
use std::{
212
alloc::Global,
313
time::{Duration, Instant},
414
};
515

616
use criterion::{measurement::WallTime, BenchmarkGroup, Criterion};
17+
use doublets::data::{Flow, LinksConstants};
718
use doublets::{
8-
data::{Flow, LinksConstants},
919
mem::{Alloc, FileMapped},
1020
parts::LinkPart,
1121
split::{self, DataPart, IndexPart},
1222
unit, Doublets,
1323
};
14-
use linksneo4j::{bench, connect, Benched, Client, Exclusive, Fork, Transaction};
24+
use linksneo4j::{bench, Benched, Fork};
1525

1626
use crate::tri;
1727

28+
/// Runs the each_identity benchmark on a Doublets backend.
1829
fn bench<B: Benched + Doublets<usize>>(
1930
group: &mut BenchmarkGroup<WallTime>,
2031
id: &str,
@@ -25,27 +36,17 @@ fn bench<B: Benched + Doublets<usize>>(
2536
group.bench_function(id, |bencher| {
2637
bench!(|fork| as B {
2738
use linksneo4j::BACKGROUND_LINKS;
28-
// Query all background links by identity
2939
for index in 1..=BACKGROUND_LINKS {
3040
elapsed! {fork.each_by([index, any, any], handler)};
3141
}
3242
})(bencher, &mut benched);
3343
});
3444
}
3545

46+
/// Creates benchmark for Doublets backends on ID lookup.
3647
pub fn each_identity(c: &mut Criterion) {
3748
let mut group = c.benchmark_group("Each_Identity");
38-
tri! {
39-
bench(&mut group, "Neo4j_NonTransaction", Exclusive::<Client<usize>>::setup(()).unwrap());
40-
}
41-
tri! {
42-
let client = connect().unwrap();
43-
bench(
44-
&mut group,
45-
"Neo4j_Transaction",
46-
Exclusive::<Transaction<'_, usize>>::setup(&client).unwrap(),
47-
);
48-
}
49+
4950
tri! {
5051
bench(
5152
&mut group,
@@ -74,5 +75,6 @@ pub fn each_identity(c: &mut Criterion) {
7475
split::Store::<usize, FileMapped<_>, FileMapped<_>>::setup(("split_index.links", "split_data.links")).unwrap()
7576
)
7677
}
78+
7779
group.finish();
7880
}

0 commit comments

Comments
 (0)