Maintain scoped operation history totals without table scans

This commit is contained in:
2026-10-06 14:53:51 -04:00
parent b17673720b
commit 703d414c7a
5 changed files with 89 additions and 1 deletions
+39
View File
@@ -43,6 +43,40 @@ async function operationHistory() {
}
describe('host operation history', () => {
it('maintains exact scoped totals through receipts, expiration, rollback, deletion and reopening without recounting history', async () => {
const api = await operationHistory();
const { importantOperationSql } = await import('../../src/lib/server/hosts/observations.js');
const { closeDb, db } = await import('../../src/lib/server/db/index.js');
const ids = Array.from({ length: 35 }, (_, i) => api.add(i % 2 ? 'instance.inspect' : 'instance.restart', { state: 'pending' }));
const verify = () => {
for (const host of [undefined, api.first.id, api.second.id]) for (const server of [undefined, 'server-one']) {
for (const filter of ['all', 'routine', 'important'] as const) {
const where = ['o.history_expired_at IS NULL']; const args: string[] = [];
if (host) { where.push('o.host_id=?'); args.push(host); }
if (server) { where.push('o.server_name=?'); args.push(server); }
if (filter !== 'all') where.push(filter === 'routine' ? 'o.routine=1' : importantOperationSql);
const expected = db().prepare(`SELECT COUNT(*) total FROM ec_host_operations o WHERE ${where.join(' AND ')}`).get(...args) as { total: number };
expect(api.listHostOperationHistory(1, filter, { host, server }).total).toBe(expected.total);
}
}
};
verify();
for (const [index, id] of ids.entries()) api.reportHostOperationStatus(api.first.id, id,
index % 3 ? { state: 'completed', result: { healthy: index % 5 !== 0 } } : { state: 'failed', error: 'failure' });
api.handle.prepare("UPDATE ec_host_operations SET server_name='server-one',host_id=? WHERE rowid%2=0").run(api.second.id);
api.handle.prepare('UPDATE ec_host_operations SET history_expired_at=? WHERE rowid%4=0').run(new Date().toISOString());
api.handle.exec('DELETE FROM ec_host_operation_events WHERE operation_id IN (SELECT id FROM ec_host_operations WHERE rowid%7=0); DELETE FROM ec_host_operations WHERE rowid%7=0');
expect(() => api.handle.transaction(() => { api.handle.exec('DELETE FROM ec_host_operation_events; DELETE FROM ec_host_operations'); throw new Error('rollback'); })()).toThrow('rollback');
verify(); closeDb(); verify();
const prepare = vi.spyOn(db(), 'prepare');
api.listHostOperationHistory(1); api.listHostOperationHistory(2);
expect(prepare.mock.calls.some(([sql]) => /COUNT\(/i.test(sql))).toBe(false);
const count = prepare.mock.calls.find(([sql]) => sql.includes('FROM ec_host_operation_history_counts'))![0];
expect(db().prepare('EXPLAIN QUERY PLAN ' + count).all('', '')).toEqual(expect.arrayContaining([
expect.objectContaining({ detail: expect.stringContaining('USING PRIMARY KEY') })
]));
});
it('scopes counts and pages to one host or server and preserves deleted-host history', async () => {
const api = await seedHistory(90);
api.handle.prepare("UPDATE ec_host_operations SET server_name='server-one' WHERE host_id=?").run(api.first.id);
@@ -223,6 +257,11 @@ describe('host operation history', () => {
const manual = api.add('rcon.execute', { payload: { command: 'say command-secret' } });
const unsafe = api.add('files.read', { payload: { path: '../private-secret' } });
api.handle.exec(`DROP INDEX ec_host_operations_routine_history;
DROP TRIGGER operation_history_count_insert;
DROP TRIGGER operation_history_count_delete;
DROP TRIGGER operation_history_count_update;
DROP TABLE ec_host_operation_history_counts;
DELETE FROM ec_host_schema_migrations WHERE name='history-counts-v1';
DROP INDEX ec_host_operations_important_history;
DROP INDEX ec_host_operations_server_history;
ALTER TABLE ec_host_operations DROP COLUMN routine;