Skip to main content

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}