From 42021a500d19dbe091075338d1a621498a81f167 Mon Sep 17 00:00:00 2001 From: eunhhu Date: Sat, 26 Sep 2026 22:56:32 +0100 Subject: Snapshot an app's saved states for readers on other threads Right after a save, pure_app_snapshot makes a read-only snapshot of the saved states: numbers are copied, text states are frozen drafts that share the store mapping (pure_draft_freeze, no copy), and lists are copies of their item pointers that share the items. An unchanged list shares the last snapshot's copy. pure_app_read binds a reader app on another thread to a snapshot so the existing view functions read it. A shared item never changes again: a list stamps each item with its share count, copies a shared item it changes, and retires shared items it lets go instead of freeing them. Snapshots form a chain that goes oldest first, and items retired while a snapshot was the newest go with it. References are atomic and may be released on any thread. test-module checks that each snapshot equals the app, that kept snapshots stay as made through changes, removals, a module switch, the app stopping and the store closing, that a failed save's snapshot equals the one before, and that two threads read the newest snapshots while the app goes on (also under ASan, UBSan and LeakSanitizer). --- prototypes/connections/state.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'prototypes/connections/state.h') diff --git a/prototypes/connections/state.h b/prototypes/connections/state.h index 43489c1..2bf78b0 100644 --- a/prototypes/connections/state.h +++ b/prototypes/connections/state.h @@ -35,7 +35,8 @@ PureResult pure_store_state(PureStore *, const char *name, PureDraft **out); * nodes from (NULL for other drafts). Spans that mapping holds stay readable * until the reference is released, after the draft closes and after the * store moves on. Spans of a draft's unsaved edits are not in it. Take it on - * the handle's owner thread; the reference may be released on any thread. */ + * the handle's owner thread (a frozen draft's on any); the reference may be + * released on any thread. */ typedef struct PureMapping PureMapping; PureMapping *pure_draft_mapping(const PureDraft *); bool pure_mapping_holds(const PureMapping *, PureSpan); @@ -60,6 +61,12 @@ typedef struct { uint64_t ref, bytes; } PureVersion; PureVersion pure_draft_version(const PureDraft *); PureResult pure_draft_read_version(const PureDraft *, PureVersion, size_t offset, size_t length, bool (*visit)(void *, PureSpan), void *context); +/* A read-only copy of a draft opened through a store handle, at its current + * version, when that version is all stored (no edits since its last commit, + * as right after one): it shares the draft's mapping, and since reading + * changes nothing it may be read, lend its mapping and close on any thread. + * NULL otherwise, or when memory runs out. */ +PureDraft *pure_draft_freeze(const PureDraft *); /* While held, edits keep every earlier version's nodes (one transaction). */ void pure_draft_hold(PureDraft *, bool held); /* Abandon edits made since version was taken; the draft was held since then. */ -- cgit v1.2.3