1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
//! Benchmarks, as ignored tests (`cargo benchmarks`, `docs/development.md`).
//!
//! `replay`: carrying writes over into a new epoch's document, last writer wins
//! (`delta::replay_newest`): what a rejoin does with the writes made during it, and a
//! switch with those made after the remake's base. It finds the paths of every write
//! carried, and of every newer change in the new document, from its operations
//! (`store::changed_by`).
use std::time::Instant;
use automerge::transaction::Transactable;
use automerge::{ObjType, ROOT, ReadDoc, ScalarValue};
use super::delta::{Superseded, replay_newest};
use super::kind::Translator;
use crate::document::Document;
use crate::document::bench::{document, median};
use crate::document::store;
/// `count` changes to `doc`, each writing one key under `data` (from `first` on), made
/// at `at` and after.
fn writes(doc: &mut Document, first: usize, count: usize, at: i64) {
for i in 0..count {
let mut transaction = doc.transaction();
let data = transaction
.get(ROOT, "data")
.expect("read")
.map(|(_, id)| id)
.unwrap_or_else(|| {
transaction
.put_object(ROOT, "data", ObjType::Map)
.expect("map")
});
transaction
.put(
&data,
format!("late{}", first + i),
ScalarValue::Int(i as i64),
)
.expect("write");
transaction
.commit_with(automerge::transaction::CommitOptions::default().with_time(at + i as i64));
}
}
/// `late` writes made to the old document after `keys` keys, carried into a new one
/// holding those keys (as a snapshot, at time 0) and `newer` writes of its own made
/// after them.
fn replay(keys: usize, late: usize, newer: usize) {
let old_base = document(keys);
let base = old_base.get_heads();
let mut old = old_base.clone();
writes(&mut old, 0, late, 1_000);
let after = old.get_heads();
let mut new = Document::new();
{
let mut transaction = new.transaction();
store::materialize_into(&old_base, &mut transaction, &|_| false).expect("snapshot");
transaction.commit_with(automerge::transaction::CommitOptions::default().with_time(0));
}
writes(&mut new, late, newer, 2_000);
let took = median(5, || {
let mut target = new.clone();
let started = Instant::now();
std::hint::black_box(replay_newest(
&old,
&base,
&after,
&mut target,
&Translator::default(),
Superseded::Drop,
));
started.elapsed()
});
println!(
"{:<60} {:>10.3} ms",
format!("replay of {late} writes, {keys} keys, {newer} newer changes"),
took.as_secs_f64() * 1e3
);
}
#[test]
#[ignore = "a benchmark: cargo benchmarks"]
fn bench_replay() {
println!(""); // put reports on new line
replay(1_000, 100, 100);
replay(100_000, 100, 100);
replay(100_000, 1_000, 1_000);
}
|