Skip to content

Commit 260b5e4

Browse files
authored
Merge pull request #6583 from loopx-project/codex/sqlite-retained-utf8-bytes-20261016
2 parents 3dede0f + 1569b1f commit 260b5e4

2 files changed

Lines changed: 48 additions & 3 deletions

File tree

‎loopx/control_plane/coordination/sqlite_authority_store.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -673,11 +673,12 @@ export class SqliteAuthorityStore implements AuthorityStore {
673673
return {status: "failed", reason_code: "provider_read_unavailable", reason: "SQLite authority database is empty"};
674674
}
675675
const counted = db.prepare("SELECT COUNT(*) AS count FROM commits").get();
676+
// SQLite length(TEXT) counts characters, not the encoded JSON bytes.
676677
const retained = db.prepare(`SELECT
677678
(SELECT COUNT(*) FROM checkpoints) AS checkpoints,
678-
(SELECT COALESCE(SUM(length(projection)), 0) FROM checkpoints) AS projection_bytes,
679-
(SELECT COALESCE(SUM(length(delta)), 0) FROM commits) AS delta_bytes,
680-
(SELECT COALESCE(SUM(length(events) + length(receipts)), 0) FROM commits) AS payload_bytes`).get();
679+
(SELECT COALESCE(SUM(length(CAST(projection AS BLOB))), 0) FROM checkpoints) AS projection_bytes,
680+
(SELECT COALESCE(SUM(length(CAST(delta AS BLOB))), 0) FROM commits) AS delta_bytes,
681+
(SELECT COALESCE(SUM(length(CAST(events AS BLOB)) + length(CAST(receipts AS BLOB))), 0) FROM commits) AS payload_bytes`).get();
681682
const cursor = head.state.cursor;
682683
return {
683684
schema_version: "loopx_sqlite_authority_bounded_profile_v0",

‎tests/control_plane_ts/sqlite_authority_bounded_profile.test.ts‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from "node:assert/strict";
22
import {mkdtemp, rm} from "node:fs/promises";
33
import {tmpdir} from "node:os";
44
import {join} from "node:path";
5+
import {DatabaseSync} from "node:sqlite";
56
import test from "node:test";
67

78
import {AUTHORITY_STATE_CHECKPOINT_INTERVAL} from
@@ -23,6 +24,49 @@ async function fixture(t: test.TestContext): Promise<SqliteAuthorityStore> {
2324
return new SqliteAuthorityStore(directory, GOAL_ID);
2425
}
2526

27+
for (const text of ["plain ASCII", "中文", "😀🛰️"]) {
28+
test(`SQLite retained byte counts measure UTF-8 for ${JSON.stringify(text)}`, async t => {
29+
const store = await fixture(t);
30+
let revision: string | null = null;
31+
for (let index = 1; index <= AUTHORITY_STATE_CHECKPOINT_INTERVAL + 1; index += 1) {
32+
const applied = await store.commitAuthority({expected_provider_revision: revision,
33+
operation_id: `byte-profile-${index}`, next_projection: {text, index},
34+
events: [{text, index}], receipts: [{text, index}]});
35+
assert.equal(applied.status, "applied", JSON.stringify(applied));
36+
if (applied.status !== "applied") return;
37+
revision = applied.provider_revision;
38+
}
39+
const before = await store.loadAuthority();
40+
assert.equal(before.status, "loaded");
41+
const original = await store.readReceipt("byte-profile-1");
42+
assert.equal(original.status, "found");
43+
const profile = await store.boundedProfile();
44+
assert.equal(profile.status, "available", JSON.stringify(profile));
45+
if (profile.status !== "available") return;
46+
assert.equal(profile.checkpoints, 2);
47+
// Measure the exact retained JSON independently of the profile's SQL
48+
// aggregates. UTF-8 bytes differ from SQLite TEXT character counts.
49+
const utf8Bytes = (value: unknown): number => {
50+
assert.equal(typeof value, "string");
51+
return Buffer.byteLength(value as string, "utf8");
52+
};
53+
const db = new DatabaseSync(store.path, {readOnly: true});
54+
try {
55+
const checkpoints = db.prepare("SELECT projection FROM checkpoints").all();
56+
const commits = db.prepare("SELECT delta, events, receipts FROM commits").all();
57+
assert.equal(profile.retained_projection_bytes,
58+
checkpoints.reduce((total, row) => total + utf8Bytes(row.projection), 0));
59+
assert.equal(profile.retained_delta_bytes,
60+
commits.reduce((total, row) => total + utf8Bytes(row.delta), 0));
61+
assert.equal(profile.retained_payload_bytes,
62+
commits.reduce((total, row) => total + utf8Bytes(row.events) + utf8Bytes(row.receipts), 0));
63+
} finally { db.close(); }
64+
assert.deepEqual(await store.loadAuthority(), before);
65+
assert.deepEqual(await store.readReceipt("byte-profile-1"), original);
66+
assert.equal((await store.verifyAuthorityHistory()).status, "verified");
67+
});
68+
}
69+
2670
interface ReplayedHistory {
2771
readonly heads: string[];
2872
readonly operations: string[];

0 commit comments

Comments
 (0)