aboutsummaryrefslogtreecommitdiffstats
path: root/src/document
diff options
context:
space:
mode:
Diffstat (limited to 'src/document')
-rw-r--r--src/document/changes.rs22
-rw-r--r--src/document/file.rs9
-rw-r--r--src/document/mod.rs24
-rw-r--r--src/document/replica.rs2
4 files changed, 49 insertions, 8 deletions
diff --git a/src/document/changes.rs b/src/document/changes.rs
index d369c79..655063b 100644
--- a/src/document/changes.rs
+++ b/src/document/changes.rs
@@ -8,6 +8,26 @@ use anyhow::{Context, Result, anyhow, bail};
use super::{Change, ChangeHash, Document};
+/// Those of `heads` that `doc` doesn't have. (Looking a change up needs the document
+/// mutably.)
+pub(crate) fn missing(doc: &mut Document, heads: &[ChangeHash]) -> Vec<ChangeHash> {
+ heads
+ .iter()
+ .copied()
+ .filter(|head| doc.get_change_by_hash(head).is_none())
+ .collect()
+}
+
+/// When the changes after `since` were committed, in Unix milliseconds by their
+/// writers' clocks (`Replica::commit`); changes without a time (snapshots) left out.
+pub(crate) fn commit_times(doc: &mut Document, since: &[ChangeHash]) -> Vec<i64> {
+ doc.get_changes(since)
+ .iter()
+ .map(|change| change.timestamp())
+ .filter(|&time| time > 0)
+ .collect()
+}
+
/// The change `hash` as the document encodes it; None if `doc` doesn't have it.
pub(crate) fn change_bytes(doc: &mut Document, hash: &ChangeHash) -> Option<Vec<u8>> {
doc.get_change_by_hash(hash)
@@ -33,7 +53,7 @@ pub(crate) fn delta_bytes(
from: &[ChangeHash],
to: &[ChangeHash],
) -> Option<Vec<u8>> {
- if to.iter().any(|head| doc.get_change_by_hash(head).is_none()) {
+ if !missing(doc, to).is_empty() {
return None;
}
// Heads of `from` we don't have can't hide anything we have.
diff --git a/src/document/file.rs b/src/document/file.rs
index 47d7310..e03c2e6 100644
--- a/src/document/file.rs
+++ b/src/document/file.rs
@@ -99,7 +99,7 @@ fn parse(bytes: &[u8]) -> Result<(Loaded, usize)> {
}
let (record, after) = after.split_at(length);
match &mut doc {
- None => doc = Some(AutoCommit::load(record).context("the full save")?),
+ None => doc = Some(super::load(record).context("the full save")?),
Some(doc) => {
doc.load_incremental(record).context("an increment")?;
}
@@ -109,10 +109,7 @@ fn parse(bytes: &[u8]) -> Result<(Loaded, usize)> {
let Some(doc) = doc else {
bail!("no full save");
};
- let loaded = Loaded {
- doc: doc.with_actor(ActorId::random()),
- actors,
- };
+ let loaded = Loaded { doc, actors };
Ok((loaded, records.len()))
}
@@ -250,7 +247,7 @@ impl DocumentFile {
.into_iter()
.filter(|actor| *actor == current || present.contains(actor))
.collect();
- let save = copy.save();
+ let save = super::save(&mut copy);
let bytes = whole(&actors, &save)?;
writer
.files
diff --git a/src/document/mod.rs b/src/document/mod.rs
index 1612145..2230e47 100644
--- a/src/document/mod.rs
+++ b/src/document/mod.rs
@@ -6,6 +6,30 @@
/// Only `document` and `remake` use Automerge itself (`architecture.md`, The document).
pub(crate) use automerge::{ActorId, AutoCommit as Document, Change, ChangeHash};
+/// The whole document as bytes, as the engine saves it: a backup, the document
+/// file's full save, the size a joining node downloads.
+pub(crate) fn save(doc: &mut Document) -> Vec<u8> {
+ doc.save()
+}
+
+/// The changes after `since` as bytes that, appended to a save, load with it (the
+/// document file's appends).
+pub(crate) fn save_since(doc: &mut Document, since: &[ChangeHash]) -> Vec<u8> {
+ doc.save_after(since)
+}
+
+/// A saved document (`save`), loaded to write to under a writer ID of its own: one ID
+/// must never write in two places, and a save may be loaded on several nodes, or again
+/// after the node that saved it wrote on.
+pub(crate) fn load(bytes: &[u8]) -> anyhow::Result<Document> {
+ Ok(Document::load(bytes)?.with_actor(ActorId::random()))
+}
+
+/// The actor (writer ID) `doc` writes under.
+pub(crate) fn actor(doc: &Document) -> ActorId {
+ doc.get_actor().clone()
+}
+
pub(crate) mod changes;
pub(crate) mod file;
pub(crate) mod lock;
diff --git a/src/document/replica.rs b/src/document/replica.rs
index 5d3d7a7..5a87016 100644
--- a/src/document/replica.rs
+++ b/src/document/replica.rs
@@ -101,7 +101,7 @@ impl fmt::Debug for Epoch {
/// The heads are cached: `AutoCommit::get_heads` takes `&mut self` (it closes a pending
/// transaction), so without the cache every keepalive and status read would need the
/// write lock. Every path that changes the document under the write lock calls
-/// [`Replica::refresh_heads`] before releasing it (`AppState::write_doc`, `mutate_doc`,
+/// [`Replica::refresh_heads`] before releasing it (`AppState::mutate_doc`,
/// `switch_epoch`, the sync apply); readers take the read lock and use
/// [`Replica::heads`].
///