memoryd: the Honcho worker sends decided turns, waits out outages, retries undecided turns

Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
2026-09-28 12:30:49 -07:00
co-authored by ornith-1.5-35b-a3b
parent aabfbc2f0a
commit b37eaef390
12 changed files with 1451 additions and 34 deletions
+40 -2
View File
@@ -112,13 +112,45 @@ impl TurnSync {
&self.ledger
}
/// The directory of `loopd`'s session logs.
pub fn sessions(&self) -> &Path {
&self.sessions
}
/// The sessions that still have undecided turns, with the highest turn reported for each.
pub fn waiting(&self) -> Vec<(SessionId, u64)> {
self.reported.values().cloned().collect()
}
/// `loopd` reported that turn `turn` of `session` ended. Remember it, then walk every session
/// with undecided turns, in the order of their ids, until one stops the walk.
/// After a restart: each session with a decided turn in the ledger waits again, at the turns
/// its log holds, so that a turn left undecided before the restart is decided at the next
/// walk (`decidable` holds back one still running). A session with no decided turn is left
/// to its next report: sessions from before Honcho was turned on are never walked.
pub fn resume(&mut self) {
let mut sessions: Vec<SessionId> = Vec::new();
for (item, _) in self.ledger.decisions() {
if let Item::Turn { session, .. } = item
&& !sessions.contains(session)
{
sessions.push(session.clone());
}
}
for session in sessions {
if let Ok(records) = read_log(&log_path(&self.sessions, &session)) {
self.reported.insert(
session.as_str().to_string(),
(session.clone(), turns(&records)),
);
}
}
}
/// Append `record` to the ledger (the worker's `Sent` and `Failed`).
pub fn append(&mut self, record: Record) -> Result<(), ledger::LedgerError> {
self.ledger.append(record)
}
/// `loopd` reported that turn `turn` of `session` ended. Remember it, then walk.
pub fn updated(
&mut self,
session: &SessionId,
@@ -132,6 +164,12 @@ impl TurnSync {
.entry(session.as_str().to_string())
.or_insert((session.clone(), 0));
entry.1 = entry.1.max(turn);
self.retry(ask, now, log);
}
/// Walk every session with undecided turns, in the order of their ids, until one stops the
/// walk: at a report, and from the worker when it has nothing to send (M5c spec, section 5).
pub fn retry(&mut self, ask: Ask<'_>, now: Timestamp, log: &dyn Fn(&str)) {
for (session, turn) in self.waiting() {
match self.walk(&session, turn, ask, now, log) {
Walk::Done => {