perf(chat): ingest a message batch in one transaction
Ingesting a scan's worth of chat messages persisted each new message with its own append() call, so a batch of fresh messages opened and committed one SQLite transaction per row. - A new appendBatch persists many messages in a single transaction, using the same INSERT OR IGNORE dedup key as append() and preserving input order so load()'s rowid ordering is unchanged. - Every message is serialized and encrypted before the transaction opens, so a message with a non-UTF-8 body is skipped on its own without leaving a transaction open; the valid siblings still persist. - Ingest collects the newly stored messages and writes them once after the loop instead of per message. It is inert (returns 0) while locked or on empty input. Tests cover a batch insert, dedup on re-insert, empty input, bad-UTF-8 isolation with a valid sibling and a following append(), insert order, and the locked no-op. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,7 @@ int ChatService::ingest(const std::vector<HushChatTransactionMetadata>& metadata
|
||||
const std::string myPubKey = chatIdentityPublicKeyHex(identity_);
|
||||
|
||||
int added = 0;
|
||||
std::vector<ChatMessage> fresh; // persisted once after the loop (one transaction)
|
||||
for (const auto& meta : metadata) {
|
||||
// Already stored: append would refuse it. Every scan re-sends the whole history, so this skips the
|
||||
// decrypt for all but the new messages.
|
||||
@@ -107,13 +108,14 @@ int ChatService::ingest(const std::vector<HushChatTransactionMetadata>& metadata
|
||||
// session loadFromDatabase() repopulates the store, so re-scanning the chain re-ingests but
|
||||
// the store dedup prevents a duplicate write.
|
||||
if (store_.append(message)) {
|
||||
if (db_) db_->append(message);
|
||||
fresh.push_back(message);
|
||||
++added;
|
||||
// Every ingested message is incoming — report its cid so the caller can notify without
|
||||
// relying on a seen-watermark delta (which block-time vs wall-clock skew can swallow).
|
||||
if (newIncomingCids) newIncomingCids->push_back(message.conversation_id);
|
||||
}
|
||||
}
|
||||
if (db_ && !fresh.empty()) db_->appendBatch(fresh);
|
||||
return added;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user