Skip to main content

coven_database/
journal.rs

1//! The journal as one of coven's steps in a write sees it (§4, §11): sync's
2//! steps read and change the journal's rows, pending records and retry
3//! waits in the write's own transaction, through this, and commit or roll
4//! back with the app's SQL. Sync owns what the rows mean.
5
6use super::FileWrite;
7use crate::{
8    DbError, NewOperation, OperationId, OperationRecord, OperationUpdate, RetrySubject, StoreState,
9};
10
11/// The journal inside one write, for sync's steps.
12pub struct Journal<'write> {
13    files: &'write FileWrite<'write>,
14}
15
16impl<'write> Journal<'write> {
17    pub(crate) fn new(files: &'write FileWrite<'write>) -> Self {
18        Self { files }
19    }
20
21    /// The operation's journal row, as this write sees it; `None` once it
22    /// has finished, or if it never existed.
23    pub fn operation(&self, id: OperationId) -> Result<Option<OperationRecord>, DbError> {
24        crate::operation::find(self.files.database, id)
25    }
26
27    /// The journal's rows of `kind`, oldest first, as this write sees them.
28    pub fn operations(&self, kind: &str) -> Result<Vec<OperationRecord>, DbError> {
29        crate::operation::of_kind(self.files.database, kind)
30    }
31
32    /// Advance an operation one step past the row it read; its pending
33    /// record and retry wait end with the step it left. A row that has
34    /// moved on since fails with `OperationChanged`.
35    pub fn advance_operation(&self, update: &OperationUpdate) -> Result<(), DbError> {
36        crate::operation::advance(self.files.database, update)
37    }
38
39    /// Membership and audience state after the applied slots, as this
40    /// write sees it.
41    pub fn store_state(&self) -> Result<StoreState, DbError> {
42        crate::store_state_tables::read(self.files.database)
43    }
44
45    /// The last slot whose effects this device has applied.
46    pub fn applied_slot(&self) -> Result<u64, DbError> {
47        crate::sequence::applied(self.files.database)
48    }
49
50    /// Journal an operation before its first step, which sync runs and
51    /// ends on its own; `coven_operations` doesn't list it.
52    pub fn start_operation(&self, operation: &NewOperation) -> Result<OperationId, DbError> {
53        crate::operation::insert(self.files.database, operation)
54    }
55
56    /// Journal an operation the app's write asks for, of `kind` as sync
57    /// names it, before its first step. It is listed in `coven_operations`
58    /// from this write's commit until the app acknowledges its outcome.
59    pub fn start_app_operation(
60        &self,
61        operation: &NewOperation,
62        kind: &str,
63    ) -> Result<OperationId, DbError> {
64        crate::operation::insert_for_app(self.files.database, operation, kind)
65    }
66
67    /// End the app's record of a finished operation: it leaves
68    /// `coven_operations`. One still running fails with `OperationRunning`;
69    /// one this device doesn't list, never journaled by the app or
70    /// acknowledged already, with `OperationUnknown`.
71    pub(crate) fn acknowledge(&self, id: OperationId) -> Result<(), DbError> {
72        crate::operation::acknowledge(self.files.database, id)
73    }
74
75    /// The pending record that names the operation, if any.
76    pub fn operation_pending<P: crate::PendingValue>(
77        &self,
78        id: OperationId,
79    ) -> Result<Option<P>, DbError> {
80        crate::pending::operation(self.files.database, id)
81    }
82
83    /// Whether automatic work can retry the subject with the coven and
84    /// schema versions installed now.
85    pub fn pending_can_retry<P: crate::PendingValue>(
86        &self,
87        subject: &P::Subject,
88    ) -> Result<bool, DbError> {
89        crate::pending::retry::<P>(self.files.database, subject)
90    }
91
92    /// Clear the subject's pending record.
93    pub fn clear_pending<S: serde::Serialize>(&self, subject: &S) -> Result<(), DbError> {
94        crate::pending::clear(self.files.database, subject)
95    }
96
97    /// Clear the subject's retry wait.
98    pub fn clear_retry(&self, subject: RetrySubject) -> Result<(), DbError> {
99        crate::retry::clear(self.files.database, subject)
100    }
101}
102
103#[cfg(test)]
104#[path = "journal_tests.rs"]
105mod tests;