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
|
//! The worker that keeps the document file (`document::file`) up to date: it looks at
//! the node (ready, not rejoining, the document's epoch and heads, this node's actors),
//! and the file says what is due.
use crate::document::file::Due;
use crate::state::AppState;
/// Keeps the document file up to date. Runs for as long as the node does.
pub(crate) async fn run(state: AppState) {
let Some(file) = state.document_file.clone() else {
return;
};
let mut tick = tokio::time::interval(file.append_every());
tick.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay);
loop {
tick.tick().await;
flush(&state).await;
}
}
/// Writes what is due now (`DocumentFile::due`). Also called at shutdown.
pub(crate) async fn flush(state: &AppState) {
let Some(file) = state.document_file.clone() else {
return;
};
if !state.is_ready().await || state.remake.is_rejoining() {
return;
}
let own = state.remake.own_actors();
let (epoch, heads) = {
let replica = state.doc.read().await;
(replica.epoch, replica.heads().to_vec())
};
match file.due(epoch, own.len(), &heads) {
Due::Rewrite(reason) => {
let (epoch, copy) = {
let replica = state.doc.read().await;
(replica.epoch, replica.doc.clone())
};
file.rewrite(epoch, copy, own, reason).await;
}
Due::Append { epoch, since } => {
let (heads, increment) = {
let mut replica = state.doc.write().await;
// Switched since: the next flush rewrites the file instead.
if replica.epoch != epoch {
return;
}
let heads = replica.heads().to_vec();
(heads, crate::document::save_since(&mut replica.doc, &since))
};
file.append(since, heads, increment).await;
}
Due::Nothing => {}
}
}
|