audit 3: every per-message question of the send log has its index
test / test (push) Canceled after 0s
test / test (push) Canceled after 0s
Migration 0010 (DDL only; 0009 went to stage 2b). EXPLAIN QUERY PLAN of
every send_log statement showed, beyond M2 as written (stage 2 had already
moved the by-domain counts onto (domain_id, created_at)):
- the tailer's sweep of open rows (every 5 min) and its count scanned the
table: partial idx_send_log_open (created_at) WHERE status IN ('queued',
'deferred'), the statuses literal in the statements, ORDER BY +id (else
SQLite walks the table in id order to skip a sort);
- AttachRefusalLine's NOT EXISTS (... refusal_line = ?1) scanned the table
for every refusal line: partial idx_send_log_refusal_line, the query
carrying the index's WHERE; its row found by idx_send_log_rejected
(status literal, +queue_id) instead of every refusal without a queue id;
- an application's level-2 count went through its domain's index:
+domain_id in appByLogin;
- a page of one domain's or one application's log sorted all of it:
idx_send_log_domain_id, idx_send_log_app_login (id order; several domains
still sort, top-N). idx_send_log_domain stays for the global filter.
The statements are constants and builders (countMessagesQuery,
peakPerHourQuery, listOpenQuery, countOpenQuery, sendLogPageQuery,
attachRefusalLineQuery, limitRefusalsQuery) and
TestSendLogQueriesUseTheirIndexes explains exactly those: the index each
must use, no SCAN of send_log, no sort where none is wanted; the literal
statuses checked against the constants. It replaces the hand-written plan
check of TestLimitRefusalsSince.
Tested on the test server: go vet + go test of 24 packages, make e2e (all
pass) on this tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1092,12 +1092,28 @@ those after it move up one patch number each.
|
||||
untouched, no `-wal`), a damaged key named; the domain import of a cut
|
||||
plain export, a cut and an altered `.spde` (each refused, nothing
|
||||
created). The CLI's `-decrypt -o` is step 3.
|
||||
- [ ] **Indexes**: `idx_send_log_domain_created_at (domain_id, created_at)` —
|
||||
- [x] **Indexes**: `idx_send_log_domain_created_at (domain_id, created_at)` —
|
||||
on the id column stage 2 adds, replacing `idx_send_log_domain`;
|
||||
partial `idx_send_log_queued (created_at) WHERE status = 'queued'`;
|
||||
consider `(domain, id)` for the scoped page. Migration `0009` DDL only;
|
||||
`TestLimitRefusalsSince`-style EXPLAIN tests against the **real** query
|
||||
strings. — **Opus**
|
||||
*Done 2026-10-15,* migration `0010` (0009 went to stage 2b). Stage 2
|
||||
already counted by `(domain_id, created_at)`; `idx_send_log_domain` stays,
|
||||
the global log's filter by name reads its page off it in id order. The
|
||||
plans of every `send_log` statement showed four more: the sweep now asks
|
||||
for queued *and* deferred rows - `idx_send_log_open (created_at) WHERE
|
||||
status IN ('queued', 'deferred')`, the statuses literal and `ORDER BY +id`
|
||||
(else SQLite walks the table in id order); `NOT EXISTS (... refusal_line
|
||||
= ?1)` of stage 2b scanned the table per refusal line - partial
|
||||
`idx_send_log_refusal_line`, and its row is found by
|
||||
`idx_send_log_rejected` (status literal, `+queue_id`); the application's
|
||||
level-2 count went by the domain's index - `+domain_id`; a page of one
|
||||
domain or one application - `idx_send_log_domain_id`,
|
||||
`idx_send_log_app_login` (id order, no sort; several domains still sort,
|
||||
top-N). The statements are constants/builders the test explains
|
||||
(`TestSendLogQueriesUseTheirIndexes`, which replaces the hand-written
|
||||
plan check of `TestLimitRefusalsSince`).
|
||||
- [ ] **CLI backup**: open the source `mode=ro`, refuse a missing file; password
|
||||
floor of 12 shared with the panel (`validate.MinSecretFilePasswordLen`);
|
||||
`-decrypt -o` verifies the password (first chunk) before opening the
|
||||
|
||||
Reference in New Issue
Block a user