haematite_cli/serve/storage/embed_rewalk.rs
1//! EMB-E2 (j): `embed.rewalk_longer` walks one field again, once, for the
2//! records it passed with no vector because their text was longer than the
3//! model reads, so windows can cover them.
4//!
5//! It is not a reset. The field's position keeps its `through`, `V`; the
6//! call opens a walk toward `V` itself and marks it a rewalk
7//! ([`embedded::rewalk_key`]). That walk reads from the empty tree to `V`,
8//! at most `embed_page_records` changes a page, and lists only the texts with
9//! no vector and no windows at `V` (`embed_pending`). The page that ends it
10//! removes the marker in its own commit, and the position is as it was:
11//! anything changed after `V` is the next walk's, as always.
12//!
13//! Durable commits: one, writing the marker and the opened position.
14
15use super::embedded::{self, Toward};
16use super::{Failure, Storage, branch_name, identifier, version};
17use crate::serve::protocol::Version;
18
19impl Storage {
20 /// Opens the rewalk of `branch`'s `collection.field` toward its position's
21 /// `through`, which it answers.
22 ///
23 /// # Errors
24 /// `branch_missing`; `embed_field_not_declared`;
25 /// `embed_rewalk_not_ready` when the field has no position of `branch`'s
26 /// own with a finished walk; `embed_walk_open` while a walk or rewalk is
27 /// open; whatever a read or the commit answers.
28 pub fn embed_rewalk_longer(
29 &mut self,
30 branch: &str,
31 collection: &str,
32 field: &str,
33 ) -> Result<Version, Failure> {
34 identifier(branch)?;
35 identifier(collection)?;
36 identifier(field)?;
37 let record = self
38 .refs
39 .get(&branch_name(branch))
40 .ok_or_else(|| Failure::new("branch_missing", branch))?;
41 let head = super::Captured {
42 branch: branch.to_owned(),
43 version: version(record),
44 shards: record.shards.clone(),
45 };
46 self.declared(&head, collection, field)?;
47 let companion = embedded::companion_name(branch);
48 let key = embedded::position_key(collection, field);
49 let not_ready = || {
50 Failure::new(
51 "embed_rewalk_not_ready",
52 format!("{collection}.{field} has no finished walk of {branch}'s own"),
53 )
54 };
55 let mut position = self.position(&companion, &key)?.ok_or_else(not_ready)?;
56 if position.toward.is_some() {
57 return Err(Failure::new(
58 "embed_walk_open",
59 "a rewalk cannot begin while a walk is open",
60 ));
61 }
62 let through = position
63 .through
64 .filter(|_| position.branch == branch)
65 .ok_or_else(not_ready)?;
66 position.toward = Some(Toward {
67 version: through,
68 after: String::new(),
69 });
70 let marker = serde_json::to_vec(&through).map_err(Failure::storage)?;
71 let writes = [
72 (embedded::rewalk_key(collection, field), Some(marker)),
73 (key, Some(embedded::encode_position(&position)?)),
74 ];
75 self.commit_namespace(&companion, &writes)?;
76 Ok(through)
77 }
78}