diff options
| author | eunhhu <[email protected]> | 2026-10-18 23:29:42 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-18 23:29:42 +0100 |
| commit | ff2e0823e97d10477341192d72f5d9e61d9d5bad (patch) | |
| tree | a882cce6e799ab2096ed3d3722e01ec357764e9b /core/module-save.c | |
| parent | 1d255b735e92c2d6b360ed5ea150a1e42f6dd535 (diff) | |
| download | pure-ff2e0823e97d10477341192d72f5d9e61d9d5bad.tar.gz pure-ff2e0823e97d10477341192d72f5d9e61d9d5bad.zip | |
027's 4f-2: no fixed count of states: the header's u16 alone (PURE_MODULE_STATES gone); a module's transient and counted states are flags of each, the lists views and functions change or name sets of states (state_words words, a bit each), the verifier's walked lists a list with its length, duplicate names found by sorting them; an app's eighteen arrays of each state (values, texts, lists, the stored lists' slots, the last save's and the burst's, a reader's, an event's values and marks) in one block sized to its module, a replace laying the new module's apart and taking it once nothing can fail; the runtime's lists placed past any state (PURE_LIST_HEARD 0x10000), their slots after the states'; a snapshot's arrays sized so too; pure_app_read false without room (pure-serve then shows none); a save's drafts, values and the tree's revisions on the stack for 64 states, else on the heap; the JIT compiles modules of 32 states at most (its sets a word), the app's lists read through a pointer; a view reads the app's values as they are (no state changes in one), no copy of 32 a evaluation; unit test: 300 states loaded and the last counted; a hole closed: pure_app_stop read the arrays a failed start never laid; PureApp 4,256 bytes, not 8,504; counts: b39b against b38 with batches within 0.06%, without batches knapsack +0.49%, join +0.23%, the rest within 0.17%; the bank's queries (s38 and s39b in turns, three each) field -1.99%, found -1.18%, in_credit -1.10%, large -0.99%, the rest -0.58% to +0.11% (the first build, s39, copied a view's values at run time's size: in_credit +2.4%); 008 and 027
Diffstat (limited to 'core/module-save.c')
| -rw-r--r-- | core/module-save.c | 64 |
1 files changed, 40 insertions, 24 deletions
diff --git a/core/module-save.c b/core/module-save.c index c70a181..63553e0 100644 --- a/core/module-save.c +++ b/core/module-save.c @@ -67,7 +67,7 @@ enum { JOURNAL_MIN = 1 << 20 }; static const unsigned char links_magic[4] = {'P', 'L', 'K', '4'}, links_magic_3[4] = {'P', 'L', 'K', '3'}, links_magic_2[4] = {'P', 'L', 'K', '2'}, links_magic_1[4] = {'P', 'L', 'K', '1'}; typedef struct { const char *name; unsigned fields; uint8_t kinds[3]; char names[3][PURE_MODULE_NAME]; } RuntimeList; -static const RuntimeList runtime_lists[PURE_LISTS_STORED - PURE_LIST_HEARD] = { +static const RuntimeList runtime_lists[PURE_LIST_RUNTIME] = { {"0heard", 2, {1, 0}, {"source", "seq"}}, {"0sent", 3, {1, 0, 2}, {"output", "seq", "payload"}}, }; @@ -429,7 +429,7 @@ PURE_COLD PureResult pure_save_open_log(PureApp *app) { void pure_save_release(PureApp *app) { if (!app->log) return; uint64_t kept = app->seq + 1; - for (uint32_t i = 0; i < PURE_LISTS_STORED; ++i) + for (size_t i = 0; i < pure_slots(app); ++i) if (app->logged_since[i] && app->logged_since[i] < kept) kept = app->logged_since[i]; pure_log_release(app->log, kept - 1); } @@ -673,35 +673,36 @@ PureCheckpoint *pure_app_checkpoint(PureApp *app) { if (!app->log || app->checkpoint || app->open || app->uncertain || app->reading) return NULL; /* A list whose logged changes outgrew its items, or, when the log grew * past LOG_KEPT, the one that holds it back most: the heard list is one. */ - int due = -1, oldest = -1; + int due = -1, oldest = -1; /* slots */ uint64_t items = 0; - for (uint32_t i = 0; i < PURE_LISTS_STORED && due < 0; ++i) { - const PureList *list = stored_list(app, i); + for (size_t i = 0; i < pure_slots(app) && due < 0; ++i) { + const PureList *list = stored_list(app, pure_place(app, i)); size_t size = list ? pure_list_size(list) : 0; items += size; if (!list || !app->logged_since[i]) continue; if (app->logged[i] > (size > JOURNAL_MIN ? size : JOURNAL_MIN)) due = (int)i; else if (oldest < 0 || app->logged_since[i] < app->logged_since[oldest]) oldest = (int)i; } - int pick = due >= 0 ? due : pure_log_bytes(app->log) > (items > LOG_KEPT ? items : LOG_KEPT) ? oldest : -1; - if (pick < 0) return NULL; + int slot = due >= 0 ? due : pure_log_bytes(app->log) > (items > LOG_KEPT ? items : LOG_KEPT) ? oldest : -1; + if (slot < 0) return NULL; + uint32_t pick = pure_place(app, (size_t)slot); PureCheckpoint *c = calloc(1, sizeof(*c)); const char *directory = directory_of(app); size_t length = strlen(directory) + 1; if (c && (c->directory = malloc(length))) memcpy(c->directory, directory, length); - if (!c || !c->directory || !(c->snapshot = pure_save_snapshot(app, pick >= PURE_LIST_HEARD ? (uint32_t)pick : UINT32_MAX))) { + if (!c || !c->directory || !(c->snapshot = pure_save_snapshot(app, pick >= PURE_LIST_HEARD ? pick : UINT32_MAX))) { if (c) free(c->directory); free(c); return NULL; } - c->state = (uint32_t)pick; - snprintf(c->name, sizeof(c->name), "%s", stored_name(app, (uint32_t)pick)); + c->state = pick; + snprintf(c->name, sizeof(c->name), "%s", stored_name(app, pick)); c->seq = app->seq; c->header_size = pick == PURE_LIST_OUTBOX ? outbox_header(m, c->seq, c->header) : - pick >= PURE_LIST_HEARD ? runtime_header((uint32_t)pick, c->seq, c->header) : + pick >= PURE_LIST_HEARD ? runtime_header(pick, c->seq, c->header) : image_header(m, m->state_ref[pick], c->seq, c->header); - c->logged = app->logged[pick]; - c->since = app->logged_since[pick]; + c->logged = app->logged[slot]; + c->since = app->logged_since[slot]; app->checkpoint = c; return c; } @@ -712,7 +713,7 @@ PureResult pure_checkpoint_write(PureCheckpoint *c) { void pure_app_checkpointed(PureApp *app, PureCheckpoint *c, PureResult result) { if (!c) return; - uint32_t i = c->state; + size_t i = pure_slot(app, c->state); if (result == PURE_OK && app->checkpoint == c) { /* The image holds every change logged up to its save: those logged * since stay (counted from the save after it). */ @@ -769,7 +770,9 @@ static size_t encode_values(const PureModule *m, const PureValue *values, unsign return at; } -enum { VALUES_BYTES = 4 + PURE_MODULE_STATES * (2 + PURE_MODULE_NAME + 8) }; +/* The values' bytes at most for states of them (and as many for a few on the stack). */ +static size_t values_bytes(uint32_t states) { return 4 + (size_t)states * (2 + PURE_MODULE_NAME + 8); } +enum { FEW_STATES = 64, FEW_VALUES_BYTES = 4 + FEW_STATES * (2 + PURE_MODULE_NAME + 8) }; PURE_COLD PureResult pure_save_open_values(PureApp *app, const PureModule *m, PureValue *values, const int *kept, PureDraft *const *texts, PureList *const *lists) { @@ -1040,12 +1043,14 @@ PURE_COLD PureResult pure_save_open_links(PureApp *app, const PureModule *m, boo * its name and its records. NULL with size 0 when no list changed. */ static unsigned char *list_changes(const PureApp *app, size_t *size) { *size = 0; - for (uint32_t i = 0; i < PURE_LISTS_STORED; ++i) { + for (size_t s = 0; s < pure_slots(app); ++s) { + uint32_t i = pure_place(app, s); const PureList *list = stored_list(app, i); if (list && pure_list_changes(list).size) *size += 1 + strlen(stored_name(app, i)) + 4 + pure_list_changes(list).size; } unsigned char *payload = *size ? malloc(*size) : NULL, *at = payload; - for (uint32_t i = 0; payload && i < PURE_LISTS_STORED; ++i) { + for (size_t s = 0; payload && s < pure_slots(app); ++s) { + uint32_t i = pure_place(app, s); const PureList *list = stored_list(app, i); PureSpan changes = list ? pure_list_changes(list) : (PureSpan){0}; if (!changes.size) continue; @@ -1065,8 +1070,15 @@ PureResult pure_save_commit(PureApp *app, const PureValue *values) { * from what the store has, no save follows it. */ if (app->uncertain) return PURE_CONFLICT; const PureModule *m = app->module; - PureDraft *drafts[2 * PURE_MODULE_STATES + 3]; - uint32_t states[2 * PURE_MODULE_STATES + 3]; + /* A draft a state at most, and three more: on the stack for a few states (027's 4f-2). */ + PureDraft *few_drafts[FEW_STATES + 3], **drafts = few_drafts; + uint32_t few_states[FEW_STATES + 3], *states = few_states; + if (m->states > FEW_STATES && (!(drafts = malloc((m->states + 3) * sizeof(*drafts))) | + !(states = malloc((m->states + 3) * sizeof(*states))))) { + if (drafts != few_drafts) free(drafts); + if (states != few_states) free(states); + return PURE_ALLOCATION; + } size_t count = 0; for (uint32_t i = 0; i < m->states; ++i) { PureDraft *draft = pure_state_transient(m, i) ? NULL : @@ -1081,9 +1093,11 @@ PureResult pure_save_commit(PureApp *app, const PureValue *values) { PureVersion values_before = {0, 0}, links_before = {0, 0}, seq_before = {0, 0}; bool values_changed = false, links_written = false, seq_written = false; PureResult result = PURE_OK; - if (app->stored_values) { - unsigned char encoded[VALUES_BYTES], *stored; - size_t length = encode_values(m, values, encoded), size; + unsigned char few_encoded[FEW_VALUES_BYTES], *encoded = few_encoded; + if (app->stored_values && m->states > FEW_STATES && !(encoded = malloc(values_bytes(m->states)))) result = PURE_ALLOCATION; + if (app->stored_values && result == PURE_OK) { + unsigned char *stored; + size_t length = encode_values(m, values, encoded), size = 0; result = read_whole(app->stored_values, &stored, &size); if (result == PURE_OK) { values_changed = size != length || memcmp(stored, encoded, length); @@ -1149,8 +1163,8 @@ PureResult pure_save_commit(PureApp *app, const PureValue *values) { if (result == PURE_OK) { for (size_t k = 0; k < count; ++k) if (states[k] != UINT32_MAX) app->saved[states[k]] = pure_draft_version(drafts[k]); - for (uint32_t i = 0; i < PURE_LISTS_STORED; ++i) { - PureList *list = stored_list(app, i); + for (size_t i = 0; i < pure_slots(app); ++i) { + PureList *list = stored_list(app, pure_place(app, i)); PureSpan changes = list ? pure_list_changes(list) : (PureSpan){0}; if (!changes.size) continue; app->logged[i] += changes.size; @@ -1171,5 +1185,7 @@ PureResult pure_save_commit(PureApp *app, const PureValue *values) { if (result != PURE_OK) pure_draft_restore(app->stored_seq, seq_before); pure_draft_hold(app->stored_seq, false); } + if (encoded != few_encoded) free(encoded); + if (drafts != few_drafts) free(drafts), free(states); return result; } |
