@bobfrankston/rmfmail 1.2.16 → 1.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/packages/mailx-imap/index.d.ts.map +1 -1
- package/packages/mailx-imap/index.js +15 -23
- package/packages/mailx-imap/index.js.map +1 -1
- package/packages/mailx-imap/index.ts +15 -23
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +11 -8
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +11 -8
- package/packages/mailx-store/db.d.ts.map +1 -1
- package/packages/mailx-store/db.js +20 -1
- package/packages/mailx-store/db.js.map +1 -1
- package/packages/mailx-store/db.ts +19 -1
- package/packages/mailx-store/package.json +1 -1
|
@@ -488,6 +488,18 @@ export class MailxDB {
|
|
|
488
488
|
try {
|
|
489
489
|
this.db.exec("CREATE INDEX IF NOT EXISTS idx_messages_thread_id ON messages(account_id, thread_id)");
|
|
490
490
|
} catch { /* already exists */ }
|
|
491
|
+
// (account_id, message_id) composite — THE hot-path lookup. upsertMessage's
|
|
492
|
+
// move-detect and computeThreadId both query `WHERE account_id=? AND
|
|
493
|
+
// message_id=?`. The old idx_messages_message_id is on message_id ALONE, so
|
|
494
|
+
// with an account_id predicate the planner instead picks an account_id-only
|
|
495
|
+
// index and SCANS every row for the account (Bob's bobma INBOX = 136k rows).
|
|
496
|
+
// One new-message upsert ran several such scans (one per reference); a
|
|
497
|
+
// 50-message batch = the 62-SECOND write txn the slow-txn logger caught
|
|
498
|
+
// (2026-06-16) — which held the write lock and starved every other writer.
|
|
499
|
+
// A leading composite turns each into an O(log n) seek.
|
|
500
|
+
try {
|
|
501
|
+
this.db.exec("CREATE INDEX IF NOT EXISTS idx_messages_acct_msgid ON messages(account_id, message_id)");
|
|
502
|
+
} catch { /* already exists */ }
|
|
491
503
|
// is_replied: set when ANY other message in this account has in_reply_to
|
|
492
504
|
// pointing at this row's message_id. Primary source of truth for the ↩
|
|
493
505
|
// marker — \Answered is plan B (some servers strip it, Gmail labels
|
|
@@ -2900,7 +2912,13 @@ export class MailxDB {
|
|
|
2900
2912
|
// straddling an `await` — the wrapper is nesting-safe (savepoints)
|
|
2901
2913
|
// so it can't collide with the sync backfill's own transactions
|
|
2902
2914
|
// when the two interleave across the yield below.
|
|
2903
|
-
|
|
2915
|
+
// 100, not 500: each chunk is one held write transaction, and the
|
|
2916
|
+
// slow-txn logger caught these running 2+ SECONDS apiece under WAL
|
|
2917
|
+
// pressure — long enough to lock out the sync worker's storeMessages
|
|
2918
|
+
// ("database is locked"). Smaller chunks = shorter lock holds + a
|
|
2919
|
+
// yield (below) after each, giving the worker write windows (Bob
|
|
2920
|
+
// 2026-06-16, live debug).
|
|
2921
|
+
const WRITE_CHUNK = 100;
|
|
2904
2922
|
const entries = [...agg.entries()];
|
|
2905
2923
|
for (let i = 0; i < entries.length; i += WRITE_CHUNK) {
|
|
2906
2924
|
const slice = entries.slice(i, i + WRITE_CHUNK);
|