Skip to main content

write_chunked_field

Function write_chunked_field 

Source
fn write_chunked_field(
    field_key: &str,
    value: &str,
    generation: &str,
) -> Result<Vec<(String, PriorKeychainState)>, StoreError>
Expand description

Write value to field_key as one or more chunk entries (each under MAX_CHUNK_LEN) plus a :count entry, clearing any stale trailing chunks left over from a previous, longer value at this key, and stamps generation (same value across all three fields for one write_split_tokens call — see new_generation’s doc comment) on this field’s :gen entry. Rolls back everything this call touched if any single write/delete fails partway through.

Write order matters here beyond just “rollback on failure” (reagent P1: a prior version wrote chunks, then cleared stale trailing chunks, then updated :count, then :gen, in that order — a process CRASH between the chunk-write and the trailing-chunk-delete left :count still pointing at the OLD larger count while the leading chunks already held NEW content; on restart read_chunked_field would read exactly old_count chunks — none technically missing, so no error — silently reconstructing a spliced new-prefix/old-suffix value that’s neither the old nor the new token, with :gen untouched so read_split_tokens’s cross-field generation check never even saw a mismatch to catch). This version deletes :gen FIRST, before touching any chunk content, and writes the fresh generation value LAST, only once chunks + :count are fully consistent — read_chunked_field already treats a missing :gen on an otherwise-populated field as an error, so a crash ANYWHERE in between now makes this field unambiguously detectable as torn, rather than silently reconstructible.

On success, returns the PRE-call state of every entry touched (:gen, chunks, :count), so a caller doing more work of its own afterward (write_split_tokens covering a sibling field, or muxbus_save’s SQL write) can roll all of it back together if that later step fails too.