diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-07-04 16:22:35 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-07-04 16:22:35 +0900 |
| commit | eb5e9d9f37bda7d78f69614da70402357794168a (patch) | |
| tree | 608dd61d8b4ca989df505e9777a8b95f4f17b06d /src/storage | |
| parent | 1a6a2e7f8572415d435c056dc9947d6d08eb1862 (diff) | |
feat(P1-002): add offline JSONL import via import_messages MCP tool
- implement `import_messages` MCP tool parsing manifest + PUT/DEL JSONL
- atomic store replacement under lock with overwrite/reject conflict policies
- add `include_deleted` to read_messages export view for full round-trip
- register new tool in MCP registry and update protocol test expectations
- update docs/development-plan.md and docs/implementation-status.md
Debug/Release/ASan 15/15 CTest pass
Diffstat (limited to 'src/storage')
| -rw-r--r-- | src/storage/store.c | 99 | ||||
| -rw-r--r-- | src/storage/store.h | 19 |
2 files changed, 118 insertions, 0 deletions
diff --git a/src/storage/store.c b/src/storage/store.c index a964f60..45621d1 100644 --- a/src/storage/store.c +++ b/src/storage/store.c @@ -1921,6 +1921,105 @@ tiny_store_health(const tiny_store_t *store, tiny_store_health_t *health) snprintf(health->last_error, sizeof(health->last_error), "%s", store->last_error); } +tiny_store_status_t +tiny_store_import(tiny_store_t *store, + const tiny_import_record_t *records, + size_t record_count, + tiny_import_policy_t policy, + size_t *imported_count, + size_t *rejected_count) +{ + tiny_store_entry_t *saved_entries; + size_t saved_count, saved_capacity, index; + tiny_rebuild_report_t report; + tiny_store_status_t status = TINY_STORE_OK; + if (!store || !records || !imported_count || !rejected_count) + { + return TINY_STORE_IO_ERROR; + } + *imported_count = 0; + *rejected_count = 0; + saved_entries = store->entries; + saved_count = store->entry_count; + saved_capacity = store->entry_capacity; + store->entries = NULL; + store->entry_count = 0; + store->entry_capacity = 0; + for (index = 0; index < record_count && status == TINY_STORE_OK; ++index) + { + const tiny_import_record_t *record = &records[index]; + tiny_store_entry_t *existing = find_entry(store, record->message.message_id); + if (existing != NULL && policy == TINY_IMPORT_REJECT && !record->deleted + && !existing->deleted) + { + (*rejected_count)++; + continue; + } + if (existing != NULL) + { + tiny_message_free(&existing->message); + existing->deleted = record->deleted; + existing->sequence = (uint64_t)record->message.timestamp_ms; + existing->message = record->message; + (*imported_count)++; + } + else + { + if (!ensure_entries(store)) + { + status = TINY_STORE_NO_MEMORY; + break; + } + memset( + &store->entries[store->entry_count], 0, sizeof(store->entries[store->entry_count])); + store->entries[store->entry_count].deleted = record->deleted; + store->entries[store->entry_count].sequence = (uint64_t)record->message.timestamp_ms; + store->entries[store->entry_count].message = record->message; + store->entry_count++; + (*imported_count)++; + } + } + if (status == TINY_STORE_OK) + { + store->update_records = 0; + store->dead_bytes = 0; + store->snapshot_valid = false; + store->recovered_tail = false; + status = tiny_store_rebuild(store, &report); + if (status != TINY_STORE_OK) + { + for (index = 0; index < store->entry_count; ++index) + { + tiny_message_free(&store->entries[index].message); + } + free(store->entries); + store->entries = saved_entries; + store->entry_count = saved_count; + store->entry_capacity = saved_capacity; + } + else + { + for (index = 0; index < saved_count; ++index) + { + tiny_message_free(&saved_entries[index].message); + } + free(saved_entries); + } + } + else + { + for (index = 0; index < store->entry_count; ++index) + { + tiny_message_free(&store->entries[index].message); + } + free(store->entries); + store->entries = saved_entries; + store->entry_count = saved_count; + store->entry_capacity = saved_capacity; + } + return status; +} + size_t tiny_store_entry_count(const tiny_store_t *store) { diff --git a/src/storage/store.h b/src/storage/store.h index 3ddd24d..adeae35 100644 --- a/src/storage/store.h +++ b/src/storage/store.h @@ -77,7 +77,26 @@ tiny_store_status_t tiny_store_update(tiny_store_t *store, const tiny_message_patch_t *patch, tiny_message_t *updated, bool *changed); + +typedef enum tiny_import_policy +{ + TINY_IMPORT_OVERWRITE = 0, + TINY_IMPORT_REJECT +} tiny_import_policy_t; + +typedef struct tiny_import_record +{ + bool deleted; + tiny_message_t message; +} tiny_import_record_t; + tiny_store_status_t tiny_store_rebuild(tiny_store_t *store, tiny_rebuild_report_t *report); +tiny_store_status_t tiny_store_import(tiny_store_t *store, + const tiny_import_record_t *records, + size_t record_count, + tiny_import_policy_t policy, + size_t *imported_count, + size_t *rejected_count); void tiny_store_health(const tiny_store_t *store, tiny_store_health_t *health); size_t tiny_store_entry_count(const tiny_store_t *store); |
