@tanstack/db-sqlite-persistence-core 0.4.8 → 0.4.9
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/README.md +10 -1
- package/dist/cjs/broadcast-coordinator.cjs +117 -29
- package/dist/cjs/broadcast-coordinator.cjs.map +1 -1
- package/dist/cjs/broadcast-coordinator.d.cts +16 -8
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/persisted.cjs +1408 -278
- package/dist/cjs/persisted.cjs.map +1 -1
- package/dist/cjs/persisted.d.cts +62 -15
- package/dist/cjs/remote-subset-wire.cjs +11 -0
- package/dist/cjs/remote-subset-wire.cjs.map +1 -1
- package/dist/cjs/remote-subset-wire.d.cts +1 -0
- package/dist/cjs/sqlite-core-adapter.cjs +623 -73
- package/dist/cjs/sqlite-core-adapter.cjs.map +1 -1
- package/dist/cjs/sqlite-core-adapter.d.cts +46 -12
- package/dist/esm/broadcast-coordinator.d.ts +16 -8
- package/dist/esm/broadcast-coordinator.js +118 -30
- package/dist/esm/broadcast-coordinator.js.map +1 -1
- package/dist/esm/index.js +6 -2
- package/dist/esm/persisted.d.ts +62 -15
- package/dist/esm/persisted.js +1409 -279
- package/dist/esm/persisted.js.map +1 -1
- package/dist/esm/remote-subset-wire.d.ts +1 -0
- package/dist/esm/remote-subset-wire.js +11 -0
- package/dist/esm/remote-subset-wire.js.map +1 -1
- package/dist/esm/sqlite-core-adapter.d.ts +46 -12
- package/dist/esm/sqlite-core-adapter.js +626 -76
- package/dist/esm/sqlite-core-adapter.js.map +1 -1
- package/package.json +2 -2
- package/src/broadcast-coordinator.ts +153 -23
- package/src/persisted.ts +1973 -322
- package/src/remote-subset-wire.ts +12 -0
- package/src/sqlite-core-adapter.ts +760 -77
|
@@ -108,6 +108,12 @@ function observeSharedLogicalSchedulingSupport(driver, onSupport) {
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
const DEFAULT_SCHEMA_VERSION = 1;
|
|
111
|
+
const CACHE_GENERATION_ID_PREFIX = `tanstack-db-cache:`;
|
|
112
|
+
const LEGACY_CACHE_GENERATION_ID_PREFIX = `\0tanstack-db-cache:`;
|
|
113
|
+
function hasCacheGenerationIdPrefix(collectionId) {
|
|
114
|
+
return collectionId.startsWith(CACHE_GENERATION_ID_PREFIX) || collectionId.startsWith(LEGACY_CACHE_GENERATION_ID_PREFIX);
|
|
115
|
+
}
|
|
116
|
+
const DEFAULT_CACHE_GENERATION_CLAIM_TTL_MS = 5 * 6e4;
|
|
111
117
|
const DEFAULT_PULL_SINCE_RELOAD_THRESHOLD = 128;
|
|
112
118
|
const DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS = 1e3;
|
|
113
119
|
const DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS = 24 * 60 * 60;
|
|
@@ -1049,6 +1055,13 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1049
1055
|
);
|
|
1050
1056
|
}
|
|
1051
1057
|
this.replacementBatchSize = maxBoundParameters === void 0 ? REPLACEMENT_BATCH_SIZE : Math.min(REPLACEMENT_BATCH_SIZE, Math.floor(maxBoundParameters / 4));
|
|
1058
|
+
this.cacheGenerationClaimTtlMs = options.cacheGenerationClaimTtlMs ?? DEFAULT_CACHE_GENERATION_CLAIM_TTL_MS;
|
|
1059
|
+
if (!Number.isSafeInteger(this.cacheGenerationClaimTtlMs) || this.cacheGenerationClaimTtlMs <= 0) {
|
|
1060
|
+
throw new errors.InvalidPersistedCollectionConfigError(
|
|
1061
|
+
`SQLite adapter cacheGenerationClaimTtlMs must be a positive safe integer`
|
|
1062
|
+
);
|
|
1063
|
+
}
|
|
1064
|
+
this.now = options.now ?? Date.now;
|
|
1052
1065
|
const schemaVersion = options.schemaVersion ?? DEFAULT_SCHEMA_VERSION;
|
|
1053
1066
|
if (!Number.isInteger(schemaVersion) || schemaVersion < 0) {
|
|
1054
1067
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
@@ -1091,16 +1104,257 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1091
1104
|
loadSubset: (collectionId, loadOptions, context) => this.loadSubsetUnscheduled(collectionId, loadOptions, context),
|
|
1092
1105
|
loadResumeSnapshot: (collectionId, context) => this.loadResumeSnapshotUnscheduled(collectionId, context),
|
|
1093
1106
|
applyCommittedTx: (collectionId, tx) => this.applyCommittedTxUnscheduled(collectionId, tx),
|
|
1107
|
+
renewCacheGenerationClaim: (storageCollectionId, claimId) => this.renewCacheGenerationClaimUnscheduled(storageCollectionId, claimId),
|
|
1094
1108
|
reconcileCommittedTx: (collectionId, tx, anchor) => this.reconcileCommittedTxUnscheduled(collectionId, tx, anchor),
|
|
1095
|
-
loadCollectionMetadata: (collectionId) => this.loadCollectionMetadataUnscheduled(collectionId),
|
|
1096
|
-
scanRows: (collectionId, scanOptions) => this.scanRowsUnscheduled(collectionId, scanOptions),
|
|
1097
|
-
ensureIndex: (collectionId, signature, spec) => this.ensureIndexUnscheduled(collectionId, signature, spec),
|
|
1098
|
-
markIndexRemoved: (collectionId, signature) => this.markIndexRemovedUnscheduled(collectionId, signature),
|
|
1099
|
-
getStreamPosition: (collectionId) => this.getStreamPositionUnscheduled(collectionId),
|
|
1100
|
-
pullSince: (collectionId, fromRowVersion) => this.pullSinceUnscheduled(collectionId, fromRowVersion),
|
|
1109
|
+
loadCollectionMetadata: (collectionId, context) => this.loadCollectionMetadataUnscheduled(collectionId, context),
|
|
1110
|
+
scanRows: (collectionId, scanOptions, context) => this.scanRowsUnscheduled(collectionId, scanOptions, context),
|
|
1111
|
+
ensureIndex: (collectionId, signature, spec, ctx) => this.ensureIndexUnscheduled(collectionId, signature, spec, ctx),
|
|
1112
|
+
markIndexRemoved: (collectionId, signature, ctx) => this.markIndexRemovedUnscheduled(collectionId, signature, ctx),
|
|
1113
|
+
getStreamPosition: (collectionId, ctx) => this.getStreamPositionUnscheduled(collectionId, ctx),
|
|
1114
|
+
pullSince: (collectionId, fromRowVersion, ctx) => this.pullSinceUnscheduled(collectionId, fromRowVersion, ctx),
|
|
1101
1115
|
runInHydrationScope: async (task) => task(this.hydrationAdapter)
|
|
1102
1116
|
};
|
|
1103
1117
|
}
|
|
1118
|
+
claimCacheGeneration(collectionId) {
|
|
1119
|
+
return this.runRegular(async () => {
|
|
1120
|
+
await this.ensureInitialized();
|
|
1121
|
+
return this.driver.transaction(async (driver) => {
|
|
1122
|
+
const expiresAtMs = this.now() + this.cacheGenerationClaimTtlMs;
|
|
1123
|
+
const initialPhysicalId = `${CACHE_GENERATION_ID_PREFIX}${db.safeRandomUUID()}`;
|
|
1124
|
+
await driver.run(
|
|
1125
|
+
`INSERT INTO cache_generation (logical_id, generation, physical_id, retired)
|
|
1126
|
+
SELECT ?, 0, ?, 0
|
|
1127
|
+
WHERE NOT EXISTS (
|
|
1128
|
+
SELECT 1 FROM cache_generation WHERE logical_id = ?
|
|
1129
|
+
)`,
|
|
1130
|
+
[collectionId, initialPhysicalId, collectionId]
|
|
1131
|
+
);
|
|
1132
|
+
const head = await driver.query(
|
|
1133
|
+
`SELECT physical_id FROM cache_generation
|
|
1134
|
+
WHERE logical_id = ? AND retired = 0`,
|
|
1135
|
+
[collectionId]
|
|
1136
|
+
);
|
|
1137
|
+
const storageCollectionId = head[0]?.physical_id;
|
|
1138
|
+
if (!storageCollectionId) {
|
|
1139
|
+
throw new errors.InvalidPersistedCollectionConfigError(
|
|
1140
|
+
`No active persisted cache generation for collection "${collectionId}"`
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
const claimId = db.safeRandomUUID();
|
|
1144
|
+
await driver.run(
|
|
1145
|
+
`INSERT INTO cache_generation_claim
|
|
1146
|
+
(claim_id, logical_id, physical_id, expires_at_ms)
|
|
1147
|
+
VALUES (?, ?, ?, ?)`,
|
|
1148
|
+
[claimId, collectionId, storageCollectionId, expiresAtMs]
|
|
1149
|
+
);
|
|
1150
|
+
await this.collectRetiredCacheGenerations(driver);
|
|
1151
|
+
return { storageCollectionId, claimId, expiresAtMs };
|
|
1152
|
+
});
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
rotateCacheGeneration(collectionId, claimId, resetMetadata, expectedStorageCollectionId) {
|
|
1156
|
+
return this.runRegular(async () => {
|
|
1157
|
+
await this.ensureInitialized();
|
|
1158
|
+
return this.driver.transaction(async (driver) => {
|
|
1159
|
+
const now = this.now();
|
|
1160
|
+
const expiresAtMs = now + this.cacheGenerationClaimTtlMs;
|
|
1161
|
+
const claimed = await driver.query(
|
|
1162
|
+
`SELECT physical_id, expires_at_ms
|
|
1163
|
+
FROM cache_generation_claim
|
|
1164
|
+
WHERE claim_id = ? AND logical_id = ?`,
|
|
1165
|
+
[claimId, collectionId]
|
|
1166
|
+
);
|
|
1167
|
+
const claimedPhysicalId = claimed[0] && claimed[0].expires_at_ms > now ? claimed[0].physical_id : void 0;
|
|
1168
|
+
if (claimedPhysicalId && expectedStorageCollectionId && claimedPhysicalId !== expectedStorageCollectionId) {
|
|
1169
|
+
throw new errors.InvalidPersistedCollectionConfigError(
|
|
1170
|
+
`Persisted cache claim changed generations before recovery`
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
const head = await driver.query(
|
|
1174
|
+
`SELECT generation, physical_id FROM cache_generation
|
|
1175
|
+
WHERE logical_id = ? AND retired = 0`,
|
|
1176
|
+
[collectionId]
|
|
1177
|
+
);
|
|
1178
|
+
const active = head[0];
|
|
1179
|
+
if (!active) {
|
|
1180
|
+
throw new errors.InvalidPersistedCollectionConfigError(
|
|
1181
|
+
`No active persisted cache generation for collection "${collectionId}"`
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
await driver.run(
|
|
1185
|
+
`INSERT INTO cache_generation_sequence (logical_id, next_generation)
|
|
1186
|
+
SELECT ?, COALESCE(MAX(generation), -1) + 1
|
|
1187
|
+
FROM cache_generation WHERE logical_id = ?
|
|
1188
|
+
ON CONFLICT(logical_id) DO NOTHING`,
|
|
1189
|
+
[collectionId, collectionId]
|
|
1190
|
+
);
|
|
1191
|
+
const nextRows = await driver.query(
|
|
1192
|
+
`SELECT next_generation FROM cache_generation_sequence
|
|
1193
|
+
WHERE logical_id = ?`,
|
|
1194
|
+
[collectionId]
|
|
1195
|
+
);
|
|
1196
|
+
const nextGeneration = nextRows[0].next_generation;
|
|
1197
|
+
await driver.run(
|
|
1198
|
+
`UPDATE cache_generation_sequence SET next_generation = ?
|
|
1199
|
+
WHERE logical_id = ?`,
|
|
1200
|
+
[nextGeneration + 1, collectionId]
|
|
1201
|
+
);
|
|
1202
|
+
const ownedHead = claimedPhysicalId === active.physical_id;
|
|
1203
|
+
const storageCollectionId = `${CACHE_GENERATION_ID_PREFIX}${db.safeRandomUUID()}`;
|
|
1204
|
+
if (ownedHead) {
|
|
1205
|
+
await driver.run(
|
|
1206
|
+
`UPDATE cache_generation SET retired = 1
|
|
1207
|
+
WHERE logical_id = ? AND generation = ?`,
|
|
1208
|
+
[collectionId, active.generation]
|
|
1209
|
+
);
|
|
1210
|
+
}
|
|
1211
|
+
await driver.run(
|
|
1212
|
+
`INSERT INTO cache_generation (logical_id, generation, physical_id, retired)
|
|
1213
|
+
VALUES (?, ?, ?, ?)`,
|
|
1214
|
+
[
|
|
1215
|
+
collectionId,
|
|
1216
|
+
nextGeneration,
|
|
1217
|
+
storageCollectionId,
|
|
1218
|
+
ownedHead ? 0 : 1
|
|
1219
|
+
]
|
|
1220
|
+
);
|
|
1221
|
+
const nextClaimId = claimed[0] ? claimId : db.safeRandomUUID();
|
|
1222
|
+
if (claimed[0]) {
|
|
1223
|
+
await driver.run(
|
|
1224
|
+
`UPDATE cache_generation_claim
|
|
1225
|
+
SET physical_id = ?, expires_at_ms = ? WHERE claim_id = ?`,
|
|
1226
|
+
[storageCollectionId, expiresAtMs, claimId]
|
|
1227
|
+
);
|
|
1228
|
+
} else {
|
|
1229
|
+
await driver.run(
|
|
1230
|
+
`INSERT INTO cache_generation_claim
|
|
1231
|
+
(claim_id, logical_id, physical_id, expires_at_ms)
|
|
1232
|
+
VALUES (?, ?, ?, ?)`,
|
|
1233
|
+
[nextClaimId, collectionId, storageCollectionId, expiresAtMs]
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
await driver.run(
|
|
1237
|
+
`INSERT INTO collection_version (
|
|
1238
|
+
collection_id, latest_row_version,
|
|
1239
|
+
key_set_evidence_available, key_set_evidence_incompatible
|
|
1240
|
+
) VALUES (?, 0, 1, 1)`,
|
|
1241
|
+
[storageCollectionId]
|
|
1242
|
+
);
|
|
1243
|
+
if (resetMetadata) {
|
|
1244
|
+
await driver.run(
|
|
1245
|
+
`INSERT INTO collection_metadata (collection_id, key, value, updated_at)
|
|
1246
|
+
VALUES (?, ?, ?, CAST(strftime('%s', 'now') AS INTEGER))`,
|
|
1247
|
+
[
|
|
1248
|
+
storageCollectionId,
|
|
1249
|
+
resetMetadata.key,
|
|
1250
|
+
serializePersistedRowValue(resetMetadata.value)
|
|
1251
|
+
]
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
await this.collectRetiredCacheGenerations(driver);
|
|
1255
|
+
return { storageCollectionId, claimId: nextClaimId, expiresAtMs };
|
|
1256
|
+
});
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
releaseCacheGenerationClaim(claimId) {
|
|
1260
|
+
return this.runRegular(async () => {
|
|
1261
|
+
await this.ensureInitialized();
|
|
1262
|
+
await this.runInTransaction(async (driver) => {
|
|
1263
|
+
await driver.run(
|
|
1264
|
+
`DELETE FROM cache_generation_claim WHERE claim_id = ?`,
|
|
1265
|
+
[claimId]
|
|
1266
|
+
);
|
|
1267
|
+
await this.collectRetiredCacheGenerations(driver);
|
|
1268
|
+
});
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
renewCacheGenerationClaim(storageCollectionId, claimId) {
|
|
1272
|
+
return this.runRegular(
|
|
1273
|
+
() => this.renewCacheGenerationClaimUnscheduled(storageCollectionId, claimId)
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
async renewCacheGenerationClaimUnscheduled(storageCollectionId, claimId) {
|
|
1277
|
+
await this.ensureInitialized();
|
|
1278
|
+
return this.runInTransaction(async (driver) => {
|
|
1279
|
+
const now = this.now();
|
|
1280
|
+
const rows = await driver.query(
|
|
1281
|
+
`SELECT claim_id FROM cache_generation_claim
|
|
1282
|
+
WHERE claim_id = ? AND physical_id = ? AND expires_at_ms > ?`,
|
|
1283
|
+
[claimId, storageCollectionId, now]
|
|
1284
|
+
);
|
|
1285
|
+
if (!rows[0]) {
|
|
1286
|
+
await this.collectRetiredCacheGenerations(driver);
|
|
1287
|
+
return void 0;
|
|
1288
|
+
}
|
|
1289
|
+
const expiresAtMs = now + this.cacheGenerationClaimTtlMs;
|
|
1290
|
+
await driver.run(
|
|
1291
|
+
`UPDATE cache_generation_claim SET expires_at_ms = ?
|
|
1292
|
+
WHERE claim_id = ?`,
|
|
1293
|
+
[expiresAtMs, claimId]
|
|
1294
|
+
);
|
|
1295
|
+
return expiresAtMs;
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
async collectRetiredCacheGenerations(driver) {
|
|
1299
|
+
await driver.run(
|
|
1300
|
+
`DELETE FROM cache_generation_claim WHERE expires_at_ms <= ?`,
|
|
1301
|
+
[this.now()]
|
|
1302
|
+
);
|
|
1303
|
+
const retired = await driver.query(
|
|
1304
|
+
`SELECT generation.physical_id, registry.table_name,
|
|
1305
|
+
registry.tombstone_table_name
|
|
1306
|
+
FROM cache_generation AS generation
|
|
1307
|
+
LEFT JOIN collection_registry AS registry
|
|
1308
|
+
ON registry.collection_id = generation.physical_id
|
|
1309
|
+
WHERE generation.retired = 1
|
|
1310
|
+
AND NOT EXISTS (
|
|
1311
|
+
SELECT 1 FROM cache_generation_claim AS claim
|
|
1312
|
+
WHERE claim.physical_id = generation.physical_id
|
|
1313
|
+
)`
|
|
1314
|
+
);
|
|
1315
|
+
for (const generation of retired) {
|
|
1316
|
+
if (generation.table_name) {
|
|
1317
|
+
await driver.exec(
|
|
1318
|
+
`DROP TABLE IF EXISTS ${quoteIdentifier(generation.table_name)}`
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
if (generation.tombstone_table_name) {
|
|
1322
|
+
await driver.exec(
|
|
1323
|
+
`DROP TABLE IF EXISTS ${quoteIdentifier(generation.tombstone_table_name)}`
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
for (const table of [
|
|
1327
|
+
`applied_tx`,
|
|
1328
|
+
`collection_expected_keys`,
|
|
1329
|
+
`collection_metadata`,
|
|
1330
|
+
`persisted_index_registry`,
|
|
1331
|
+
`leader_term`
|
|
1332
|
+
]) {
|
|
1333
|
+
await driver.run(`DELETE FROM ${table} WHERE collection_id = ?`, [
|
|
1334
|
+
generation.physical_id
|
|
1335
|
+
]);
|
|
1336
|
+
}
|
|
1337
|
+
await driver.run(
|
|
1338
|
+
`DELETE FROM collection_version WHERE collection_id = ?`,
|
|
1339
|
+
[generation.physical_id]
|
|
1340
|
+
);
|
|
1341
|
+
await driver.run(
|
|
1342
|
+
`DELETE FROM collection_reset_epoch WHERE collection_id = ?`,
|
|
1343
|
+
[generation.physical_id]
|
|
1344
|
+
);
|
|
1345
|
+
await driver.run(
|
|
1346
|
+
`DELETE FROM collection_registry WHERE collection_id = ?`,
|
|
1347
|
+
[generation.physical_id]
|
|
1348
|
+
);
|
|
1349
|
+
await driver.run(`DELETE FROM cache_generation WHERE physical_id = ?`, [
|
|
1350
|
+
generation.physical_id
|
|
1351
|
+
]);
|
|
1352
|
+
this.collectionTableCache.delete(generation.physical_id);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
getCacheGenerationNow() {
|
|
1356
|
+
return this.now();
|
|
1357
|
+
}
|
|
1104
1358
|
runInHydrationScope(task) {
|
|
1105
1359
|
const scheduler = this.resolveScheduler();
|
|
1106
1360
|
if (scheduler) {
|
|
@@ -1155,14 +1409,63 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1155
1409
|
);
|
|
1156
1410
|
}
|
|
1157
1411
|
}
|
|
1158
|
-
|
|
1412
|
+
async assertCacheGenerationReadClaim(driver, storageCollectionId, claimId) {
|
|
1413
|
+
await this.ensureInitialized();
|
|
1414
|
+
if (!claimId) {
|
|
1415
|
+
if (!hasCacheGenerationIdPrefix(storageCollectionId)) return;
|
|
1416
|
+
const generation = await driver.query(
|
|
1417
|
+
`SELECT physical_id FROM cache_generation WHERE physical_id = ?`,
|
|
1418
|
+
[storageCollectionId]
|
|
1419
|
+
);
|
|
1420
|
+
if (generation[0]) {
|
|
1421
|
+
throw new errors.InvalidPersistedCollectionConfigError(
|
|
1422
|
+
`Persisted cache claim is required for collection "${storageCollectionId}"`
|
|
1423
|
+
);
|
|
1424
|
+
}
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
const rows = await driver.query(
|
|
1428
|
+
`SELECT claim.claim_id
|
|
1429
|
+
FROM cache_generation_claim AS claim
|
|
1430
|
+
JOIN cache_generation AS generation
|
|
1431
|
+
ON generation.physical_id = claim.physical_id
|
|
1432
|
+
WHERE claim.claim_id = ? AND claim.physical_id = ?
|
|
1433
|
+
AND claim.expires_at_ms > ?`,
|
|
1434
|
+
[claimId, storageCollectionId, this.now()]
|
|
1435
|
+
);
|
|
1436
|
+
if (!rows[0]) {
|
|
1437
|
+
throw new errors.InvalidPersistedCollectionConfigError(
|
|
1438
|
+
`Persisted cache claim is no longer active for collection "${storageCollectionId}"`
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
loadSubset(target, options, ctx) {
|
|
1159
1443
|
return this.runRegular(
|
|
1160
|
-
() => this.loadSubsetUnscheduled(
|
|
1444
|
+
() => this.loadSubsetUnscheduled(target, options, ctx)
|
|
1161
1445
|
);
|
|
1162
1446
|
}
|
|
1163
|
-
async loadSubsetUnscheduled(
|
|
1164
|
-
const
|
|
1447
|
+
async loadSubsetUnscheduled(target, options, ctx) {
|
|
1448
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
1449
|
+
target,
|
|
1450
|
+
ctx?.cacheGenerationClaimId
|
|
1451
|
+
);
|
|
1452
|
+
const collectionId = access.collectionId;
|
|
1453
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
1454
|
+
await this.assertCacheGenerationReadClaim(
|
|
1455
|
+
this.driver,
|
|
1456
|
+
collectionId,
|
|
1457
|
+
ctx?.cacheGenerationClaimId
|
|
1458
|
+
);
|
|
1459
|
+
const tableMapping = await this.ensureCollectionReady(
|
|
1460
|
+
collectionId,
|
|
1461
|
+
ctx?.cacheGenerationClaimId
|
|
1462
|
+
);
|
|
1165
1463
|
return this.runInTransaction(async (transactionDriver) => {
|
|
1464
|
+
await this.assertCacheGenerationReadClaim(
|
|
1465
|
+
transactionDriver,
|
|
1466
|
+
collectionId,
|
|
1467
|
+
ctx?.cacheGenerationClaimId
|
|
1468
|
+
);
|
|
1166
1469
|
await this.assertCurrentSchemaVersion(
|
|
1167
1470
|
collectionId,
|
|
1168
1471
|
transactionDriver,
|
|
@@ -1221,15 +1524,34 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1221
1524
|
}));
|
|
1222
1525
|
});
|
|
1223
1526
|
}
|
|
1224
|
-
loadResumeSnapshot(
|
|
1527
|
+
loadResumeSnapshot(target, ctx) {
|
|
1225
1528
|
return this.runRegular(
|
|
1226
|
-
() => this.loadResumeSnapshotUnscheduled(
|
|
1529
|
+
() => this.loadResumeSnapshotUnscheduled(target, ctx)
|
|
1227
1530
|
);
|
|
1228
1531
|
}
|
|
1229
|
-
async loadResumeSnapshotUnscheduled(
|
|
1230
|
-
const
|
|
1532
|
+
async loadResumeSnapshotUnscheduled(target, ctx) {
|
|
1533
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
1534
|
+
target,
|
|
1535
|
+
ctx?.cacheGenerationClaimId
|
|
1536
|
+
);
|
|
1537
|
+
const collectionId = access.collectionId;
|
|
1538
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
1539
|
+
await this.assertCacheGenerationReadClaim(
|
|
1540
|
+
this.driver,
|
|
1541
|
+
collectionId,
|
|
1542
|
+
ctx?.cacheGenerationClaimId
|
|
1543
|
+
);
|
|
1544
|
+
const tableMapping = await this.ensureCollectionReady(
|
|
1545
|
+
collectionId,
|
|
1546
|
+
ctx?.cacheGenerationClaimId
|
|
1547
|
+
);
|
|
1231
1548
|
const includeRows = ctx?.includeRows !== false;
|
|
1232
1549
|
return this.runInTransaction(async (transactionDriver) => {
|
|
1550
|
+
await this.assertCacheGenerationReadClaim(
|
|
1551
|
+
transactionDriver,
|
|
1552
|
+
collectionId,
|
|
1553
|
+
ctx?.cacheGenerationClaimId
|
|
1554
|
+
);
|
|
1233
1555
|
await this.assertCurrentSchemaVersion(
|
|
1234
1556
|
collectionId,
|
|
1235
1557
|
transactionDriver,
|
|
@@ -1282,32 +1604,49 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1282
1604
|
};
|
|
1283
1605
|
});
|
|
1284
1606
|
}
|
|
1285
|
-
applyCommittedTx(
|
|
1286
|
-
return this.runRegular(
|
|
1287
|
-
() => this.applyCommittedTxUnscheduled(collectionId, tx)
|
|
1288
|
-
);
|
|
1607
|
+
applyCommittedTx(target, tx) {
|
|
1608
|
+
return this.runRegular(() => this.applyCommittedTxUnscheduled(target, tx));
|
|
1289
1609
|
}
|
|
1290
|
-
reconcileCommittedTx(
|
|
1610
|
+
reconcileCommittedTx(target, tx, anchor) {
|
|
1291
1611
|
return this.runRegular(
|
|
1292
|
-
() => this.reconcileCommittedTxUnscheduled(
|
|
1612
|
+
() => this.reconcileCommittedTxUnscheduled(target, tx, anchor)
|
|
1293
1613
|
);
|
|
1294
1614
|
}
|
|
1295
|
-
async applyCommittedTxUnscheduled(
|
|
1296
|
-
await this.applyCommittedTxInternal(
|
|
1615
|
+
async applyCommittedTxUnscheduled(target, tx) {
|
|
1616
|
+
await this.applyCommittedTxInternal(target, tx);
|
|
1297
1617
|
}
|
|
1298
|
-
reconcileCommittedTxUnscheduled(
|
|
1618
|
+
reconcileCommittedTxUnscheduled(target, tx, anchor) {
|
|
1299
1619
|
if (!committedTxAnchor.isValidCommittedTxAnchor(anchor)) {
|
|
1300
1620
|
throw new Error(
|
|
1301
1621
|
`Cannot reconcile a committed transaction without a valid durable anchor`
|
|
1302
1622
|
);
|
|
1303
1623
|
}
|
|
1304
|
-
return this.applyCommittedTxInternal(
|
|
1624
|
+
return this.applyCommittedTxInternal(target, tx, anchor);
|
|
1305
1625
|
}
|
|
1306
|
-
async applyCommittedTxInternal(
|
|
1307
|
-
const
|
|
1626
|
+
async applyCommittedTxInternal(target, tx, anchor) {
|
|
1627
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
1628
|
+
target,
|
|
1629
|
+
tx.cacheGenerationClaimId
|
|
1630
|
+
);
|
|
1631
|
+
const collectionId = access.collectionId;
|
|
1632
|
+
tx = { ...tx, cacheGenerationClaimId: access.claimId };
|
|
1633
|
+
await this.assertCacheGenerationReadClaim(
|
|
1634
|
+
this.driver,
|
|
1635
|
+
collectionId,
|
|
1636
|
+
tx.cacheGenerationClaimId
|
|
1637
|
+
);
|
|
1638
|
+
const tableMapping = await this.ensureCollectionReady(
|
|
1639
|
+
collectionId,
|
|
1640
|
+
tx.cacheGenerationClaimId
|
|
1641
|
+
);
|
|
1308
1642
|
const collectionTableSql = quoteIdentifier(tableMapping.tableName);
|
|
1309
1643
|
const tombstoneTableSql = quoteIdentifier(tableMapping.tombstoneTableName);
|
|
1310
1644
|
return this.runInTransaction(async (transactionDriver) => {
|
|
1645
|
+
await this.assertCacheGenerationReadClaim(
|
|
1646
|
+
transactionDriver,
|
|
1647
|
+
collectionId,
|
|
1648
|
+
tx.cacheGenerationClaimId
|
|
1649
|
+
);
|
|
1311
1650
|
const versionRows = await transactionDriver.query(
|
|
1312
1651
|
`SELECT
|
|
1313
1652
|
latest_row_version,
|
|
@@ -1634,14 +1973,30 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1634
1973
|
};
|
|
1635
1974
|
});
|
|
1636
1975
|
}
|
|
1637
|
-
loadCollectionMetadata(
|
|
1976
|
+
loadCollectionMetadata(target, ctx) {
|
|
1638
1977
|
return this.runRegular(
|
|
1639
|
-
() => this.loadCollectionMetadataUnscheduled(
|
|
1978
|
+
() => this.loadCollectionMetadataUnscheduled(target, ctx)
|
|
1640
1979
|
);
|
|
1641
1980
|
}
|
|
1642
|
-
async loadCollectionMetadataUnscheduled(
|
|
1643
|
-
|
|
1981
|
+
async loadCollectionMetadataUnscheduled(target, ctx) {
|
|
1982
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
1983
|
+
target,
|
|
1984
|
+
ctx?.cacheGenerationClaimId
|
|
1985
|
+
);
|
|
1986
|
+
const collectionId = access.collectionId;
|
|
1987
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
1988
|
+
await this.assertCacheGenerationReadClaim(
|
|
1989
|
+
this.driver,
|
|
1990
|
+
collectionId,
|
|
1991
|
+
ctx?.cacheGenerationClaimId
|
|
1992
|
+
);
|
|
1993
|
+
await this.ensureCollectionReady(collectionId, ctx?.cacheGenerationClaimId);
|
|
1644
1994
|
return this.runInTransaction(async (transactionDriver) => {
|
|
1995
|
+
await this.assertCacheGenerationReadClaim(
|
|
1996
|
+
transactionDriver,
|
|
1997
|
+
collectionId,
|
|
1998
|
+
ctx?.cacheGenerationClaimId
|
|
1999
|
+
);
|
|
1645
2000
|
await this.assertCurrentSchemaVersion(
|
|
1646
2001
|
collectionId,
|
|
1647
2002
|
transactionDriver,
|
|
@@ -1659,15 +2014,32 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1659
2014
|
}));
|
|
1660
2015
|
});
|
|
1661
2016
|
}
|
|
1662
|
-
scanRows(
|
|
1663
|
-
return this.runRegular(
|
|
1664
|
-
() => this.scanRowsUnscheduled(collectionId, options)
|
|
1665
|
-
);
|
|
2017
|
+
scanRows(target, options, ctx) {
|
|
2018
|
+
return this.runRegular(() => this.scanRowsUnscheduled(target, options, ctx));
|
|
1666
2019
|
}
|
|
1667
|
-
async scanRowsUnscheduled(
|
|
1668
|
-
const
|
|
2020
|
+
async scanRowsUnscheduled(target, options, ctx) {
|
|
2021
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
2022
|
+
target,
|
|
2023
|
+
ctx?.cacheGenerationClaimId
|
|
2024
|
+
);
|
|
2025
|
+
const collectionId = access.collectionId;
|
|
2026
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
2027
|
+
await this.assertCacheGenerationReadClaim(
|
|
2028
|
+
this.driver,
|
|
2029
|
+
collectionId,
|
|
2030
|
+
ctx?.cacheGenerationClaimId
|
|
2031
|
+
);
|
|
2032
|
+
const tableMapping = await this.ensureCollectionReady(
|
|
2033
|
+
collectionId,
|
|
2034
|
+
ctx?.cacheGenerationClaimId
|
|
2035
|
+
);
|
|
1669
2036
|
const collectionTableSql = quoteIdentifier(tableMapping.tableName);
|
|
1670
2037
|
return this.runInTransaction(async (transactionDriver) => {
|
|
2038
|
+
await this.assertCacheGenerationReadClaim(
|
|
2039
|
+
transactionDriver,
|
|
2040
|
+
collectionId,
|
|
2041
|
+
ctx?.cacheGenerationClaimId
|
|
2042
|
+
);
|
|
1671
2043
|
await this.assertCurrentSchemaVersion(
|
|
1672
2044
|
collectionId,
|
|
1673
2045
|
transactionDriver,
|
|
@@ -1686,13 +2058,27 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1686
2058
|
}));
|
|
1687
2059
|
});
|
|
1688
2060
|
}
|
|
1689
|
-
ensureIndex(
|
|
2061
|
+
ensureIndex(target, signature, spec, ctx) {
|
|
1690
2062
|
return this.runRegular(
|
|
1691
|
-
() => this.ensureIndexUnscheduled(
|
|
2063
|
+
() => this.ensureIndexUnscheduled(target, signature, spec, ctx)
|
|
1692
2064
|
);
|
|
1693
2065
|
}
|
|
1694
|
-
async ensureIndexUnscheduled(
|
|
1695
|
-
const
|
|
2066
|
+
async ensureIndexUnscheduled(target, signature, spec, ctx) {
|
|
2067
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
2068
|
+
target,
|
|
2069
|
+
ctx?.cacheGenerationClaimId
|
|
2070
|
+
);
|
|
2071
|
+
const collectionId = access.collectionId;
|
|
2072
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
2073
|
+
await this.assertCacheGenerationReadClaim(
|
|
2074
|
+
this.driver,
|
|
2075
|
+
collectionId,
|
|
2076
|
+
ctx?.cacheGenerationClaimId
|
|
2077
|
+
);
|
|
2078
|
+
const tableMapping = await this.ensureCollectionReady(
|
|
2079
|
+
collectionId,
|
|
2080
|
+
ctx?.cacheGenerationClaimId
|
|
2081
|
+
);
|
|
1696
2082
|
const collectionTableSql = quoteIdentifier(tableMapping.tableName);
|
|
1697
2083
|
const indexName = buildIndexName(collectionId, signature);
|
|
1698
2084
|
const indexNameSql = quoteIdentifier(indexName);
|
|
@@ -1704,6 +2090,11 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1704
2090
|
const whereSql = spec.whereSql ? normalizeIndexSqlFragment(spec.whereSql) : void 0;
|
|
1705
2091
|
const persistedWhereSql = whereSql ?? null;
|
|
1706
2092
|
await this.runInTransaction(async (transactionDriver) => {
|
|
2093
|
+
await this.assertCacheGenerationReadClaim(
|
|
2094
|
+
transactionDriver,
|
|
2095
|
+
collectionId,
|
|
2096
|
+
ctx?.cacheGenerationClaimId
|
|
2097
|
+
);
|
|
1707
2098
|
await this.assertCurrentSchemaVersion(
|
|
1708
2099
|
collectionId,
|
|
1709
2100
|
transactionDriver,
|
|
@@ -1760,14 +2151,30 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1760
2151
|
await transactionDriver.exec(createIndexSql);
|
|
1761
2152
|
});
|
|
1762
2153
|
}
|
|
1763
|
-
markIndexRemoved(
|
|
2154
|
+
markIndexRemoved(target, signature, ctx) {
|
|
1764
2155
|
return this.runRegular(
|
|
1765
|
-
() => this.markIndexRemovedUnscheduled(
|
|
2156
|
+
() => this.markIndexRemovedUnscheduled(target, signature, ctx)
|
|
1766
2157
|
);
|
|
1767
2158
|
}
|
|
1768
|
-
async markIndexRemovedUnscheduled(
|
|
1769
|
-
|
|
2159
|
+
async markIndexRemovedUnscheduled(target, signature, ctx) {
|
|
2160
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
2161
|
+
target,
|
|
2162
|
+
ctx?.cacheGenerationClaimId
|
|
2163
|
+
);
|
|
2164
|
+
const collectionId = access.collectionId;
|
|
2165
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
2166
|
+
await this.assertCacheGenerationReadClaim(
|
|
2167
|
+
this.driver,
|
|
2168
|
+
collectionId,
|
|
2169
|
+
ctx?.cacheGenerationClaimId
|
|
2170
|
+
);
|
|
2171
|
+
await this.ensureCollectionReady(collectionId, ctx?.cacheGenerationClaimId);
|
|
1770
2172
|
await this.runInTransaction(async (transactionDriver) => {
|
|
2173
|
+
await this.assertCacheGenerationReadClaim(
|
|
2174
|
+
transactionDriver,
|
|
2175
|
+
collectionId,
|
|
2176
|
+
ctx?.cacheGenerationClaimId
|
|
2177
|
+
);
|
|
1771
2178
|
await this.assertCurrentSchemaVersion(
|
|
1772
2179
|
collectionId,
|
|
1773
2180
|
transactionDriver,
|
|
@@ -1796,12 +2203,28 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1796
2203
|
}
|
|
1797
2204
|
});
|
|
1798
2205
|
}
|
|
1799
|
-
reserveLeadershipTerm(
|
|
1800
|
-
return this.reserveLeadershipTermUnscheduled(
|
|
2206
|
+
reserveLeadershipTerm(target, observedTerm, ctx) {
|
|
2207
|
+
return this.reserveLeadershipTermUnscheduled(target, observedTerm, ctx);
|
|
1801
2208
|
}
|
|
1802
|
-
async reserveLeadershipTermUnscheduled(
|
|
1803
|
-
|
|
2209
|
+
async reserveLeadershipTermUnscheduled(target, observedTerm, ctx) {
|
|
2210
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
2211
|
+
target,
|
|
2212
|
+
ctx?.cacheGenerationClaimId
|
|
2213
|
+
);
|
|
2214
|
+
const collectionId = access.collectionId;
|
|
2215
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
2216
|
+
await this.assertCacheGenerationReadClaim(
|
|
2217
|
+
this.driver,
|
|
2218
|
+
collectionId,
|
|
2219
|
+
ctx?.cacheGenerationClaimId
|
|
2220
|
+
);
|
|
2221
|
+
await this.ensureCollectionReady(collectionId, ctx?.cacheGenerationClaimId);
|
|
1804
2222
|
return this.runInTransaction(async (transactionDriver) => {
|
|
2223
|
+
await this.assertCacheGenerationReadClaim(
|
|
2224
|
+
transactionDriver,
|
|
2225
|
+
collectionId,
|
|
2226
|
+
ctx?.cacheGenerationClaimId
|
|
2227
|
+
);
|
|
1805
2228
|
await this.assertCurrentSchemaVersion(
|
|
1806
2229
|
collectionId,
|
|
1807
2230
|
transactionDriver,
|
|
@@ -1821,12 +2244,28 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1821
2244
|
return { ...position, latestRowVersion };
|
|
1822
2245
|
});
|
|
1823
2246
|
}
|
|
1824
|
-
getStreamPosition(
|
|
1825
|
-
return this.getStreamPositionUnscheduled(
|
|
2247
|
+
getStreamPosition(target, ctx) {
|
|
2248
|
+
return this.getStreamPositionUnscheduled(target, ctx);
|
|
1826
2249
|
}
|
|
1827
|
-
async getStreamPositionUnscheduled(
|
|
1828
|
-
|
|
2250
|
+
async getStreamPositionUnscheduled(target, ctx) {
|
|
2251
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
2252
|
+
target,
|
|
2253
|
+
ctx?.cacheGenerationClaimId
|
|
2254
|
+
);
|
|
2255
|
+
const collectionId = access.collectionId;
|
|
2256
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
2257
|
+
await this.assertCacheGenerationReadClaim(
|
|
2258
|
+
this.driver,
|
|
2259
|
+
collectionId,
|
|
2260
|
+
ctx?.cacheGenerationClaimId
|
|
2261
|
+
);
|
|
2262
|
+
await this.ensureCollectionReady(collectionId, ctx?.cacheGenerationClaimId);
|
|
1829
2263
|
return this.runInTransaction(async (transactionDriver) => {
|
|
2264
|
+
await this.assertCacheGenerationReadClaim(
|
|
2265
|
+
transactionDriver,
|
|
2266
|
+
collectionId,
|
|
2267
|
+
ctx?.cacheGenerationClaimId
|
|
2268
|
+
);
|
|
1830
2269
|
await this.assertCurrentSchemaVersion(
|
|
1831
2270
|
collectionId,
|
|
1832
2271
|
transactionDriver,
|
|
@@ -1894,16 +2333,35 @@ class SQLiteCorePersistenceAdapter {
|
|
|
1894
2333
|
}
|
|
1895
2334
|
};
|
|
1896
2335
|
}
|
|
1897
|
-
pullSince(
|
|
2336
|
+
pullSince(target, fromRowVersion, ctx) {
|
|
1898
2337
|
return this.runRegular(
|
|
1899
|
-
() => this.pullSinceUnscheduled(
|
|
2338
|
+
() => this.pullSinceUnscheduled(target, fromRowVersion, ctx)
|
|
1900
2339
|
);
|
|
1901
2340
|
}
|
|
1902
|
-
async pullSinceUnscheduled(
|
|
1903
|
-
const
|
|
2341
|
+
async pullSinceUnscheduled(target, fromRowVersion, ctx) {
|
|
2342
|
+
const access = persisted.resolvePersistedStorageTarget(
|
|
2343
|
+
target,
|
|
2344
|
+
ctx?.cacheGenerationClaimId
|
|
2345
|
+
);
|
|
2346
|
+
const collectionId = access.collectionId;
|
|
2347
|
+
ctx = access.claimId ? { ...ctx, cacheGenerationClaimId: access.claimId } : ctx;
|
|
2348
|
+
await this.assertCacheGenerationReadClaim(
|
|
2349
|
+
this.driver,
|
|
2350
|
+
collectionId,
|
|
2351
|
+
ctx?.cacheGenerationClaimId
|
|
2352
|
+
);
|
|
2353
|
+
const tableMapping = await this.ensureCollectionReady(
|
|
2354
|
+
collectionId,
|
|
2355
|
+
ctx?.cacheGenerationClaimId
|
|
2356
|
+
);
|
|
1904
2357
|
const collectionTableSql = quoteIdentifier(tableMapping.tableName);
|
|
1905
2358
|
const tombstoneTableSql = quoteIdentifier(tableMapping.tombstoneTableName);
|
|
1906
2359
|
return this.runInTransaction(async (transactionDriver) => {
|
|
2360
|
+
await this.assertCacheGenerationReadClaim(
|
|
2361
|
+
transactionDriver,
|
|
2362
|
+
collectionId,
|
|
2363
|
+
ctx?.cacheGenerationClaimId
|
|
2364
|
+
);
|
|
1907
2365
|
await this.assertCurrentSchemaVersion(
|
|
1908
2366
|
collectionId,
|
|
1909
2367
|
transactionDriver,
|
|
@@ -2139,7 +2597,7 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2139
2597
|
[collectionId, excessRows]
|
|
2140
2598
|
);
|
|
2141
2599
|
}
|
|
2142
|
-
async ensureCollectionReady(collectionId) {
|
|
2600
|
+
async ensureCollectionReady(collectionId, cacheGenerationClaimId) {
|
|
2143
2601
|
await this.ensureInitialized();
|
|
2144
2602
|
const cached = this.collectionTableCache.get(collectionId);
|
|
2145
2603
|
if (cached) {
|
|
@@ -2149,7 +2607,10 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2149
2607
|
if (inFlight) {
|
|
2150
2608
|
return inFlight;
|
|
2151
2609
|
}
|
|
2152
|
-
const loadPromise = this.ensureCollectionReadyInternal(
|
|
2610
|
+
const loadPromise = this.ensureCollectionReadyInternal(
|
|
2611
|
+
collectionId,
|
|
2612
|
+
cacheGenerationClaimId
|
|
2613
|
+
);
|
|
2153
2614
|
this.collectionTableLoads.set(collectionId, loadPromise);
|
|
2154
2615
|
try {
|
|
2155
2616
|
return await loadPromise;
|
|
@@ -2167,23 +2628,34 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2167
2628
|
);
|
|
2168
2629
|
return rows[0];
|
|
2169
2630
|
}
|
|
2170
|
-
async ensureCollectionReadyInternal(collectionId) {
|
|
2631
|
+
async ensureCollectionReadyInternal(collectionId, cacheGenerationClaimId) {
|
|
2632
|
+
const managedAtAdmission = cacheGenerationClaimId !== void 0 || hasCacheGenerationIdPrefix(collectionId) && (await this.driver.query(
|
|
2633
|
+
`SELECT physical_id FROM cache_generation WHERE physical_id = ?`,
|
|
2634
|
+
[collectionId]
|
|
2635
|
+
))[0] !== void 0;
|
|
2171
2636
|
let registration = await this.loadCollectionRegistration(collectionId);
|
|
2172
2637
|
if (!registration) {
|
|
2173
2638
|
const tableName2 = persisted.createPersistedTableName(collectionId, `c`);
|
|
2174
2639
|
const tombstoneTableName2 = persisted.createPersistedTableName(collectionId, `t`);
|
|
2175
|
-
await this.
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2640
|
+
await this.runInTransaction(async (transactionDriver) => {
|
|
2641
|
+
await this.assertCacheGenerationReadClaim(
|
|
2642
|
+
transactionDriver,
|
|
2643
|
+
collectionId,
|
|
2644
|
+
cacheGenerationClaimId
|
|
2645
|
+
);
|
|
2646
|
+
await transactionDriver.run(
|
|
2647
|
+
`INSERT INTO collection_registry (
|
|
2648
|
+
collection_id,
|
|
2649
|
+
table_name,
|
|
2650
|
+
tombstone_table_name,
|
|
2651
|
+
schema_version,
|
|
2652
|
+
updated_at
|
|
2653
|
+
)
|
|
2654
|
+
VALUES (?, ?, ?, ?, CAST(strftime('%s', 'now') AS INTEGER))
|
|
2655
|
+
ON CONFLICT DO NOTHING`,
|
|
2656
|
+
[collectionId, tableName2, tombstoneTableName2, this.schemaVersion]
|
|
2657
|
+
);
|
|
2658
|
+
});
|
|
2187
2659
|
registration = await this.loadCollectionRegistration(collectionId);
|
|
2188
2660
|
if (!registration) {
|
|
2189
2661
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
@@ -2199,7 +2671,8 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2199
2671
|
registration.schema_version,
|
|
2200
2672
|
this.schemaVersion,
|
|
2201
2673
|
tableName,
|
|
2202
|
-
tombstoneTableName
|
|
2674
|
+
tombstoneTableName,
|
|
2675
|
+
cacheGenerationClaimId
|
|
2203
2676
|
);
|
|
2204
2677
|
}
|
|
2205
2678
|
const collectionTableSql = quoteIdentifier(tableName);
|
|
@@ -2246,6 +2719,35 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2246
2719
|
[collectionId]
|
|
2247
2720
|
);
|
|
2248
2721
|
await this.ensureCollectionKeyEvidenceTriggers(collectionId, tableName);
|
|
2722
|
+
if (managedAtAdmission) {
|
|
2723
|
+
const generation = await this.driver.query(
|
|
2724
|
+
`SELECT physical_id FROM cache_generation WHERE physical_id = ?`,
|
|
2725
|
+
[collectionId]
|
|
2726
|
+
);
|
|
2727
|
+
if (!generation[0]) {
|
|
2728
|
+
await this.driver.exec(
|
|
2729
|
+
`DROP TABLE IF EXISTS ${quoteIdentifier(tableName)}`
|
|
2730
|
+
);
|
|
2731
|
+
await this.driver.exec(
|
|
2732
|
+
`DROP TABLE IF EXISTS ${quoteIdentifier(tombstoneTableName)}`
|
|
2733
|
+
);
|
|
2734
|
+
await this.driver.run(
|
|
2735
|
+
`DELETE FROM collection_registry WHERE collection_id = ?`,
|
|
2736
|
+
[collectionId]
|
|
2737
|
+
);
|
|
2738
|
+
await this.driver.run(
|
|
2739
|
+
`DELETE FROM collection_version WHERE collection_id = ?`,
|
|
2740
|
+
[collectionId]
|
|
2741
|
+
);
|
|
2742
|
+
await this.driver.run(
|
|
2743
|
+
`DELETE FROM collection_reset_epoch WHERE collection_id = ?`,
|
|
2744
|
+
[collectionId]
|
|
2745
|
+
);
|
|
2746
|
+
throw new errors.InvalidPersistedCollectionConfigError(
|
|
2747
|
+
`Persisted cache generation was collected before registration finished`
|
|
2748
|
+
);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2249
2751
|
const mapping = {
|
|
2250
2752
|
tableName,
|
|
2251
2753
|
tombstoneTableName
|
|
@@ -2315,7 +2817,7 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2315
2817
|
END`
|
|
2316
2818
|
);
|
|
2317
2819
|
}
|
|
2318
|
-
async handleSchemaMismatch(collectionId, previousSchemaVersion, nextSchemaVersion, tableName, tombstoneTableName) {
|
|
2820
|
+
async handleSchemaMismatch(collectionId, previousSchemaVersion, nextSchemaVersion, tableName, tombstoneTableName, cacheGenerationClaimId) {
|
|
2319
2821
|
if (this.schemaMismatchPolicy === `sync-absent-error`) {
|
|
2320
2822
|
throw new errors.InvalidPersistedCollectionConfigError(
|
|
2321
2823
|
`Schema version mismatch for collection "${collectionId}": found ${previousSchemaVersion}, expected ${nextSchemaVersion}. Set schemaMismatchPolicy to "sync-present-reset" or "reset" to allow automatic reset.`
|
|
@@ -2324,6 +2826,11 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2324
2826
|
const collectionTableSql = quoteIdentifier(tableName);
|
|
2325
2827
|
const tombstoneTableSql = quoteIdentifier(tombstoneTableName);
|
|
2326
2828
|
await this.runInTransaction(async (transactionDriver) => {
|
|
2829
|
+
await this.assertCacheGenerationReadClaim(
|
|
2830
|
+
transactionDriver,
|
|
2831
|
+
collectionId,
|
|
2832
|
+
cacheGenerationClaimId
|
|
2833
|
+
);
|
|
2327
2834
|
const currentSchemaRows = await transactionDriver.query(
|
|
2328
2835
|
`SELECT schema_version
|
|
2329
2836
|
FROM collection_registry
|
|
@@ -2408,6 +2915,48 @@ class SQLiteCorePersistenceAdapter {
|
|
|
2408
2915
|
if (this.initialized) {
|
|
2409
2916
|
return;
|
|
2410
2917
|
}
|
|
2918
|
+
await this.driver.exec(
|
|
2919
|
+
`CREATE TABLE IF NOT EXISTS cache_generation (
|
|
2920
|
+
logical_id TEXT NOT NULL,
|
|
2921
|
+
generation INTEGER NOT NULL,
|
|
2922
|
+
physical_id TEXT NOT NULL UNIQUE,
|
|
2923
|
+
retired INTEGER NOT NULL DEFAULT 0,
|
|
2924
|
+
PRIMARY KEY (logical_id, generation)
|
|
2925
|
+
)`
|
|
2926
|
+
);
|
|
2927
|
+
await this.driver.exec(
|
|
2928
|
+
`CREATE UNIQUE INDEX IF NOT EXISTS cache_generation_head
|
|
2929
|
+
ON cache_generation (logical_id) WHERE retired = 0`
|
|
2930
|
+
);
|
|
2931
|
+
await this.driver.exec(
|
|
2932
|
+
`CREATE TABLE IF NOT EXISTS cache_generation_sequence (
|
|
2933
|
+
logical_id TEXT PRIMARY KEY,
|
|
2934
|
+
next_generation INTEGER NOT NULL
|
|
2935
|
+
)`
|
|
2936
|
+
);
|
|
2937
|
+
await this.driver.exec(
|
|
2938
|
+
`CREATE TABLE IF NOT EXISTS cache_generation_claim (
|
|
2939
|
+
claim_id TEXT PRIMARY KEY,
|
|
2940
|
+
logical_id TEXT NOT NULL,
|
|
2941
|
+
physical_id TEXT NOT NULL,
|
|
2942
|
+
expires_at_ms INTEGER NOT NULL
|
|
2943
|
+
)`
|
|
2944
|
+
);
|
|
2945
|
+
const claimColumns = await this.driver.query(
|
|
2946
|
+
`PRAGMA table_info(cache_generation_claim)`
|
|
2947
|
+
);
|
|
2948
|
+
if (!claimColumns.some(({ name }) => name === `logical_id`)) {
|
|
2949
|
+
await this.driver.exec(
|
|
2950
|
+
`ALTER TABLE cache_generation_claim
|
|
2951
|
+
ADD COLUMN logical_id TEXT NOT NULL DEFAULT ''`
|
|
2952
|
+
);
|
|
2953
|
+
}
|
|
2954
|
+
if (!claimColumns.some(({ name }) => name === `expires_at_ms`)) {
|
|
2955
|
+
await this.driver.exec(
|
|
2956
|
+
`ALTER TABLE cache_generation_claim
|
|
2957
|
+
ADD COLUMN expires_at_ms INTEGER NOT NULL DEFAULT 0`
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2411
2960
|
await this.driver.exec(
|
|
2412
2961
|
`CREATE TABLE IF NOT EXISTS collection_registry (
|
|
2413
2962
|
collection_id TEXT PRIMARY KEY,
|
|
@@ -2547,6 +3096,7 @@ function createSQLiteCorePersistenceAdapter(options) {
|
|
|
2547
3096
|
}
|
|
2548
3097
|
exports.DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS = DEFAULT_APPLIED_TX_PRUNE_MAX_AGE_SECONDS;
|
|
2549
3098
|
exports.DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS = DEFAULT_APPLIED_TX_PRUNE_MAX_ROWS;
|
|
3099
|
+
exports.DEFAULT_CACHE_GENERATION_CLAIM_TTL_MS = DEFAULT_CACHE_GENERATION_CLAIM_TTL_MS;
|
|
2550
3100
|
exports.SQLiteCorePersistenceAdapter = SQLiteCorePersistenceAdapter;
|
|
2551
3101
|
exports.createSQLiteCorePersistenceAdapter = createSQLiteCorePersistenceAdapter;
|
|
2552
3102
|
//# sourceMappingURL=sqlite-core-adapter.cjs.map
|