@vibesdotdev/localdb 0.0.2 → 1.0.0-rc.3
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/LICENSE +18 -0
- package/README.md +123 -2
- package/dist/cli/commands/_shared.consumer.d.ts +1 -3
- package/dist/cli/commands/_shared.consumer.d.ts.map +1 -1
- package/dist/cli/commands/_shared.consumer.js +1 -11
- package/dist/cli/commands/_shared.consumer.js.map +1 -1
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.js +1 -1
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.js.map +1 -1
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.d.ts +9 -3
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.d.ts.map +1 -1
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.js +59 -45
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.js.map +1 -1
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.js +1 -1
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.js.map +1 -1
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.d.ts +8 -3
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.d.ts.map +1 -1
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.js +12 -10
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.js.map +1 -1
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.js +1 -1
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.js.map +1 -1
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.d.ts +6 -3
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.d.ts.map +1 -1
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.js +8 -7
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.js.map +1 -1
- package/dist/cli/commands/query/dev.localdb.query.cli-command.descriptor.js +1 -1
- package/dist/cli/commands/query/dev.localdb.query.cli-command.descriptor.js.map +1 -1
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.d.ts +13 -3
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.d.ts.map +1 -1
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.js +66 -51
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.js.map +1 -1
- package/dist/cli/commands/status/dev.localdb.status.cli-command.descriptor.js +1 -1
- package/dist/cli/commands/status/dev.localdb.status.cli-command.descriptor.js.map +1 -1
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.d.ts +9 -3
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.d.ts.map +1 -1
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.js +41 -29
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.js.map +1 -1
- package/dist/cli/inputs.d.ts +25 -0
- package/dist/cli/inputs.d.ts.map +1 -0
- package/dist/cli/inputs.js +81 -0
- package/dist/cli/inputs.js.map +1 -0
- package/dist/cli/types.d.ts +45 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +14 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/core/connection-pool.d.ts +204 -46
- package/dist/core/connection-pool.d.ts.map +1 -1
- package/dist/core/connection-pool.js +610 -101
- package/dist/core/connection-pool.js.map +1 -1
- package/dist/core/database.d.ts +243 -63
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +937 -203
- package/dist/core/database.js.map +1 -1
- package/dist/core/holders.d.ts +15 -0
- package/dist/core/holders.d.ts.map +1 -0
- package/dist/core/holders.js +4 -0
- package/dist/core/holders.js.map +1 -0
- package/dist/core/host-kinds.d.ts +22 -0
- package/dist/core/host-kinds.d.ts.map +1 -0
- package/dist/core/host-kinds.js +52 -0
- package/dist/core/host-kinds.js.map +1 -0
- package/dist/core/live-runtime.d.ts +17 -0
- package/dist/core/live-runtime.d.ts.map +1 -0
- package/dist/core/live-runtime.js +28 -0
- package/dist/core/live-runtime.js.map +1 -0
- package/dist/core/migration-registry.d.ts +115 -80
- package/dist/core/migration-registry.d.ts.map +1 -1
- package/dist/core/migration-registry.js +340 -199
- package/dist/core/migration-registry.js.map +1 -1
- package/dist/core/open-connection.d.ts +11 -0
- package/dist/core/open-connection.d.ts.map +1 -0
- package/dist/core/open-connection.js +70 -0
- package/dist/core/open-connection.js.map +1 -0
- package/dist/core/outcome.d.ts +21 -0
- package/dist/core/outcome.d.ts.map +1 -0
- package/dist/core/outcome.js +22 -0
- package/dist/core/outcome.js.map +1 -0
- package/dist/core/pool-api.d.ts +19 -0
- package/dist/core/pool-api.d.ts.map +1 -0
- package/dist/core/pool-api.js +59 -0
- package/dist/core/pool-api.js.map +1 -0
- package/dist/core/slow-statement.d.ts +81 -0
- package/dist/core/slow-statement.d.ts.map +1 -0
- package/dist/core/slow-statement.js +149 -0
- package/dist/core/slow-statement.js.map +1 -0
- package/dist/core/wal-policy.d.ts +86 -0
- package/dist/core/wal-policy.d.ts.map +1 -0
- package/dist/core/wal-policy.js +115 -0
- package/dist/core/wal-policy.js.map +1 -0
- package/dist/dev.localdb.cli-group.descriptor.d.ts +1 -1
- package/dist/dev.localdb.cli-group.descriptor.d.ts.map +1 -1
- package/dist/dev.localdb.context.descriptor.d.ts +15 -1
- package/dist/dev.localdb.context.descriptor.d.ts.map +1 -1
- package/dist/dev.localdb.context.descriptor.js +1 -1
- package/dist/dev.localdb.context.descriptor.js.map +1 -1
- package/dist/dev.localdb.context.impl.consumer.d.ts +12 -5
- package/dist/dev.localdb.context.impl.consumer.d.ts.map +1 -1
- package/dist/dev.localdb.context.impl.consumer.js +14 -5
- package/dist/dev.localdb.context.impl.consumer.js.map +1 -1
- package/dist/driver/sqlite-driver.base.d.ts +107 -0
- package/dist/driver/sqlite-driver.base.d.ts.map +1 -0
- package/dist/driver/sqlite-driver.base.js +426 -0
- package/dist/driver/sqlite-driver.base.js.map +1 -0
- package/dist/driver/sqlite-driver.d.ts +154 -0
- package/dist/driver/sqlite-driver.d.ts.map +1 -0
- package/dist/driver/sqlite-driver.js +103 -0
- package/dist/driver/sqlite-driver.js.map +1 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/localdb.client.descriptor.d.ts +10 -0
- package/dist/localdb.client.descriptor.d.ts.map +1 -0
- package/dist/localdb.client.descriptor.js +13 -0
- package/dist/localdb.client.descriptor.js.map +1 -0
- package/dist/localdb.client.impl.consumer.d.ts +11 -0
- package/dist/localdb.client.impl.consumer.d.ts.map +1 -0
- package/dist/localdb.client.impl.consumer.js +11 -0
- package/dist/localdb.client.impl.consumer.js.map +1 -0
- package/dist/localdb.plugin.d.ts +2 -2
- package/dist/localdb.plugin.d.ts.map +1 -1
- package/dist/localdb.plugin.js +58 -10
- package/dist/localdb.plugin.js.map +1 -1
- package/dist/location.d.ts +6 -0
- package/dist/location.d.ts.map +1 -0
- package/dist/location.js +6 -0
- package/dist/location.js.map +1 -0
- package/dist/migrations/load-sql.d.ts +25 -21
- package/dist/migrations/load-sql.d.ts.map +1 -1
- package/dist/migrations/load-sql.js +91 -76
- package/dist/migrations/load-sql.js.map +1 -1
- package/dist/pool.d.ts +3 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +3 -0
- package/dist/pool.js.map +1 -0
- package/dist/schemas/api.d.ts +133 -59
- package/dist/schemas/api.d.ts.map +1 -1
- package/dist/schemas/api.js +1 -1
- package/dist/schemas/api.js.map +1 -1
- package/dist/schemas/migrations.d.ts +123 -0
- package/dist/schemas/migrations.d.ts.map +1 -0
- package/dist/schemas/migrations.js +55 -0
- package/dist/schemas/migrations.js.map +1 -0
- package/dist/schemas/pool.d.ts +27 -0
- package/dist/schemas/pool.d.ts.map +1 -0
- package/dist/schemas/pool.js +7 -0
- package/dist/schemas/pool.js.map +1 -0
- package/dist/schemas/sqlite-driver-base.d.ts +50 -0
- package/dist/schemas/sqlite-driver-base.d.ts.map +1 -0
- package/dist/schemas/sqlite-driver-base.js +2 -0
- package/dist/schemas/sqlite-driver-base.js.map +1 -0
- package/dist/testing/sqlite-driver-conformance.d.ts +42 -0
- package/dist/testing/sqlite-driver-conformance.d.ts.map +1 -0
- package/dist/testing/sqlite-driver-conformance.js +471 -0
- package/dist/testing/sqlite-driver-conformance.js.map +1 -0
- package/package.json +78 -104
- package/dist/core/error-context.d.ts +0 -2
- package/dist/core/error-context.d.ts.map +0 -1
- package/dist/core/error-context.js +0 -17
- package/dist/core/error-context.js.map +0 -1
- package/dist/core/runtime.d.ts +0 -3
- package/dist/core/runtime.d.ts.map +0 -1
- package/dist/core/runtime.js +0 -17
- package/dist/core/runtime.js.map +0 -1
- package/dist/localdb.cloud.plugin.d.ts +0 -17
- package/dist/localdb.cloud.plugin.d.ts.map +0 -1
- package/dist/localdb.cloud.plugin.js +0 -23
- package/dist/localdb.cloud.plugin.js.map +0 -1
- package/src/cli/commands/_shared.consumer.ts +0 -20
- package/src/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.ts +0 -20
- package/src/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.ts +0 -97
- package/src/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.ts +0 -17
- package/src/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.ts +0 -46
- package/src/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.ts +0 -16
- package/src/cli/commands/pools/dev.localdb.pools.cli-command.impl.ts +0 -37
- package/src/cli/commands/query/dev.localdb.query.cli-command.descriptor.ts +0 -21
- package/src/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.ts +0 -69
- package/src/cli/commands/status/dev.localdb.status.cli-command.descriptor.ts +0 -20
- package/src/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.ts +0 -93
- package/src/core/connection-pool.ts +0 -240
- package/src/core/database.ts +0 -419
- package/src/core/error-context.ts +0 -19
- package/src/core/migration-registry.ts +0 -321
- package/src/core/runtime.ts +0 -17
- package/src/dev.localdb.cli-group.descriptor.ts +0 -20
- package/src/dev.localdb.context.descriptor.ts +0 -13
- package/src/dev.localdb.context.impl.consumer.ts +0 -12
- package/src/index.ts +0 -28
- package/src/localdb.cloud.plugin.ts +0 -24
- package/src/localdb.plugin.ts +0 -43
- package/src/migrations/atlas/001-initial-schema.sql +0 -173
- package/src/migrations/atlas/002-lang-server-fields.sql +0 -12
- package/src/migrations/atlas/003-config-id-dedup.sql +0 -31
- package/src/migrations/atlas/004-fix-on-conflict-constraints.sql +0 -25
- package/src/migrations/atlas/005-diagnostics.sql +0 -66
- package/src/migrations/atlas/006-diagnostic-summaries.sql +0 -65
- package/src/migrations/atlas/007-diagnostic-slice.sql +0 -83
- package/src/migrations/load-sql.ts +0 -133
- package/src/schemas/api.ts +0 -92
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { CaughtFailureSchema } from '@vibesdotdev/kernel';
|
|
2
|
+
import { isSqliteBusy } from "../driver/sqlite-driver.js";
|
|
3
|
+
import { assertRuntimeLive } from "./live-runtime.js";
|
|
4
|
+
import { attempt } from "./outcome.js";
|
|
5
|
+
const STARTUP_TIMEOUT_MS = 5000;
|
|
6
|
+
/** One startup attempt. Cancellation and configuration failures close the handle before returning. */
|
|
7
|
+
function startOnce(runtime, open, configure, deadline, lifecycle) {
|
|
8
|
+
let db;
|
|
9
|
+
try {
|
|
10
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
11
|
+
const connection = open();
|
|
12
|
+
db = connection;
|
|
13
|
+
configure((sql) => {
|
|
14
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
15
|
+
const remaining = Math.max(0, Math.floor(deadline - lifecycle.now()));
|
|
16
|
+
connection.exec(`PRAGMA busy_timeout = ${remaining};`);
|
|
17
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
18
|
+
connection.exec(sql);
|
|
19
|
+
});
|
|
20
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
21
|
+
connection.exec(`PRAGMA busy_timeout = ${STARTUP_TIMEOUT_MS};`);
|
|
22
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
23
|
+
return { opened: true, db: connection };
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const opened = db;
|
|
27
|
+
return { opened: false, cause: error, cleanup: attempt(() => opened?.close()) };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Keep custody of a just-opened handle across the caller's async continuation. */
|
|
31
|
+
export function assertOpenedConnectionLive(runtime, db, lifecycle = runtime.lifecycle) {
|
|
32
|
+
const live = attempt(() => assertRuntimeLive(runtime, 'connection startup', lifecycle));
|
|
33
|
+
if (!live.failed)
|
|
34
|
+
return;
|
|
35
|
+
const cleanup = attempt(() => db.close());
|
|
36
|
+
if (cleanup.failed) {
|
|
37
|
+
throw new AggregateError([live.cause, cleanup.cause], 'Database startup cancellation and cleanup failed', { cause: live.cause });
|
|
38
|
+
}
|
|
39
|
+
throw live.cause;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Foreground SQLite setup only: one five-second contention budget, with the
|
|
43
|
+
* calling lifecycle owning the wait and cancellation. Migrations and application
|
|
44
|
+
* statements never enter this policy.
|
|
45
|
+
*/
|
|
46
|
+
export async function openConfiguredDatabase(runtime, open, configure, lifecycle = runtime.lifecycle) {
|
|
47
|
+
// Capture the lifecycle: a reload dispatcher must not move this startup to a
|
|
48
|
+
// replacement generation while its original lifecycle is ending.
|
|
49
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
50
|
+
const deadline = lifecycle.now() + STARTUP_TIMEOUT_MS;
|
|
51
|
+
for (;;) {
|
|
52
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
53
|
+
const started = startOnce(runtime, open, configure, deadline, lifecycle);
|
|
54
|
+
if (started.opened)
|
|
55
|
+
return started.db;
|
|
56
|
+
if (started.cleanup.failed) {
|
|
57
|
+
throw new AggregateError([started.cause, started.cleanup.cause], 'Database startup and cleanup failed', {
|
|
58
|
+
cause: started.cause
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const remaining = deadline - lifecycle.now();
|
|
62
|
+
if (!isSqliteBusy(CaughtFailureSchema.parse(started.cause)) || remaining <= 0)
|
|
63
|
+
throw started.cause;
|
|
64
|
+
await lifecycle.delay(Math.min(10, remaining), lifecycle.signal);
|
|
65
|
+
assertRuntimeLive(runtime, 'connection startup', lifecycle);
|
|
66
|
+
if (lifecycle.now() >= deadline)
|
|
67
|
+
throw started.cause;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=open-connection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-connection.js","sourceRoot":"","sources":["../../src/core/open-connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAmB,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAyB,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAC;AAErD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAMhC,sGAAsG;AACtG,SAAS,SAAS,CAAC,OAAmB,EAAE,IAA4B,EAAE,SAAgD,EAAE,QAAgB,EAAE,SAAkC;IAC3K,IAAI,EAAgC,CAAC;IACrC,IAAI,CAAC;QACJ,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;QAC5D,MAAM,UAAU,GAAG,IAAI,EAAE,CAAC;QAC1B,EAAE,GAAG,UAAU,CAAC;QAChB,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;YACjB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;YAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACtE,UAAU,CAAC,IAAI,CAAC,yBAAyB,SAAS,GAAG,CAAC,CAAC;YACvD,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;YAC5D,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;QACH,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;QAC5D,UAAU,CAAC,IAAI,CAAC,yBAAyB,kBAAkB,GAAG,CAAC,CAAC;QAChE,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;QAC5D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,MAAM,GAAG,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACjF,CAAC;AACF,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,0BAA0B,CAAC,OAAmB,EAAE,EAAoB,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS;IAClH,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC,CAAC;IACxF,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO;IACzB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;IAC1C,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,IAAI,cAAc,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,kDAAkD,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAClI,CAAC;IACD,MAAM,IAAI,CAAC,KAAK,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,OAAmB,EACnB,IAA4B,EAC5B,SAAgD,EAChD,SAAS,GAAG,OAAO,CAAC,SAAS;IAE7B,6EAA6E;IAC7E,iEAAiE;IACjE,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC;IACtD,SAAS,CAAC;QACT,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QACzE,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,OAAO,CAAC,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YAC5B,MAAM,IAAI,cAAc,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,qCAAqC,EAAE;gBACvG,KAAK,EAAE,OAAO,CAAC,KAAK;aACpB,CAAC,CAAC;QACJ,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC;QAC7C,IAAI,CAAC,YAAY,CAAC,mBAAmB,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,SAAS,IAAI,CAAC;YAAE,MAAM,OAAO,CAAC,KAAK,CAAC;QACnG,MAAM,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;QACjE,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,EAAE,SAAS,CAAC,CAAC;QAC5D,IAAI,SAAS,CAAC,GAAG,EAAE,IAAI,QAAQ;YAAE,MAAM,OAAO,CAAC,KAAK,CAAC;IACtD,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure outcomes as values.
|
|
3
|
+
*
|
|
4
|
+
* A throw or a rejection becomes a value that carries its cause, so the owner
|
|
5
|
+
* decides what the failure means (report it, retain it for a retry, or rethrow
|
|
6
|
+
* it) and nothing can drop it. Runtime and Logging keep the same helpers
|
|
7
|
+
* private; LocalDB keeps its own until Runtime publishes one.
|
|
8
|
+
*/
|
|
9
|
+
/** What an operation produced, or the failure it raised. */
|
|
10
|
+
export type Outcome<T> = {
|
|
11
|
+
readonly failed: false;
|
|
12
|
+
readonly value: T;
|
|
13
|
+
} | {
|
|
14
|
+
readonly failed: true;
|
|
15
|
+
readonly cause: unknown;
|
|
16
|
+
};
|
|
17
|
+
/** Run a synchronous operation; a throw becomes a failed outcome carrying its cause. */
|
|
18
|
+
export declare function attempt<T>(run: () => T): Outcome<T>;
|
|
19
|
+
/** Observe an asynchronous operation; a rejection becomes a failed outcome carrying its cause. */
|
|
20
|
+
export declare function settle<T>(operation: PromiseLike<T>): Promise<Outcome<T>>;
|
|
21
|
+
//# sourceMappingURL=outcome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../../src/core/outcome.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4DAA4D;AAC5D,MAAM,MAAM,OAAO,CAAC,CAAC,IAClB;IAAE,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC7C;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,wFAAwF;AACxF,wBAAgB,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAMnD;AAED,kGAAkG;AAClG,wBAAgB,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAKxE"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Failure outcomes as values.
|
|
3
|
+
*
|
|
4
|
+
* A throw or a rejection becomes a value that carries its cause, so the owner
|
|
5
|
+
* decides what the failure means (report it, retain it for a retry, or rethrow
|
|
6
|
+
* it) and nothing can drop it. Runtime and Logging keep the same helpers
|
|
7
|
+
* private; LocalDB keeps its own until Runtime publishes one.
|
|
8
|
+
*/
|
|
9
|
+
/** Run a synchronous operation; a throw becomes a failed outcome carrying its cause. */
|
|
10
|
+
export function attempt(run) {
|
|
11
|
+
try {
|
|
12
|
+
return { failed: false, value: run() };
|
|
13
|
+
}
|
|
14
|
+
catch (cause) {
|
|
15
|
+
return { failed: true, cause };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Observe an asynchronous operation; a rejection becomes a failed outcome carrying its cause. */
|
|
19
|
+
export function settle(operation) {
|
|
20
|
+
return Promise.resolve(operation).then((value) => ({ failed: false, value }), (cause) => ({ failed: true, cause }));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=outcome.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcome.js","sourceRoot":"","sources":["../../src/core/outcome.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,wFAAwF;AACxF,MAAM,UAAU,OAAO,CAAI,GAAY;IACtC,IAAI,CAAC;QACJ,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAChC,CAAC;AACF,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,MAAM,CAAI,SAAyB;IAClD,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CACrC,CAAC,KAAK,EAAc,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EACjD,CAAC,KAAK,EAAc,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAChD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type RuntimeRef } from '@vibesdotdev/kernel';
|
|
2
|
+
import type { ConnectionPoolApi } from '../schemas/api.ts';
|
|
3
|
+
import type { SqliteConnection } from '../driver/sqlite-driver.ts';
|
|
4
|
+
/** Stateless compatibility facade. No ambient runtime or physical state. */
|
|
5
|
+
export declare const connectionPool: {
|
|
6
|
+
forRuntime(runtime: RuntimeRef): Promise<ConnectionPoolApi>;
|
|
7
|
+
getConnection(runtime: RuntimeRef, path: string, consumer?: string): Promise<SqliteConnection>;
|
|
8
|
+
releaseConnection(runtime: RuntimeRef, path: string): void;
|
|
9
|
+
retain(runtime: RuntimeRef, path: string): void;
|
|
10
|
+
closeConnection(runtime: RuntimeRef, path: string, force?: boolean): boolean;
|
|
11
|
+
maintain(runtime: RuntimeRef, now?: number): void;
|
|
12
|
+
closeAll(runtime: RuntimeRef, retainedPaths?: ReadonlySet<string>): void;
|
|
13
|
+
getStats(runtime?: RuntimeRef): import("./connection-pool.ts").ConnectionStats;
|
|
14
|
+
withDatabasePathLock<T>(path: string, task: () => Promise<T>, runtime?: RuntimeRef): Promise<T>;
|
|
15
|
+
assertCanReplaceDatabase(runtime: RuntimeRef, path: string, ownedConnection?: SqliteConnection): void;
|
|
16
|
+
releaseOrphanedConnection(path: string, runtime?: RuntimeRef): boolean;
|
|
17
|
+
ownsConnection(path: string, db: SqliteConnection, runtime?: RuntimeRef): boolean;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=pool-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool-api.d.ts","sourceRoot":"","sources":["../../src/core/pool-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAqBnE,4EAA4E;AAC5E,eAAO,MAAM,cAAc;wBACA,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC;2BAGpC,UAAU,QAAQ,MAAM,aAAa,MAAM;+BAG7C,UAAU,QAAQ,MAAM;oBAGnC,UAAU,QAAQ,MAAM;6BAGf,UAAU,QAAQ,MAAM;sBAG/B,UAAU,QAAQ,MAAM;sBAGxB,UAAU,kBAAkB,WAAW,CAAC,MAAM,CAAC;uBAG9C,UAAU;yBAGR,CAAC,QAAQ,MAAM,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,UAAU;sCAGhD,UAAU,QAAQ,MAAM,oBAAoB,gBAAgB;oCAG9D,MAAM,YAAY,UAAU;yBAGvC,MAAM,MAAM,gBAAgB,YAAY,UAAU;CAGvE,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { CapabilityError } from '@vibesdotdev/kernel';
|
|
2
|
+
import { ownedPoolOf, tryOwnedPoolOf } from "./database.js";
|
|
3
|
+
/** Legacy synchronous calls need an explicit, already activated owner. */
|
|
4
|
+
function selected(runtime) {
|
|
5
|
+
if (!runtime) {
|
|
6
|
+
throw new CapabilityError('LocalDB pool access requires a runtime.', 'INVALID_INPUT', {
|
|
7
|
+
reason: 'localdb-runtime-required', retryable: false,
|
|
8
|
+
recoveryHint: 'Pass the calling runtime, or await connectionPool.forRuntime(runtime).'
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
const pool = tryOwnedPoolOf(runtime);
|
|
12
|
+
if (!pool) {
|
|
13
|
+
throw new CapabilityError('The runtime has no activated LocalDB pool.', 'UNAVAILABLE', {
|
|
14
|
+
reason: 'localdb-pool-unavailable', retryable: false,
|
|
15
|
+
recoveryHint: 'Compose the LocalDB plugin or await connectionPool.forRuntime(runtime).'
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return pool;
|
|
19
|
+
}
|
|
20
|
+
/** Stateless compatibility facade. No ambient runtime or physical state. */
|
|
21
|
+
export const connectionPool = {
|
|
22
|
+
async forRuntime(runtime) {
|
|
23
|
+
return ownedPoolOf(runtime);
|
|
24
|
+
},
|
|
25
|
+
async getConnection(runtime, path, consumer) {
|
|
26
|
+
return (await ownedPoolOf(runtime)).getConnection(runtime, path, consumer);
|
|
27
|
+
},
|
|
28
|
+
releaseConnection(runtime, path) {
|
|
29
|
+
selected(runtime).releaseConnection(runtime, path);
|
|
30
|
+
},
|
|
31
|
+
retain(runtime, path) {
|
|
32
|
+
selected(runtime).retain(runtime, path);
|
|
33
|
+
},
|
|
34
|
+
closeConnection(runtime, path, force = false) {
|
|
35
|
+
return selected(runtime).closeConnection(runtime, path, force);
|
|
36
|
+
},
|
|
37
|
+
maintain(runtime, now) {
|
|
38
|
+
selected(runtime).maintain(runtime, now);
|
|
39
|
+
},
|
|
40
|
+
closeAll(runtime, retainedPaths) {
|
|
41
|
+
selected(runtime).closeAll(runtime, retainedPaths);
|
|
42
|
+
},
|
|
43
|
+
getStats(runtime) {
|
|
44
|
+
return selected(runtime).getStats();
|
|
45
|
+
},
|
|
46
|
+
withDatabasePathLock(path, task, runtime) {
|
|
47
|
+
return selected(runtime).withDatabasePathLock(path, task);
|
|
48
|
+
},
|
|
49
|
+
assertCanReplaceDatabase(runtime, path, ownedConnection) {
|
|
50
|
+
selected(runtime).assertCanReplaceDatabase(runtime, path, ownedConnection);
|
|
51
|
+
},
|
|
52
|
+
releaseOrphanedConnection(path, runtime) {
|
|
53
|
+
return selected(runtime).releaseOrphanedConnection(path);
|
|
54
|
+
},
|
|
55
|
+
ownsConnection(path, db, runtime) {
|
|
56
|
+
return selected(runtime).ownsConnection(path, db);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=pool-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool-api.js","sourceRoot":"","sources":["../../src/core/pool-api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAGvE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE5D,0EAA0E;AAC1E,SAAS,QAAQ,CAAC,OAAoB;IACrC,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,eAAe,CAAC,yCAAyC,EAAE,eAAe,EAAE;YACrF,MAAM,EAAE,0BAA0B,EAAE,SAAS,EAAE,KAAK;YACpD,YAAY,EAAE,wEAAwE;SACtF,CAAC,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,MAAM,IAAI,eAAe,CAAC,4CAA4C,EAAE,aAAa,EAAE;YACtF,MAAM,EAAE,0BAA0B,EAAE,SAAS,EAAE,KAAK;YACpD,YAAY,EAAE,yEAAyE;SACvF,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,cAAc,GAAG;IAC7B,KAAK,CAAC,UAAU,CAAC,OAAmB;QACnC,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IACD,KAAK,CAAC,aAAa,CAAC,OAAmB,EAAE,IAAY,EAAE,QAAiB;QACvE,OAAO,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC5E,CAAC;IACD,iBAAiB,CAAC,OAAmB,EAAE,IAAY;QAClD,QAAQ,CAAC,OAAO,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,CAAC,OAAmB,EAAE,IAAY;QACvC,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,eAAe,CAAC,OAAmB,EAAE,IAAY,EAAE,KAAK,GAAG,KAAK;QAC/D,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;IACD,QAAQ,CAAC,OAAmB,EAAE,GAAY;QACzC,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IACD,QAAQ,CAAC,OAAmB,EAAE,aAAmC;QAChE,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACpD,CAAC;IACD,QAAQ,CAAC,OAAoB;QAC5B,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IACrC,CAAC;IACD,oBAAoB,CAAI,IAAY,EAAE,IAAsB,EAAE,OAAoB;QACjF,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3D,CAAC;IACD,wBAAwB,CAAC,OAAmB,EAAE,IAAY,EAAE,eAAkC;QAC7F,QAAQ,CAAC,OAAO,CAAC,CAAC,wBAAwB,CAAC,OAAO,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;IAC5E,CAAC;IACD,yBAAyB,CAAC,IAAY,EAAE,OAAoB;QAC3D,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;IACD,cAAc,CAAC,IAAY,EAAE,EAAoB,EAAE,OAAoB;QACtE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACnD,CAAC;CACD,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slow-statement reporting for every pooled connection (C083b).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. SQLite's calls are synchronous, and the pool is one per
|
|
5
|
+
* process: a statement that runs for seconds holds the thread, so every other
|
|
6
|
+
* client of that process waits behind it with no progress to show. The pool
|
|
7
|
+
* already bounded the WAL and the transaction age, but nothing said WHICH
|
|
8
|
+
* statement cost the time — a `sample` stack names SQLite frames, and a
|
|
9
|
+
* caller's log names the tool, and neither names the table.
|
|
10
|
+
*
|
|
11
|
+
* WHAT IT REPORTS. The consumer that opened the connection, the database path,
|
|
12
|
+
* the statement's operation, the table it named, and how long it took. Every
|
|
13
|
+
* one of those is an identifier or a number the pool already holds: the
|
|
14
|
+
* consumer label is the value-free string the caller passed to
|
|
15
|
+
* `getConnection`, and the operation and table are read out of the statement's
|
|
16
|
+
* own keywords. Bound values, SQL text and result rows are never read, so a
|
|
17
|
+
* report cannot carry a row's contents.
|
|
18
|
+
*
|
|
19
|
+
* WHY IT IS NOT LOGGED FROM THE STATEMENT PATH. A report raised while a
|
|
20
|
+
* statement is unwinding would run on whatever runtime the pool last saw, which
|
|
21
|
+
* may have ended, and an observability path that can fail the operation it
|
|
22
|
+
* observes is worse than none. Reports are recorded here and drained by the
|
|
23
|
+
* pool's existing maintenance tick, which already reports on a live holder.
|
|
24
|
+
*
|
|
25
|
+
* The cost when nothing is slow is two `performance.now()` reads and one
|
|
26
|
+
* comparison per statement.
|
|
27
|
+
*/
|
|
28
|
+
import type { SqliteConnection } from '../driver/sqlite-driver.ts';
|
|
29
|
+
/** A statement that took at least this many milliseconds is recorded. */
|
|
30
|
+
export declare const SLOW_STATEMENT_MS = 250;
|
|
31
|
+
/**
|
|
32
|
+
* Reports one drain window can hold. A workload that trips the threshold many
|
|
33
|
+
* times in 30 s is a fact about itself, not a reason to grow without bound: the
|
|
34
|
+
* pool logs how many it kept and how many it did not.
|
|
35
|
+
*/
|
|
36
|
+
export declare const SLOW_STATEMENT_REPORT_LIMIT = 100;
|
|
37
|
+
/** What a statement does, by its leading keyword. */
|
|
38
|
+
export type SqliteOperation = 'select' | 'insert' | 'update' | 'delete' | 'pragma' | 'transaction' | 'other';
|
|
39
|
+
/** One recorded statement: what it did, which table it named, how long it took. Never its values. */
|
|
40
|
+
export interface SlowStatementReport {
|
|
41
|
+
readonly operation: SqliteOperation;
|
|
42
|
+
/** The table the statement named, when it named one that is a bare identifier. */
|
|
43
|
+
readonly table?: string;
|
|
44
|
+
readonly elapsedMs: number;
|
|
45
|
+
}
|
|
46
|
+
/** One recorded statement's fields for a log line: the table only when it has one. */
|
|
47
|
+
export interface SlowStatementFields {
|
|
48
|
+
operation: SqliteOperation;
|
|
49
|
+
table?: string;
|
|
50
|
+
elapsedMs: number;
|
|
51
|
+
}
|
|
52
|
+
/** A recorded report as its log fields, with the elapsed time rounded to whole milliseconds. */
|
|
53
|
+
export declare function slowStatementFields(report: SlowStatementReport): SlowStatementFields;
|
|
54
|
+
/** Where recorded reports wait for the pool's maintenance tick. */
|
|
55
|
+
export interface SlowStatementRecorder {
|
|
56
|
+
/** Record one statement at or over the threshold. Drops, and counts, past {@link SLOW_STATEMENT_REPORT_LIMIT}. */
|
|
57
|
+
record(report: SlowStatementReport): void;
|
|
58
|
+
/** Take everything recorded since the last drain, oldest first, and how many were dropped. */
|
|
59
|
+
drain(): {
|
|
60
|
+
reports: SlowStatementReport[];
|
|
61
|
+
dropped: number;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** What a statement does, by its leading keyword, and the table it named. */
|
|
65
|
+
export interface StatementDescription {
|
|
66
|
+
readonly operation: SqliteOperation;
|
|
67
|
+
/** Absent when the statement named no table that is a bare identifier. */
|
|
68
|
+
readonly table?: string;
|
|
69
|
+
}
|
|
70
|
+
/** A statement's operation and, when it named one, its table. Reads keywords and identifiers only. */
|
|
71
|
+
export declare function describeStatement(sql: string): StatementDescription;
|
|
72
|
+
/** A recorder that keeps the first {@link SLOW_STATEMENT_REPORT_LIMIT} reports of a window and counts the rest. */
|
|
73
|
+
export declare function createSlowStatementRecorder(limit?: number): SlowStatementRecorder;
|
|
74
|
+
/**
|
|
75
|
+
* Wrap a connection so every statement on it is timed, and one at or over
|
|
76
|
+
* {@link SLOW_STATEMENT_MS} is recorded. Everything else is delegated, so the
|
|
77
|
+
* connection still satisfies the driver contract and still owns its own
|
|
78
|
+
* transactions: a slow statement is observed, never altered or retried.
|
|
79
|
+
*/
|
|
80
|
+
export declare function instrumentConnection(db: SqliteConnection, recorder: SlowStatementRecorder): SqliteConnection;
|
|
81
|
+
//# sourceMappingURL=slow-statement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slow-statement.d.ts","sourceRoot":"","sources":["../../src/core/slow-statement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAEX,gBAAgB,EAKhB,MAAM,4BAA4B,CAAC;AAEpC,yEAAyE;AACzE,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C,qDAAqD;AACrD,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,GAAG,OAAO,CAAC;AAE7G,qGAAqG;AACrG,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,kFAAkF;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,sFAAsF;AACtF,MAAM,WAAW,mBAAmB;IACnC,SAAS,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,gGAAgG;AAChG,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB,CAIpF;AAED,mEAAmE;AACnE,MAAM,WAAW,qBAAqB;IACrC,kHAAkH;IAClH,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC1C,8FAA8F;IAC9F,KAAK,IAAI;QAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7D;AA0BD,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,sGAAsG;AACtG,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CASnE;AAED,mHAAmH;AACnH,wBAAgB,2BAA2B,CAAC,KAAK,GAAE,MAAoC,GAAG,qBAAqB,CAe9G;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,gBAAgB,EAAE,QAAQ,EAAE,qBAAqB,GAAG,gBAAgB,CAyC5G"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slow-statement reporting for every pooled connection (C083b).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. SQLite's calls are synchronous, and the pool is one per
|
|
5
|
+
* process: a statement that runs for seconds holds the thread, so every other
|
|
6
|
+
* client of that process waits behind it with no progress to show. The pool
|
|
7
|
+
* already bounded the WAL and the transaction age, but nothing said WHICH
|
|
8
|
+
* statement cost the time — a `sample` stack names SQLite frames, and a
|
|
9
|
+
* caller's log names the tool, and neither names the table.
|
|
10
|
+
*
|
|
11
|
+
* WHAT IT REPORTS. The consumer that opened the connection, the database path,
|
|
12
|
+
* the statement's operation, the table it named, and how long it took. Every
|
|
13
|
+
* one of those is an identifier or a number the pool already holds: the
|
|
14
|
+
* consumer label is the value-free string the caller passed to
|
|
15
|
+
* `getConnection`, and the operation and table are read out of the statement's
|
|
16
|
+
* own keywords. Bound values, SQL text and result rows are never read, so a
|
|
17
|
+
* report cannot carry a row's contents.
|
|
18
|
+
*
|
|
19
|
+
* WHY IT IS NOT LOGGED FROM THE STATEMENT PATH. A report raised while a
|
|
20
|
+
* statement is unwinding would run on whatever runtime the pool last saw, which
|
|
21
|
+
* may have ended, and an observability path that can fail the operation it
|
|
22
|
+
* observes is worse than none. Reports are recorded here and drained by the
|
|
23
|
+
* pool's existing maintenance tick, which already reports on a live holder.
|
|
24
|
+
*
|
|
25
|
+
* The cost when nothing is slow is two `performance.now()` reads and one
|
|
26
|
+
* comparison per statement.
|
|
27
|
+
*/
|
|
28
|
+
/** A statement that took at least this many milliseconds is recorded. */
|
|
29
|
+
export const SLOW_STATEMENT_MS = 250;
|
|
30
|
+
/**
|
|
31
|
+
* Reports one drain window can hold. A workload that trips the threshold many
|
|
32
|
+
* times in 30 s is a fact about itself, not a reason to grow without bound: the
|
|
33
|
+
* pool logs how many it kept and how many it did not.
|
|
34
|
+
*/
|
|
35
|
+
export const SLOW_STATEMENT_REPORT_LIMIT = 100;
|
|
36
|
+
/** A recorded report as its log fields, with the elapsed time rounded to whole milliseconds. */
|
|
37
|
+
export function slowStatementFields(report) {
|
|
38
|
+
const fields = { operation: report.operation, elapsedMs: Math.round(report.elapsedMs) };
|
|
39
|
+
if (report.table !== undefined)
|
|
40
|
+
fields.table = report.table;
|
|
41
|
+
return fields;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The only token shape a reported table may take: a bare SQLite identifier.
|
|
45
|
+
* A quoted string literal (`'…'`), a JSON path (`'$.x'`) and a number all fail
|
|
46
|
+
* it, so a value can never be reported as a table name.
|
|
47
|
+
*/
|
|
48
|
+
const IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
49
|
+
/** A double-quoted or backticked identifier, unwrapped; anything else is refused. */
|
|
50
|
+
function identifier(token) {
|
|
51
|
+
const unquoted = (token.length > 1 && (token.startsWith('"') || token.startsWith('`')) && token.endsWith(token[0]))
|
|
52
|
+
? token.slice(1, -1)
|
|
53
|
+
: token;
|
|
54
|
+
return IDENTIFIER.test(unquoted) ? unquoted : undefined;
|
|
55
|
+
}
|
|
56
|
+
/** The first identifier after `keyword`, optionally schema-qualified, as a table name. */
|
|
57
|
+
function tableAfter(sql, keyword) {
|
|
58
|
+
const match = new RegExp(`\\b${keyword}\\s+("[^"]+"|\`[^\`]+\`|[A-Za-z_][A-Za-z0-9_]*)(?:\\s*\\.\\s*("[^"]+"|\`[^\`]+\`|[A-Za-z_][A-Za-z0-9_]*))?`, 'i').exec(sql);
|
|
59
|
+
if (!match)
|
|
60
|
+
return undefined;
|
|
61
|
+
const second = match[2] ? identifier(match[2]) : undefined;
|
|
62
|
+
return second ?? identifier(match[1]);
|
|
63
|
+
}
|
|
64
|
+
/** A statement's operation and, when it named one, its table. Reads keywords and identifiers only. */
|
|
65
|
+
export function describeStatement(sql) {
|
|
66
|
+
const text = sql.trim();
|
|
67
|
+
if (/^pragma\b/i.test(text))
|
|
68
|
+
return { operation: 'pragma' };
|
|
69
|
+
if (/^(begin|commit|rollback|savepoint|release)\b/i.test(text))
|
|
70
|
+
return { operation: 'transaction' };
|
|
71
|
+
if (/^(select|with)\b/i.test(text))
|
|
72
|
+
return { operation: 'select', table: tableAfter(text, 'FROM') };
|
|
73
|
+
if (/^insert\b/i.test(text))
|
|
74
|
+
return { operation: 'insert', table: tableAfter(text, 'INTO') };
|
|
75
|
+
if (/^update\b/i.test(text))
|
|
76
|
+
return { operation: 'update', table: tableAfter(text, 'UPDATE') };
|
|
77
|
+
if (/^delete\b/i.test(text))
|
|
78
|
+
return { operation: 'delete', table: tableAfter(text, 'FROM') };
|
|
79
|
+
return { operation: 'other' };
|
|
80
|
+
}
|
|
81
|
+
/** A recorder that keeps the first {@link SLOW_STATEMENT_REPORT_LIMIT} reports of a window and counts the rest. */
|
|
82
|
+
export function createSlowStatementRecorder(limit = SLOW_STATEMENT_REPORT_LIMIT) {
|
|
83
|
+
const reports = [];
|
|
84
|
+
let dropped = 0;
|
|
85
|
+
return {
|
|
86
|
+
record(report) {
|
|
87
|
+
if (reports.length < limit)
|
|
88
|
+
reports.push(report);
|
|
89
|
+
else
|
|
90
|
+
dropped += 1;
|
|
91
|
+
},
|
|
92
|
+
drain() {
|
|
93
|
+
const taken = reports.splice(0, reports.length);
|
|
94
|
+
const takenDropped = dropped;
|
|
95
|
+
dropped = 0;
|
|
96
|
+
return { reports: taken, dropped: takenDropped };
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Wrap a connection so every statement on it is timed, and one at or over
|
|
102
|
+
* {@link SLOW_STATEMENT_MS} is recorded. Everything else is delegated, so the
|
|
103
|
+
* connection still satisfies the driver contract and still owns its own
|
|
104
|
+
* transactions: a slow statement is observed, never altered or retried.
|
|
105
|
+
*/
|
|
106
|
+
export function instrumentConnection(db, recorder) {
|
|
107
|
+
const measure = (described, run) => {
|
|
108
|
+
const started = performance.now();
|
|
109
|
+
try {
|
|
110
|
+
return run();
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
const elapsedMs = performance.now() - started;
|
|
114
|
+
if (elapsedMs >= SLOW_STATEMENT_MS)
|
|
115
|
+
recorder.record({ ...described, elapsedMs });
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
path: db.path,
|
|
120
|
+
get inTransaction() {
|
|
121
|
+
return db.inTransaction;
|
|
122
|
+
},
|
|
123
|
+
exec(sql) {
|
|
124
|
+
measure(describeStatement(sql), () => {
|
|
125
|
+
db.exec(sql);
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
prepare(sql) {
|
|
129
|
+
const statement = db.prepare(sql);
|
|
130
|
+
// Described once per prepare, not once per call: the hot path pays two
|
|
131
|
+
// clock reads and a comparison, never a parse.
|
|
132
|
+
const described = describeStatement(sql);
|
|
133
|
+
return {
|
|
134
|
+
all: (...params) => measure(described, () => statement.all(...params)),
|
|
135
|
+
get: (...params) => measure(described, () => statement.get(...params)),
|
|
136
|
+
run: (...params) => measure(described, () => statement.run(...params))
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
transaction(run, options) {
|
|
140
|
+
// Timed as a whole because COMMIT is where a transaction's cost lands,
|
|
141
|
+
// and no single statement reports it.
|
|
142
|
+
return measure({ operation: 'transaction' }, () => db.transaction(run, options));
|
|
143
|
+
},
|
|
144
|
+
close() {
|
|
145
|
+
db.close();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=slow-statement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slow-statement.js","sourceRoot":"","sources":["../../src/core/slow-statement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAWH,yEAAyE;AACzE,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC;;;;GAIG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAoB/C,gGAAgG;AAChG,MAAM,UAAU,mBAAmB,CAAC,MAA2B;IAC9D,MAAM,MAAM,GAAwB,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;IAC7G,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC5D,OAAO,MAAM,CAAC;AACf,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAE9C,qFAAqF;AACrF,SAAS,UAAU,CAAC,KAAa;IAChC,MAAM,QAAQ,GACb,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;QAClG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC;IACV,OAAO,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;AACzD,CAAC;AAED,0FAA0F;AAC1F,SAAS,UAAU,CAAC,GAAW,EAAE,OAAmC;IACnE,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,OAAO,4GAA4G,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnK,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,OAAO,MAAM,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;AACxC,CAAC;AASD,sGAAsG;AACtG,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC5C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACxB,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IAC5D,IAAI,+CAA+C,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;IACpG,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;IACpG,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;IAC7F,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;IAC/F,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;IAC7F,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,mHAAmH;AACnH,MAAM,UAAU,2BAA2B,CAAC,QAAgB,2BAA2B;IACtF,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,OAAO;QACN,MAAM,CAAC,MAAM;YACZ,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;;gBAC5C,OAAO,IAAI,CAAC,CAAC;QACnB,CAAC;QACD,KAAK;YACJ,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,YAAY,GAAG,OAAO,CAAC;YAC7B,OAAO,GAAG,CAAC,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;QAClD,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,EAAoB,EAAE,QAA+B;IACzF,MAAM,OAAO,GAAG,CAAI,SAAyD,EAAE,GAAY,EAAK,EAAE;QACjG,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC;YACJ,OAAO,GAAG,EAAE,CAAC;QACd,CAAC;gBAAS,CAAC;YACV,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;YAC9C,IAAI,SAAS,IAAI,iBAAiB;gBAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;QAClF,CAAC;IACF,CAAC,CAAC;IAEF,OAAO;QACN,IAAI,EAAE,EAAE,CAAC,IAAI;QACb,IAAI,aAAa;YAChB,OAAO,EAAE,CAAC,aAAa,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,GAAW;YACf,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE;gBACpC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,CAAkC,GAAW;YACnD,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAO,GAAG,CAAC,CAAC;YACxC,uEAAuE;YACvE,+CAA+C;YAC/C,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;YACzC,OAAO;gBACN,GAAG,EAAE,CAAC,GAAG,MAAuB,EAAU,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;gBAC/F,GAAG,EAAE,CAAC,GAAG,MAAuB,EAAe,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;gBACpG,GAAG,EAAE,CAAC,GAAG,MAAuB,EAAmB,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;aACxG,CAAC;QACH,CAAC;QACD,WAAW,CAAI,GAAY,EAAE,OAAkC;YAC9D,uEAAuE;YACvE,sCAAsC;YACtC,OAAO,OAAO,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;QAClF,CAAC;QACD,KAAK;YACJ,EAAE,CAAC,KAAK,EAAE,CAAC;QACZ,CAAC;KACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WAL policy for every LocalDB connection (D-WAL).
|
|
3
|
+
*
|
|
4
|
+
* The 2026-08-31 and 2026-09-27 disk incidents were the same defect: a WAL
|
|
5
|
+
* held open by long-lived processes grew without bound (63 GB, then 37.6 GB)
|
|
6
|
+
* because the pool only ever issued `wal_checkpoint(PASSIVE)` on close and set
|
|
7
|
+
* no `journal_size_limit`. Those processes are expected to run, so the bound
|
|
8
|
+
* lives here, not in killing holders:
|
|
9
|
+
*
|
|
10
|
+
* - `journal_size_limit` caps the bytes a WAL is truncated back to whenever it
|
|
11
|
+
* resets. It is enforced only at checkpoint boundaries, so it never ships
|
|
12
|
+
* alone.
|
|
13
|
+
* - The pool makes ONE checkpoint attempt per idle window, never blocking:
|
|
14
|
+
* the attempt runs with a zero busy timeout, so a reader or writer in
|
|
15
|
+
* another process makes it return busy at once instead of parking the
|
|
16
|
+
* event loop. The mode is `TRUNCATE`; after a busy attempt the next window
|
|
17
|
+
* falls back to `RESTART`, then alternates. Busy attempts back off by
|
|
18
|
+
* skipping whole windows (1, 2, 4, 8 …, capped) on the lifecycle-owned
|
|
19
|
+
* tick — no second timer, no retry loop.
|
|
20
|
+
* - Every attempt's `(busy, log, checkpointed)` result is observed and
|
|
21
|
+
* returned, so "the checkpoint ran" and "the checkpoint did anything" are
|
|
22
|
+
* distinguishable.
|
|
23
|
+
*
|
|
24
|
+
* Nothing in this module (or the pool) ever deletes a raw `-wal` or `-shm`
|
|
25
|
+
* file: un-checkpointed rows live only in the WAL.
|
|
26
|
+
*/
|
|
27
|
+
import type { SqliteConnection } from '../driver/sqlite-driver.ts';
|
|
28
|
+
/** Bytes the WAL is truncated back to when it resets. */
|
|
29
|
+
export declare const WAL_JOURNAL_SIZE_LIMIT_BYTES: number;
|
|
30
|
+
/** Busy timeout for a checkpoint attempt: zero, so an attempt never blocks. */
|
|
31
|
+
export declare const WAL_CHECKPOINT_BUSY_TIMEOUT_MS = 0;
|
|
32
|
+
/** Longest backoff after consecutive busy attempts, in maintenance windows. */
|
|
33
|
+
export declare const WAL_MAX_BACKOFF_WINDOWS = 8;
|
|
34
|
+
/** Consecutive busy outcomes on one connection before the pool reports starvation. */
|
|
35
|
+
export declare const WAL_BUSY_STARVATION_THRESHOLD = 3;
|
|
36
|
+
/** Longest a pooled connection may hold an open transaction across maintenance ticks. */
|
|
37
|
+
export declare const MAX_TRANSACTION_AGE_MS = 60000;
|
|
38
|
+
/** Period of the pool's lifecycle-owned maintenance tick (idle checkpoint, transaction bound, stale close). */
|
|
39
|
+
export declare const WAL_MAINTENANCE_INTERVAL_MS = 30000;
|
|
40
|
+
export type WalCheckpointMode = 'TRUNCATE' | 'RESTART';
|
|
41
|
+
/** One `PRAGMA wal_checkpoint(<mode>)` result row. */
|
|
42
|
+
export interface WalCheckpointAttempt {
|
|
43
|
+
mode: WalCheckpointMode;
|
|
44
|
+
/** 1 when the checkpoint could not obtain its locks within the busy window. */
|
|
45
|
+
busy: number;
|
|
46
|
+
/** Frames in the WAL, or -1 when the database is not in WAL mode. */
|
|
47
|
+
log: number;
|
|
48
|
+
/** Frames copied back into the database, or -1 when not in WAL mode. */
|
|
49
|
+
checkpointed: number;
|
|
50
|
+
}
|
|
51
|
+
export type WalCheckpointStatus =
|
|
52
|
+
/**
|
|
53
|
+
* Nothing left to bound: the WAL was fully checkpointed and reset (TRUNCATE
|
|
54
|
+
* also shrank the file), or it holds no committed frames at all (it is at
|
|
55
|
+
* its start, already cut back to `journal_size_limit`), even when another
|
|
56
|
+
* holder's open write transaction made the attempt report busy.
|
|
57
|
+
*/
|
|
58
|
+
'complete'
|
|
59
|
+
/**
|
|
60
|
+
* Committed frames remain in the WAL and it could not be reset: a reader
|
|
61
|
+
* or writer elsewhere still holds it. Repeated, this is how a WAL grows.
|
|
62
|
+
*/
|
|
63
|
+
| 'busy'
|
|
64
|
+
/** The connection is not in WAL mode (e.g. `:memory:`); nothing to bound. */
|
|
65
|
+
| 'not-wal';
|
|
66
|
+
export interface WalCheckpointOutcome extends WalCheckpointAttempt {
|
|
67
|
+
status: WalCheckpointStatus;
|
|
68
|
+
}
|
|
69
|
+
/** The mode for the attempt after `previous` came back busy: TRUNCATE falls back to RESTART, then alternates. */
|
|
70
|
+
export declare function nextCheckpointMode(previous: WalCheckpointMode, status: WalCheckpointStatus): WalCheckpointMode;
|
|
71
|
+
/** Windows to skip after `consecutiveBusy` busy attempts: 1, 2, 4, … capped at {@link WAL_MAX_BACKOFF_WINDOWS}. */
|
|
72
|
+
export declare function checkpointBackoffWindows(consecutiveBusy: number): number;
|
|
73
|
+
/** Returns the pragma statements that every LocalDB connection must run. */
|
|
74
|
+
export declare function localDatabasePragmaStatements(): string[];
|
|
75
|
+
/** Apply the connection pragmas every LocalDB connection carries. */
|
|
76
|
+
export declare function applyLocalDatabasePragmas(exec: (sql: string) => void): void;
|
|
77
|
+
/**
|
|
78
|
+
* One checkpoint attempt in `mode`, never blocking: the connection's busy
|
|
79
|
+
* timeout is zero for the attempt and restored on every exit path.
|
|
80
|
+
*
|
|
81
|
+
* Throws only when SQLite itself raises (a closed handle, or a checkpoint issued
|
|
82
|
+
* inside this connection's own open transaction) or answers no result row; a busy result is returned, not
|
|
83
|
+
* thrown, so the caller can observe, report and back off.
|
|
84
|
+
*/
|
|
85
|
+
export declare function checkpointWal(db: SqliteConnection, mode?: WalCheckpointMode): WalCheckpointOutcome;
|
|
86
|
+
//# sourceMappingURL=wal-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wal-policy.d.ts","sourceRoot":"","sources":["../../src/core/wal-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,yDAAyD;AACzD,eAAO,MAAM,4BAA4B,QAAmB,CAAC;AAE7D,+EAA+E;AAC/E,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAEhD,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,sFAAsF;AACtF,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,QAAS,CAAC;AAE7C,+GAA+G;AAC/G,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,SAAS,CAAC;AAEvD,sDAAsD;AACtD,MAAM,WAAW,oBAAoB;IACpC,IAAI,EAAE,iBAAiB,CAAC;IACxB,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,mBAAmB;AAC9B;;;;;GAKG;AACD,UAAU;AACZ;;;GAGG;GACD,MAAM;AACR,6EAA6E;GAC3E,SAAS,CAAC;AAEb,MAAM,WAAW,oBAAqB,SAAQ,oBAAoB;IACjE,MAAM,EAAE,mBAAmB,CAAC;CAC5B;AAED,iHAAiH;AACjH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,MAAM,EAAE,mBAAmB,GAAG,iBAAiB,CAG9G;AAED,mHAAmH;AACnH,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAGxE;AAED,4EAA4E;AAC5E,wBAAgB,6BAA6B,IAAI,MAAM,EAAE,CAiBxD;AAED,qEAAqE;AACrE,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAI3E;AAsBD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,gBAAgB,EAAE,IAAI,GAAE,iBAA8B,GAAG,oBAAoB,CAS9G"}
|