aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/design/008-module-format.md4
-rw-r--r--prototypes/connections/module.c8
-rw-r--r--prototypes/connections/module.h8
-rw-r--r--prototypes/connections/test-module.c6
4 files changed, 18 insertions, 8 deletions
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md
index 379518d..c800a8a 100644
--- a/docs/design/008-module-format.md
+++ b/docs/design/008-module-format.md
@@ -125,7 +125,7 @@ v5는 값을 가진 채 합류하는 분기(조건식)와, 리스트 항목마�
## 실행
-`PureApp`은 모듈 참조, 상태 값, text 상태 draft, 리스트, 열린 이벤트 하나를 가진다(4,400 B, `PureModule`은 상수
+`PureApp`은 모듈 참조, 상태 값, text 상태 draft, 리스트, 열린 이벤트 하나를 가진다(3,128 B, `PureModule`은 상수
블롭을 포함해 28,600 B). text 상태는 저장소 파일이 없는 draft라 1 MiB 텍스트도 조각 트리로 편집한다. 커서는 바이트
위치이며 항상 글자 경계에 있다. 넣기는 그 위치 이후의 커서를 뒤로(삽입 위치의 커서 포함) 밀고, 지우기는 범위
안의 커서를 범위 처음으로 모은다. 모든 이벤트에서 text draft를 잡아 두고, 실패하면 이벤트 전 버전으로 돌린다.
@@ -182,7 +182,7 @@ text·리스트가 남을 때만 위치를 유지한다.
frame 이벤트는 다음 이벤트나 `pure_app_save`에 함께 들어간다. `pure_app_stop`만 하면 저장하지 않은 변경은 사라진다.
- **지연 저장(그룹 커밋).** `pure_app_defer(app, true)`면 이벤트는 바로 적용되고, 호스트가 입력을 몰아 처리한 뒤
`pure_app_save` 한 번으로 저장한다. 이벤트는 그 뒤 저장이 성공해야 확정이고, 그 전에는 응답을 내보내지 않는
- 것이 호스트의 몫이다. 한 묶음에서 키 하나의 문서는 한 번만 열린다. 같은 키의 두 번째 메시지나 16개 키를 넘는
+ 것이 호스트의 몫이다. 한 묶음에서 키 하나의 문서는 한 번만 열린다. 같은 키의 두 번째 메시지나 256개 키를 넘는
메시지는 먼저 묶음을 저장하므로 문서 리비전은 저장마다 한 칸씩 움직인다(응답에 알린 리비전 = 저장된 리비전).
Pi 5의 SD(ext4)에서 이벤트 600개: 이벤트마다 저장 6,282 ms(10.47 ms/이벤트), 8개씩 973 ms, 64개씩 341 ms,
한 번에 194 ms. `pure-run --store 경로 --batch N`으로 잰다.
diff --git a/prototypes/connections/module.c b/prototypes/connections/module.c
index f8ebdd3..ebb746f 100644
--- a/prototypes/connections/module.c
+++ b/prototypes/connections/module.c
@@ -1038,6 +1038,7 @@ void pure_app_stop(PureApp *app) {
pure_draft_close(app->list_drafts[i]);
}
pure_draft_close(app->stored_values);
+ free(app->pending);
pure_undo_free(&app->undo);
free(app->arena.bytes);
free(app->view_arena.bytes);
@@ -1164,6 +1165,13 @@ PureResult pure_app_message(PureApp *app, uint32_t input, const char *key, int64
PureResult saved = pure_app_save(app);
if (saved != PURE_OK) return saved;
}
+ if (app->pending_count == app->pending_capacity) {
+ unsigned capacity = app->pending_capacity ? 2 * app->pending_capacity : 16;
+ struct PurePending *grown = realloc(app->pending, capacity * sizeof(*grown));
+ if (!grown) return PURE_ALLOCATION;
+ app->pending = grown;
+ app->pending_capacity = capacity;
+ }
PureResult opened = app->data.open(app->data.context, 0, key, &app->document, &app->revision);
if (opened != PURE_OK) { app->document = NULL; return opened; }
if (base >= 0 && base != app->revision) { pure_app_finish(app); return PURE_CONFLICT; }
diff --git a/prototypes/connections/module.h b/prototypes/connections/module.h
index c5d4f52..c9fb606 100644
--- a/prototypes/connections/module.h
+++ b/prototypes/connections/module.h
@@ -19,7 +19,7 @@ enum {
PURE_MODULE_NAME = 32, PURE_MODULE_STRINGS = 32768, PURE_MODULE_HEADER = 40,
PURE_MODULE_FIELDS = 32, PURE_MODULE_COLLECTIONS = 1, PURE_MODULE_CONSTANTS = 64,
PURE_MODULE_CONSTANT_BYTES = 8192, PURE_MODULE_RECORDS = 8, PURE_MODULE_RECORD_FIELDS = 64,
- PURE_RECORD_FIELDS = 16, PURE_MODULE_JOINS = 8, PURE_APP_PENDING = 16
+ PURE_RECORD_FIELDS = 16, PURE_MODULE_JOINS = 8, PURE_APP_PENDING = 256
};
typedef enum {
@@ -147,7 +147,7 @@ typedef struct { unsigned char *bytes; size_t used, capacity; } PureArena;
* 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 saves the burst first). */
+ * message for it, or one past PURE_APP_PENDING keys, saves the burst first). */
typedef struct {
const PureModule *module;
PureData data;
@@ -164,8 +164,8 @@ typedef struct {
double durable_values[PURE_MODULE_STATES];
PureVersion durable_texts[PURE_MODULE_STATES], durable_lists[PURE_MODULE_STATES];
uint64_t durable_ticks, durable_events;
- struct { void *document; char key[65]; bool edited; } pending[PURE_APP_PENDING];
- unsigned pending_count;
+ struct PurePending { void *document; char key[65]; bool edited; } *pending; /* grows to PURE_APP_PENDING */
+ unsigned pending_count, pending_capacity;
PureFault fault;
uint32_t fault_pc;
uint64_t ticks, events;
diff --git a/prototypes/connections/test-module.c b/prototypes/connections/test-module.c
index e1d1ccf..6f48bc8 100644
--- a/prototypes/connections/test-module.c
+++ b/prototypes/connections/test-module.c
@@ -1697,8 +1697,10 @@ static void deferred_messages(void) {
pure_app_stop(&app); /* the last edit was never saved */
CHECK(pure_app_start(&app, &module_a, pure_tree_data(path)) == PURE_OK && app.values[0] == 4 + PURE_APP_PENDING);
CHECK(pure_app_message(&app, 0, "k0", -1, (PureSpan){0}) == PURE_OK && app.revision == 2 && replied(&app, "abc"));
- CHECK(pure_app_message(&app, 0, "m16", -1, (PureSpan){0}) == PURE_NOT_FOUND);
- CHECK(pure_app_message(&app, 0, "m15", -1, (PureSpan){0}) == PURE_OK && replied(&app, "y"));
+ snprintf(key, sizeof(key), "m%d", PURE_APP_PENDING);
+ CHECK(pure_app_message(&app, 0, key, -1, (PureSpan){0}) == PURE_NOT_FOUND);
+ snprintf(key, sizeof(key), "m%d", PURE_APP_PENDING - 1);
+ CHECK(pure_app_message(&app, 0, key, -1, (PureSpan){0}) == PURE_OK && replied(&app, "y"));
pure_app_stop(&app);
remove_store(path);
}