aboutsummaryrefslogtreecommitdiffstats
path: root/core/module.h
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-18 19:30:16 +0100
committereunhhu <[email protected]>2026-10-18 19:30:16 +0100
commitb22b8c3f6c5378b47c36370225d7c41d4394bb7c (patch)
treed1a3cbf1b0e718f0acafa08ec6741761f08e5dd5 /core/module.h
parente8b3499289022c8729900a58ed218d961a85fec8 (diff)
downloadpure-b22b8c3f6c5378b47c36370225d7c41d4394bb7c.tar.gz
pure-b22b8c3f6c5378b47c36370225d7c41d4394bb7c.zip
Module format v7, 027's 4b-2: keyed documents gone, a keyed list of records holding bytes doing their work: no collections table, DOC, DOC_SIZE or REPLACE (106 opcodes now 103, those from LEN on moved up), keyed messages or a base revision (pure_app_message takes an input and a payload), no PureData document callbacks (a data host opens states and saves them together), no burst by document key; the header 38 bytes; pure-edit-module gone; pure-serve without /objects, ETag, If-Match and If-None-Match, 412 or an app a thread for a module of documents alone (one without states or outputs runs so); a hole closed: an instruction in no handler's, view's or function's block was never verified yet the load's later passes read its arguments (a damaged module read out of bounds once the header moved what the mutation test damaged), now blanked to CONST 0; checks moved: server_documents (DOCS_SOURCE, keyed byte documents with the app's revision, against a Python model, one and three connection threads, a restart) in place of the parity with editor.pure, pipelining and bursts through kill -9 on its inputs and views, the lent budget on a text view (lending a document's read is server_lent_views' already), clocks and tokens on it; message tests without a document host; the HTTP benchmark's document suite runs the earlier document server and the baselines alone; the count harness builds against either message API (runs.sh build: -DPURE_KEYED_MESSAGES before 4b); counts: b33 against b32 with batches within 0.002% but BFS -0.33%, without batches BFS +0.63%, knapsack +0.52%, join +0.38%; the bank's queries (s32 on a v6 module, s33 on v7) field +0.68%, found +0.44%, large +0.42%, the rest within 0.13%; 008 as v7, 027's 4b-2 as made and 4c designed
Diffstat (limited to 'core/module.h')
-rw-r--r--core/module.h81
1 files changed, 23 insertions, 58 deletions
diff --git a/core/module.h b/core/module.h
index d23cb49..d155b41 100644
--- a/core/module.h
+++ b/core/module.h
@@ -8,7 +8,7 @@
#include <stddef.h>
#include <stdint.h>
-/* Pure module format v6 (docs/design/008-module-format.md). A toolchain such
+/* Pure module format v7 (docs/design/008-module-format.md). A toolchain such
* as aup produces it; Pure verifies it completely before anything executes:
* operand types (including which text a cursor and which list an index
* belongs to), stack heights and the stack at every join, forward-only
@@ -16,10 +16,10 @@
enum {
PURE_MODULE_STATES = 32, PURE_MODULE_INPUTS = 32, PURE_MODULE_VIEWS = 64,
PURE_MODULE_HANDLERS = 64, PURE_MODULE_CODE = 65535, PURE_MODULE_STACK = 64,
- PURE_MODULE_NAME = 32, PURE_MODULE_STRINGS = 32768, PURE_MODULE_HEADER = 40,
- PURE_MODULE_FIELDS = 64, PURE_MODULE_COLLECTIONS = 1, PURE_MODULE_CONSTANTS = 4096,
+ PURE_MODULE_NAME = 32, PURE_MODULE_STRINGS = 32768, PURE_MODULE_HEADER = 38,
+ PURE_MODULE_FIELDS = 64, PURE_MODULE_CONSTANTS = 4096,
PURE_MODULE_CONSTANT_BYTES = 1 << 20, PURE_MODULE_RECORDS = 16, PURE_MODULE_RECORD_FIELDS = 128,
- PURE_RECORD_FIELDS = 16, PURE_MODULE_JOINS = 8, PURE_APP_PENDING = 256
+ PURE_RECORD_FIELDS = 16, PURE_MODULE_JOINS = 8
};
typedef enum {
@@ -27,7 +27,7 @@ typedef enum {
PURE_OP_DIV, PURE_OP_NEG, PURE_OP_LT, PURE_OP_LE, PURE_OP_GT, PURE_OP_GE,
PURE_OP_EQ, PURE_OP_NE, PURE_OP_AND, PURE_OP_OR, PURE_OP_NOT, PURE_OP_MIN,
PURE_OP_MAX, PURE_OP_CLAMP, PURE_OP_STORE, PURE_OP_JZ, PURE_OP_JMP,
- PURE_OP_FIELD, PURE_OP_DOC, PURE_OP_DOC_SIZE, PURE_OP_LEN, PURE_OP_REPLACE,
+ PURE_OP_FIELD, PURE_OP_LEN,
PURE_OP_REPLY, PURE_OP_REQUIRE,
PURE_OP_TEXT_CONST, PURE_OP_TEXT_LOAD, PURE_OP_TEXT_INPUT, PURE_OP_NUM_TEXT,
PURE_OP_CONCAT, PURE_OP_CHARS, PURE_OP_LINES, PURE_OP_TEXT_BYTES,
@@ -126,8 +126,8 @@ enum { PURE_FORMAT_WIDTH = 8, PURE_FORMAT_ZEROS = 1 << 16, PURE_FORMAT_FORM = 17
* locals (0 as it begins), and its own of what the function's code names:
* values held by name (empty), an event's lists (empty) and registers (bound
* to none); the caller's are as they were when the call returns. A function
- * runs as a handler's code does but for a message (no field, document or
- * reply); a handler and the functions run CALL (not a view), and a walk around
+ * runs as a handler's code does but for a message (no field or reply); a
+ * handler and the functions run CALL (not a view), and a walk around
* a call keeps to what the callee changes as it keeps to its own block's
* changes. Calls nest as deep as the event's room allows: each counts its
* frame's bytes there (MEMORY past it) and its block's length as work.
@@ -308,7 +308,6 @@ typedef struct {
typedef struct { char name[PURE_MODULE_NAME]; uint8_t type; uint16_t rows; uint32_t offset; } PureField;
typedef struct {
uint8_t kind;
- bool keyed;
uint16_t field_start, field_count;
uint32_t prefix; /* fixed payload bytes before the variable fields */
uint32_t period; /* a timer's, in milliseconds */
@@ -339,12 +338,11 @@ typedef struct { uint8_t lower_relation, upper_relation; PureBlock lower, upper;
_Static_assert(PURE_MODULE_STATES <= 32, "a state is a bit of PureApp.counted");
typedef struct {
- uint16_t states, inputs, views, handlers, fields, collections, constants, records, record_fields;
+ uint16_t states, inputs, views, handlers, fields, constants, records, record_fields;
uint32_t code_count;
char state_names[PURE_MODULE_STATES][PURE_MODULE_NAME];
char input_names[PURE_MODULE_INPUTS][PURE_MODULE_NAME];
char view_names[PURE_MODULE_VIEWS][PURE_MODULE_NAME];
- char collection_names[PURE_MODULE_COLLECTIONS][PURE_MODULE_NAME];
char input_keys[PURE_MODULE_INPUTS][PURE_MODULE_NAME];
uint8_t state_type[PURE_MODULE_STATES];
uint16_t state_ref[PURE_MODULE_STATES]; /* text: constant; cursor: text; list: record; index: list */
@@ -449,27 +447,13 @@ int pure_module_position(const PureModule *, uint32_t view);
* state), or -1: a host may lend its stored extents instead of copying. */
int pure_module_text_state(const PureModule *, uint32_t view);
-/* Keyed collections live in a data host (for example the tree store). One
- * event opens at most one document, the message's key, at its current
- * version; edits stay in that working version until the event commits it.
- * A version's bytes field is the value's size. */
+/* A data host keeps the app's states (for example the tree store); without one (all of it NULL) they live in memory
+ * alone. state opens a runtime-owned value by name as a draft (a missing one is empty at revision 0); save publishes
+ * the given drafts together, all or nothing. */
typedef struct {
void *context;
- PureResult (*open)(void *context, uint32_t collection, const char *key,
- void **document, int64_t *revision);
- PureVersion (*version)(void *context, void *document);
- PureResult (*read)(void *context, void *document, PureVersion, size_t offset, size_t length,
- bool (*visit)(void *, PureSpan), void *visit_context);
- PureResult (*splice)(void *context, void *document, size_t offset, size_t remove, PureSpan insert);
- PureResult (*commit)(void *context, void *document, int64_t *revision);
- void (*close)(void *context, void *document);
- /* Optional: the host keeps the app's states. state opens a runtime-owned
- * value by name as a draft (a missing one is empty at revision 0); save
- * publishes the given documents and state drafts together, all or
- * nothing, and names each document's new revision. */
PureResult (*state)(void *context, const char *name, PureDraft **out);
- PureResult (*save)(void *context, void *const *documents, size_t document_count, PureDraft *const *states,
- size_t count, int64_t *revisions);
+ PureResult (*save)(void *context, PureDraft *const *states, size_t count);
/* Optional, with state and save: the directory where the app's lists are
* kept, their images and the log of their changes (core/log.h); without
* one, list states are not stored. */
@@ -477,7 +461,7 @@ typedef struct {
} PureData;
/* A byte or text value inside one event or view: a range of the payload, a
- * document or text version, a module constant, a copy or the event's arena. */
+ * text version, a module constant, a copy or the event's arena. */
typedef struct { uint8_t source; uint16_t owner; PureVersion version; uint64_t offset, length; } PureBytes;
typedef struct { unsigned char *bytes; size_t used, capacity; } PureArena;
@@ -487,13 +471,11 @@ typedef struct { unsigned char *bytes; size_t used, capacity; } PureArena;
* (or 0 in an empty list). Every event is atomic: on failure nothing changes.
*
* Saving. When the data host keeps states the app starts from the stored
- * ones. A save publishes, in one commit, the documents edited by messages and
- * the states changed since the last save; if it fails, every event since the
- * last save is undone. By default each key, text and message event saves
- * before it returns (a frame waits for the next one). Deferred, events apply
- * at once and a host saves a burst with one commit: an event is durable once
- * a later save succeeds, and each key's document joins a burst once (a second
- * message for it, or one past PURE_APP_PENDING keys, saves the burst first). */
+ * ones. A save publishes, in one commit, the states changed since the last
+ * save; if it fails, every event since the last save is undone. By default
+ * each key, text and message event saves before it returns (a frame waits for
+ * the next one). Deferred, events apply at once and a host saves a burst with
+ * one commit: an event is durable once a later save succeeds. */
/* The runtime's lists' places among the stored lists' records (PureApp):
* the numbers heard, and the outbox. */
enum { PURE_LIST_HEARD = PURE_MODULE_STATES, PURE_LIST_OUTBOX, PURE_LISTS_STORED };
@@ -521,20 +503,12 @@ typedef struct {
bool uncertain; /* a save may or may not be stored: none follows until a start */
PureDraft *stored_values; /* numbers, cursors and indices, when kept */
PureVersion saved[PURE_MODULE_STATES]; /* text and list versions at the last save */
- /* Events since the last save: what a failed save returns to, and the
- * documents messages opened (held until the save). */
+ /* Events since the last save: what a failed save returns to. */
bool deferred, open;
PureValue durable_values[PURE_MODULE_STATES];
PureVersion durable_texts[PURE_MODULE_STATES];
size_t durable_lists[PURE_MODULE_STATES]; /* each stored list's journal length */
uint64_t durable_ticks, durable_events;
- struct PurePending { void *document; char key[65]; bool edited; } *pending; /* grows to PURE_APP_PENDING */
- unsigned pending_count, pending_capacity;
- /* The pending documents by key, so a message finds its key in one look:
- * open addressing over the key's hash, a slot holding one more than the
- * document's place in pending (0: none). */
- uint16_t pending_index[2 * PURE_APP_PENDING];
- bool document_pending; /* the current event's document is among them */
PureFault fault;
uint32_t fault_pc;
size_t memory; /* the budget of what the states hold (0: none): pure_app_memory */
@@ -553,12 +527,10 @@ typedef struct {
struct PureRows { uint32_t table; uint64_t changes, given; size_t *items, count, capacity; PureFault fault; } *rows; /* a filtered table's items */
unsigned row_tables;
/* Current message or text event, kept until pure_app_finish. */
- void *document;
PureSpan payload;
bool has_reply;
PureBytes reply;
unsigned char *copied;
- int64_t revision;
PureArena arena, view_arena;
/* Links (runtime-owned, saved with the states): the outbox, messages sent
* on outputs and not trimmed, in the order sent, a list of {output (its
@@ -612,11 +584,8 @@ PureResult pure_app_start(PureApp *, const PureModule *, PureData data);
/* Publish every change since the last save in one commit, or undo them all. */
PureResult pure_app_save(PureApp *);
/* Defer saving to pure_app_save (false: save after each event). Needs a data
- * host that saves documents together (PureData.save). */
+ * host that saves together (PureData.save). */
bool pure_app_defer(PureApp *, bool deferred);
-/* Whether key's document is in the unsaved burst: a message for it would
- * save the burst first. */
-bool pure_app_pending(const PureApp *, const char *key);
/* Leaves unsaved frame changes unsaved: call pure_app_save first to keep them. */
void pure_app_stop(PureApp *);
PureResult pure_app_frame(PureApp *);
@@ -629,18 +598,14 @@ PureResult pure_app_input(PureApp *, uint32_t input, PureEdge);
PureResult pure_app_point(PureApp *, uint32_t state, size_t position);
/* Deliver committed text (for example from an input method). Not UTF-8: invalid. */
PureResult pure_app_text(PureApp *, uint32_t input, PureSpan text);
-/* Deliver a message. base is the revision the sender edited, or -1 for none;
- * a handler that edits the document needs one. payload stays alive until
- * pure_app_finish. On return app->revision is the document's revision
- * (deferred: the revision the next save gives it). */
-PureResult pure_app_message(PureApp *, uint32_t input, const char *key, int64_t base, PureSpan payload);
+/* Deliver a message. payload stays alive until pure_app_finish. */
+PureResult pure_app_message(PureApp *, uint32_t input, PureSpan payload);
/* The same, with the variable fields where the host found them: field f
* starts at placed[2f] in payload and has placed[2f + 1] bytes (entries of
* fixed fields are not read, nor are the variable fields' lengths in the
* prefix). A host that parsed a request in place passes the fields' bytes
* where they are. */
-PureResult pure_app_message_fields(PureApp *, uint32_t input, const char *key, int64_t base, PureSpan payload,
- const uint32_t *placed);
+PureResult pure_app_message_fields(PureApp *, uint32_t input, PureSpan payload, const uint32_t *placed);
/* Visit the reply of the last message in order, without copying, until the
* next event (deferred: copy it before a later save too). */
PureResult pure_app_reply(const PureApp *, bool (*visit)(void *, PureSpan), void *context);