summaryrefslogtreecommitdiff
path: root/src/storage
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-07-04 18:09:47 +0900
committertanaka takashi <isazaka@gmail.com>2026-07-04 18:09:47 +0900
commit5ac1c7adb7eeefd68dbed1bf6cfbe77cd348f257 (patch)
tree863c2baabb16bf5bf4c7f81929321ed922d9e35b /src/storage
parent0634f2048c7c9a474aab1d8104b964b3bf70a064 (diff)
fix(restart): skip dangling relations on memory index rebuild; prune on compaction
- Fix restart exit code 1 caused by missing relation targets after delete+rebuild - memory_index_build: skip relations whose targets no longer exist - store_rebuild / write_snapshot: prune dangling relations and sources - Remove diagnostic fprintf from server.c and context.c - Enable restart resume test in mcp_protocol_test.py - Add scripts/benchmark_p1_cp.py and run 10k/50k import/export round-trip - Mark P1-CP, P7-001, P7-CP complete in development-plan.md
Diffstat (limited to 'src/storage')
-rw-r--r--src/storage/store.c72
1 files changed, 70 insertions, 2 deletions
diff --git a/src/storage/store.c b/src/storage/store.c
index 5701578..060c6f6 100644
--- a/src/storage/store.c
+++ b/src/storage/store.c
@@ -645,6 +645,72 @@ metadata_targets_valid(tiny_store_t *store, const char *self_id, const tiny_meta
return true;
}
+static bool
+prune_metadata_references(tiny_store_t *store, tiny_message_t *message)
+{
+ size_t index, write_index;
+ bool changed = false;
+ if (!store || !message)
+ {
+ return false;
+ }
+ /* Prune relations whose targets are deleted or missing. */
+ for (index = 0, write_index = 0; index < message->metadata.relation_count; ++index)
+ {
+ tiny_store_entry_t *target = find_entry(store, message->metadata.relations[index].message_id);
+ if (target && !target->deleted)
+ {
+ if (write_index != index)
+ {
+ message->metadata.relations[write_index] = message->metadata.relations[index];
+ }
+ write_index++;
+ }
+ else
+ {
+ changed = true;
+ }
+ }
+ if (changed)
+ {
+ message->metadata.relation_count = write_index;
+ if (write_index == 0)
+ {
+ free(message->metadata.relations);
+ message->metadata.relations = NULL;
+ }
+ }
+ /* Prune sources whose targets are deleted or missing. */
+ changed = false;
+ for (index = 0, write_index = 0; index < message->metadata.source_count; ++index)
+ {
+ tiny_store_entry_t *target = find_entry(store, message->metadata.source_message_ids[index]);
+ if (target && !target->deleted)
+ {
+ if (write_index != index)
+ {
+ message->metadata.source_message_ids[write_index]
+ = message->metadata.source_message_ids[index];
+ }
+ write_index++;
+ }
+ else
+ {
+ changed = true;
+ }
+ }
+ if (changed)
+ {
+ message->metadata.source_count = write_index;
+ if (write_index == 0)
+ {
+ free(message->metadata.source_message_ids);
+ message->metadata.source_message_ids = NULL;
+ }
+ }
+ return true;
+}
+
static tiny_store_status_t
prepare_update(tiny_store_t *store,
tiny_store_entry_t *entry,
@@ -1262,7 +1328,8 @@ write_snapshot(tiny_store_t *store)
{
unsigned char prefix[16], *payload = NULL;
uint32_t length = 0;
- if (!serialize_put(&store->entries[index].message, &payload, &length))
+ if (!prune_metadata_references(store, &store->entries[index].message)
+ || !serialize_put(&store->entries[index].message, &payload, &length))
{
ok = false;
break;
@@ -1773,7 +1840,8 @@ tiny_store_rebuild(tiny_store_t *store, tiny_rebuild_report_t *report)
{
unsigned char *payload = NULL;
uint32_t length = 0;
- if (!serialize_put(&store->entries[read_index].message, &payload, &length))
+ if (!prune_metadata_references(store, &store->entries[read_index].message)
+ || !serialize_put(&store->entries[read_index].message, &payload, &length))
{
status = TINY_STORE_NO_MEMORY;
break;