@quereus/sync-coordinator 0.8.2 → 0.10.0
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 +12 -3
- package/dist/src/common/index.d.ts +1 -0
- package/dist/src/common/index.d.ts.map +1 -1
- package/dist/src/common/index.js +1 -0
- package/dist/src/common/index.js.map +1 -1
- package/dist/src/common/serialization.d.ts +28 -0
- package/dist/src/common/serialization.d.ts.map +1 -0
- package/dist/src/common/serialization.js +128 -0
- package/dist/src/common/serialization.js.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/metrics/coordinator-metrics.d.ts +1 -0
- package/dist/src/metrics/coordinator-metrics.d.ts.map +1 -1
- package/dist/src/metrics/coordinator-metrics.js +2 -0
- package/dist/src/metrics/coordinator-metrics.js.map +1 -1
- package/dist/src/server/routes.d.ts.map +1 -1
- package/dist/src/server/routes.js +7 -31
- package/dist/src/server/routes.js.map +1 -1
- package/dist/src/server/websocket.d.ts +1 -0
- package/dist/src/server/websocket.d.ts.map +1 -1
- package/dist/src/server/websocket.js +74 -51
- package/dist/src/server/websocket.js.map +1 -1
- package/dist/src/service/coordinator-service.d.ts +10 -5
- package/dist/src/service/coordinator-service.d.ts.map +1 -1
- package/dist/src/service/coordinator-service.js +108 -41
- package/dist/src/service/coordinator-service.js.map +1 -1
- package/dist/src/service/index.d.ts +2 -2
- package/dist/src/service/index.d.ts.map +1 -1
- package/dist/src/service/index.js +1 -1
- package/dist/src/service/index.js.map +1 -1
- package/dist/src/service/s3-batch-store.d.ts +10 -6
- package/dist/src/service/s3-batch-store.d.ts.map +1 -1
- package/dist/src/service/s3-batch-store.js +42 -10
- package/dist/src/service/s3-batch-store.js.map +1 -1
- package/dist/src/service/s3-config.d.ts +10 -0
- package/dist/src/service/s3-config.d.ts.map +1 -1
- package/dist/src/service/s3-config.js +7 -0
- package/dist/src/service/s3-config.js.map +1 -1
- package/dist/src/service/s3-snapshot-store.d.ts +17 -6
- package/dist/src/service/s3-snapshot-store.d.ts.map +1 -1
- package/dist/src/service/s3-snapshot-store.js +64 -15
- package/dist/src/service/s3-snapshot-store.js.map +1 -1
- package/dist/src/service/store-manager.d.ts +32 -0
- package/dist/src/service/store-manager.d.ts.map +1 -1
- package/dist/src/service/store-manager.js +119 -8
- package/dist/src/service/store-manager.js.map +1 -1
- package/dist/src/service/types.d.ts +2 -1
- package/dist/src/service/types.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* - Change volume threshold (e.g., every 1000 changes)
|
|
10
10
|
*/
|
|
11
11
|
import { type S3Client } from '@aws-sdk/client-s3';
|
|
12
|
-
import { type S3StorageConfig } from './s3-config.js';
|
|
13
|
-
import type { SyncManager } from '@quereus/sync';
|
|
12
|
+
import { type S3StorageConfig, type StoragePathResolver } from './s3-config.js';
|
|
13
|
+
import type { SyncManager, SnapshotChunk } from '@quereus/sync';
|
|
14
14
|
/**
|
|
15
15
|
* Snapshot metadata stored alongside the snapshot.
|
|
16
16
|
*/
|
|
@@ -49,10 +49,6 @@ interface DatabaseSnapshotState {
|
|
|
49
49
|
changesSinceSnapshot: number;
|
|
50
50
|
snapshotInProgress: boolean;
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Function to resolve a database ID to a storage path for S3 keys.
|
|
54
|
-
*/
|
|
55
|
-
export type StoragePathResolver = (databaseId: string) => string;
|
|
56
52
|
/**
|
|
57
53
|
* S3 Snapshot Store for full database snapshots.
|
|
58
54
|
*/
|
|
@@ -96,10 +92,25 @@ export declare class S3SnapshotStore {
|
|
|
96
92
|
* Check if a snapshot exists for a database.
|
|
97
93
|
*/
|
|
98
94
|
hasSnapshot(databaseId: string): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Download and deserialize the latest snapshot for a database.
|
|
97
|
+
* Returns null if no snapshots exist.
|
|
98
|
+
*/
|
|
99
|
+
downloadLatestSnapshot(databaseId: string): Promise<{
|
|
100
|
+
chunks: SnapshotChunk[];
|
|
101
|
+
metadata: {
|
|
102
|
+
snapshotId: string;
|
|
103
|
+
timestamp: string;
|
|
104
|
+
};
|
|
105
|
+
} | null>;
|
|
99
106
|
/**
|
|
100
107
|
* Compress data using gzip.
|
|
101
108
|
*/
|
|
102
109
|
private compressData;
|
|
110
|
+
/**
|
|
111
|
+
* Decompress gzipped data.
|
|
112
|
+
*/
|
|
113
|
+
private decompressData;
|
|
103
114
|
/**
|
|
104
115
|
* Get databases that need snapshots (for external scheduling).
|
|
105
116
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3-snapshot-store.d.ts","sourceRoot":"","sources":["../../../src/service/s3-snapshot-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"s3-snapshot-store.d.ts","sourceRoot":"","sources":["../../../src/service/s3-snapshot-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,22 +8,17 @@
|
|
|
8
8
|
* - Time interval (e.g., every 5 minutes)
|
|
9
9
|
* - Change volume threshold (e.g., every 1000 changes)
|
|
10
10
|
*/
|
|
11
|
-
import { PutObjectCommand } from '@aws-sdk/client-s3';
|
|
11
|
+
import { GetObjectCommand, ListObjectsV2Command, PutObjectCommand } from '@aws-sdk/client-s3';
|
|
12
12
|
import { randomUUID } from 'node:crypto';
|
|
13
|
-
import { createGzip } from 'node:zlib';
|
|
13
|
+
import { createGunzip, createGzip } from 'node:zlib';
|
|
14
14
|
import { serviceLog } from '../common/logger.js';
|
|
15
|
-
import {
|
|
15
|
+
import { serializeSnapshotChunk, deserializeSnapshotChunk } from '../common/serialization.js';
|
|
16
|
+
import { buildSnapshotKey, defaultStoragePathResolver, } from './s3-config.js';
|
|
16
17
|
const DEFAULT_SCHEDULE_CONFIG = {
|
|
17
18
|
intervalMs: 5 * 60 * 1000, // 5 minutes
|
|
18
19
|
changeThreshold: 1000,
|
|
19
20
|
maxRetained: 5,
|
|
20
21
|
};
|
|
21
|
-
/**
|
|
22
|
-
* Default storage path resolver - sanitizes databaseId for use as S3 path.
|
|
23
|
-
*/
|
|
24
|
-
function defaultStoragePathResolver(databaseId) {
|
|
25
|
-
return databaseId.replace(/:/g, '/').replace(/[^a-zA-Z0-9/_-]/g, '_');
|
|
26
|
-
}
|
|
27
22
|
/**
|
|
28
23
|
* S3 Snapshot Store for full database snapshots.
|
|
29
24
|
*/
|
|
@@ -137,8 +132,11 @@ export class S3SnapshotStore {
|
|
|
137
132
|
totalTables++;
|
|
138
133
|
}
|
|
139
134
|
}
|
|
140
|
-
// Serialize
|
|
141
|
-
const jsonData = JSON.stringify({
|
|
135
|
+
// Serialize chunks for JSON-safe storage, then compress
|
|
136
|
+
const jsonData = JSON.stringify({
|
|
137
|
+
snapshotId, databaseId, timestamp,
|
|
138
|
+
chunks: chunks.map(c => serializeSnapshotChunk(c)),
|
|
139
|
+
});
|
|
142
140
|
const compressed = await this.compressData(jsonData);
|
|
143
141
|
// Upload to S3
|
|
144
142
|
await this.client.send(new PutObjectCommand({
|
|
@@ -183,11 +181,49 @@ export class S3SnapshotStore {
|
|
|
183
181
|
*/
|
|
184
182
|
async hasSnapshot(databaseId) {
|
|
185
183
|
const storagePath = this.resolveStoragePath(databaseId);
|
|
186
|
-
// Check for latest snapshot pattern
|
|
187
184
|
const prefix = this.config.keyPrefix ?? '';
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
185
|
+
const listPrefix = `${prefix}${storagePath}/snapshots/`;
|
|
186
|
+
const command = new ListObjectsV2Command({
|
|
187
|
+
Bucket: this.config.bucket,
|
|
188
|
+
Prefix: listPrefix,
|
|
189
|
+
MaxKeys: 1,
|
|
190
|
+
});
|
|
191
|
+
const response = await this.client.send(command);
|
|
192
|
+
return (response.KeyCount ?? 0) > 0;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Download and deserialize the latest snapshot for a database.
|
|
196
|
+
* Returns null if no snapshots exist.
|
|
197
|
+
*/
|
|
198
|
+
async downloadLatestSnapshot(databaseId) {
|
|
199
|
+
const storagePath = this.resolveStoragePath(databaseId);
|
|
200
|
+
const prefix = this.config.keyPrefix ?? '';
|
|
201
|
+
const listPrefix = `${prefix}${storagePath}/snapshots/`;
|
|
202
|
+
const response = await this.client.send(new ListObjectsV2Command({
|
|
203
|
+
Bucket: this.config.bucket,
|
|
204
|
+
Prefix: listPrefix,
|
|
205
|
+
}));
|
|
206
|
+
if (!response.Contents?.length)
|
|
207
|
+
return null;
|
|
208
|
+
// Keys have timestamp prefix → alphabetical order is chronological
|
|
209
|
+
const sorted = response.Contents
|
|
210
|
+
.filter(obj => obj.Key)
|
|
211
|
+
.sort((a, b) => a.Key.localeCompare(b.Key));
|
|
212
|
+
const latestKey = sorted[sorted.length - 1].Key;
|
|
213
|
+
serviceLog('Downloading snapshot for %s: %s', databaseId, latestKey);
|
|
214
|
+
const getResponse = await this.client.send(new GetObjectCommand({
|
|
215
|
+
Bucket: this.config.bucket,
|
|
216
|
+
Key: latestKey,
|
|
217
|
+
}));
|
|
218
|
+
const compressed = await getResponse.Body.transformToByteArray();
|
|
219
|
+
const decompressed = await this.decompressData(Buffer.from(compressed));
|
|
220
|
+
const data = JSON.parse(decompressed);
|
|
221
|
+
const chunks = data.chunks.map(c => deserializeSnapshotChunk(c));
|
|
222
|
+
serviceLog('Downloaded snapshot for %s: %s (%d chunks)', databaseId, data.snapshotId, chunks.length);
|
|
223
|
+
return {
|
|
224
|
+
chunks,
|
|
225
|
+
metadata: { snapshotId: data.snapshotId, timestamp: data.timestamp },
|
|
226
|
+
};
|
|
191
227
|
}
|
|
192
228
|
/**
|
|
193
229
|
* Compress data using gzip.
|
|
@@ -202,6 +238,19 @@ export class S3SnapshotStore {
|
|
|
202
238
|
gzip.end(Buffer.from(data, 'utf-8'));
|
|
203
239
|
});
|
|
204
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Decompress gzipped data.
|
|
243
|
+
*/
|
|
244
|
+
async decompressData(data) {
|
|
245
|
+
const gunzip = createGunzip();
|
|
246
|
+
const buffers = [];
|
|
247
|
+
gunzip.on('data', (chunk) => buffers.push(chunk));
|
|
248
|
+
return new Promise((resolve, reject) => {
|
|
249
|
+
gunzip.on('end', () => resolve(Buffer.concat(buffers).toString('utf-8')));
|
|
250
|
+
gunzip.on('error', reject);
|
|
251
|
+
gunzip.end(data);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
205
254
|
/**
|
|
206
255
|
* Get databases that need snapshots (for external scheduling).
|
|
207
256
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3-snapshot-store.js","sourceRoot":"","sources":["../../../src/service/s3-snapshot-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,gBAAgB,EAAiB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"s3-snapshot-store.js","sourceRoot":"","sources":["../../../src/service/s3-snapshot-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAiB,MAAM,oBAAoB,CAAC;AAC7G,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAC9F,OAAO,EAGN,gBAAgB,EAChB,0BAA0B,GAC1B,MAAM,gBAAgB,CAAC;AA2CxB,MAAM,uBAAuB,GAA2B;IACtD,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,YAAY;IACvC,eAAe,EAAE,IAAI;IACrB,WAAW,EAAE,CAAC;CACf,CAAC;AAWF;;GAEG;AACH,MAAM,OAAO,eAAe;IACT,MAAM,CAAW;IACjB,MAAM,CAAkB;IACxB,cAAc,CAAyB;IACvC,kBAAkB,CAAsB;IACxC,cAAc,GAAG,IAAI,GAAG,EAAiC,CAAC;IACnE,UAAU,GAA0C,IAAI,CAAC;IAEjE,YACE,MAAgB,EAChB,MAAuB,EACvB,iBAAkD,EAAE,EACpD,kBAAwC;QAExC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,cAAc,GAAG,EAAE,GAAG,uBAAuB,EAAE,GAAG,cAAc,EAAE,CAAC;QACxE,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,IAAI,0BAA0B,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,yDAAyD;QACzD,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,uBAAuB,EAAE,EAAE,MAAM,CAAC,CAAC;QAC5E,UAAU,CAAC,0DAA0D,EACnE,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;IACzE,CAAC;IAED;;OAEG;IACH,IAAI;QACF,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,UAAkB,EAAE,WAAmB;QACnD,IAAI,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG;gBACN,cAAc,EAAE,CAAC;gBACjB,oBAAoB,EAAE,CAAC;gBACvB,kBAAkB,EAAE,KAAK;aAC1B,CAAC;YACF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;QACD,KAAK,CAAC,oBAAoB,IAAI,WAAW,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,UAAkB;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,kBAAkB;YAAE,OAAO,KAAK,CAAC;QAErD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,iBAAiB,GAAG,GAAG,GAAG,KAAK,CAAC,cAAc,CAAC;QAErD,sBAAsB;QACtB,IAAI,iBAAiB,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,yBAAyB;QACzB,IAAI,KAAK,CAAC,oBAAoB,IAAI,IAAI,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC;YACtE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,uBAAuB;QAC7B,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;YACpD,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;gBACnC,UAAU,CAAC,sCAAsC,EAAE,UAAU,CAAC,CAAC;gBAC/D,2DAA2D;gBAC3D,4CAA4C;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAClB,UAAkB,EAClB,WAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI;YACnD,cAAc,EAAE,CAAC;YACjB,oBAAoB,EAAE,CAAC;YACvB,kBAAkB,EAAE,KAAK;SAC1B,CAAC;QACF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAE3C,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,oCAAoC,UAAU,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,KAAK,CAAC,kBAAkB,GAAG,IAAI,CAAC;QAChC,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE3C,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;YACxD,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;YAE9E,kDAAkD;YAClD,IAAI,YAAY,GAAG,CAAC,CAAC;YACrB,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,MAAM,MAAM,GAAoB,EAAE,CAAC;YAEnC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,WAAW,CAAC,iBAAiB,EAAE,EAAE,CAAC;gBAC1D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnB,IAAI,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;oBACtC,YAAY,IAAI,KAAK,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;gBAC7C,CAAC;qBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;oBACxC,WAAW,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC;YAED,wDAAwD;YACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC9B,UAAU,EAAE,UAAU,EAAE,SAAS;gBACjC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;aACnD,CAAC,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAErD,eAAe;YACf,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC;gBAC1C,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;gBAC1B,GAAG,EAAE,GAAG;gBACR,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,kBAAkB;gBAC/B,eAAe,EAAE,MAAM;gBACvB,QAAQ,EAAE;oBACR,eAAe,EAAE,UAAU;oBAC3B,eAAe,EAAE,UAAU;oBAC3B,eAAe,EAAE,MAAM,CAAC,YAAY,CAAC;oBACrC,eAAe,EAAE,MAAM,CAAC,WAAW,CAAC;iBACrC;aACF,CAAC,CAAC,CAAC;YAEJ,MAAM,QAAQ,GAAqB;gBACjC,UAAU;gBACV,UAAU;gBACV,SAAS;gBACT,SAAS,EAAE,YAAY,EAAE,gCAAgC;gBACzD,WAAW;gBACX,mBAAmB,EAAE,UAAU,CAAC,MAAM;aACvC,CAAC;YAEF,UAAU,CAAC,wDAAwD,EACjE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YAE5D,eAAe;YACf,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAClC,KAAK,CAAC,oBAAoB,GAAG,CAAC,CAAC;YAE/B,OAAO,QAAQ,CAAC;QAClB,CAAC;gBAAS,CAAC;YACT,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC;QACnC,CAAC;IACH,CAAC;IAED;;OAEG;IACK,qBAAqB,CAAC,KAAoB;QAChD,OAAO,KAAK,CAAC,IAAI,KAAK,iBAAiB,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,UAAkB;QAClC,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,GAAG,MAAM,GAAG,WAAW,aAAa,CAAC;QAExD,MAAM,OAAO,GAAG,IAAI,oBAAoB,CAAC;YACvC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,CAAC;SACX,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,sBAAsB,CAAC,UAAkB;QAI7C,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,GAAG,MAAM,GAAG,WAAW,aAAa,CAAC;QAExD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,oBAAoB,CAAC;YAC/D,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC,CAAC;QAEJ,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM;YAAE,OAAO,IAAI,CAAC;QAE5C,mEAAmE;QACnE,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ;aAC7B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;aACtB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAI,CAAC,aAAa,CAAC,CAAC,CAAC,GAAI,CAAC,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,GAAI,CAAC;QAEjD,UAAU,CAAC,iCAAiC,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAErE,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC;YAC9D,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM;YAC1B,GAAG,EAAE,SAAS;SACf,CAAC,CAAC,CAAC;QAEJ,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,IAAK,CAAC,oBAAoB,EAAE,CAAC;QAClE,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QACxE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAI,IAAI,CAAC,MAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhF,UAAU,CAAC,4CAA4C,EACrD,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAE9C,OAAO;YACL,MAAM;YACN,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE;SACrE,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,YAAY,CAAC,IAAY;QACrC,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAEhD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACtD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACzB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,cAAc,CAAC,IAAY;QACvC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAE1D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1E,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC3B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,2BAA2B;QACzB,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;YACpD,IAAI,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,UAAkB,EAAE,WAAwB;QAC9D,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,UAAkB;QACzB,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC7C,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAgB,EAChB,MAAuB,EACvB,cAAgD,EAChD,kBAAwC;IAExC,OAAO,IAAI,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -18,6 +18,8 @@ export interface StoreEntry {
|
|
|
18
18
|
storeEvents: StoreEventEmitter;
|
|
19
19
|
refCount: number;
|
|
20
20
|
lastAccess: number;
|
|
21
|
+
/** True if no local data existed before this store was opened. */
|
|
22
|
+
isNew?: boolean;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Context passed to store hooks for auth-aware decisions.
|
|
@@ -68,6 +70,12 @@ export interface StoreManagerConfig {
|
|
|
68
70
|
};
|
|
69
71
|
/** Hooks for customizing behavior */
|
|
70
72
|
hooks?: StoreManagerHooks;
|
|
73
|
+
/** Called when a new store is created (no pre-existing local data). Used for S3 restore. */
|
|
74
|
+
onStoreCreated?: (entry: StoreEntry) => Promise<void>;
|
|
75
|
+
/** Idle time (ms) before a closed store's local directory is eligible for disk eviction. 0 = disabled. */
|
|
76
|
+
diskEvictionIdleMs?: number;
|
|
77
|
+
/** Called to confirm a closed store can be safely evicted from disk. Return true to proceed with deletion. */
|
|
78
|
+
onEvictStore?: (databaseId: string) => Promise<boolean>;
|
|
71
79
|
}
|
|
72
80
|
/**
|
|
73
81
|
* Manages multiple LevelDB stores for multi-tenant sync.
|
|
@@ -77,8 +85,15 @@ export declare class StoreManager {
|
|
|
77
85
|
private readonly resolveStoragePath;
|
|
78
86
|
private readonly isValidDatabaseId;
|
|
79
87
|
private readonly stores;
|
|
88
|
+
private readonly pendingOpens;
|
|
89
|
+
private readonly onStoreCreated?;
|
|
90
|
+
/** Tracks closed stores eligible for disk eviction: databaseId → { storagePath, closedAt } */
|
|
91
|
+
private readonly closedStores;
|
|
92
|
+
private readonly diskEvictionIdleMs;
|
|
93
|
+
private readonly onEvictStore?;
|
|
80
94
|
private cleanupTimer;
|
|
81
95
|
private shutdownPromise;
|
|
96
|
+
private _shuttingDown;
|
|
82
97
|
constructor(config?: Partial<StoreManagerConfig>);
|
|
83
98
|
/**
|
|
84
99
|
* Start the store manager (begins cleanup interval).
|
|
@@ -86,6 +101,7 @@ export declare class StoreManager {
|
|
|
86
101
|
start(): void;
|
|
87
102
|
/**
|
|
88
103
|
* Get or open a store for a database. Increments refCount.
|
|
104
|
+
* Uses pendingOpens to prevent concurrent open+restore for the same databaseId.
|
|
89
105
|
* @param databaseId The database identifier
|
|
90
106
|
* @param context Optional auth context for auth-aware path resolution
|
|
91
107
|
*/
|
|
@@ -106,6 +122,10 @@ export declare class StoreManager {
|
|
|
106
122
|
* Get count of open stores.
|
|
107
123
|
*/
|
|
108
124
|
get openCount(): number;
|
|
125
|
+
/**
|
|
126
|
+
* Get count of closed stores pending disk eviction.
|
|
127
|
+
*/
|
|
128
|
+
get evictionCandidateCount(): number;
|
|
109
129
|
/**
|
|
110
130
|
* Check if a database ID is valid.
|
|
111
131
|
* @param databaseId The database identifier
|
|
@@ -116,17 +136,29 @@ export declare class StoreManager {
|
|
|
116
136
|
* Shutdown all stores.
|
|
117
137
|
*/
|
|
118
138
|
shutdown(): Promise<void>;
|
|
139
|
+
/**
|
|
140
|
+
* Open a store and run the onStoreCreated callback if the store is new.
|
|
141
|
+
* On callback failure, closes the store and rethrows.
|
|
142
|
+
*/
|
|
143
|
+
private openAndRestore;
|
|
119
144
|
private openStore;
|
|
120
145
|
/**
|
|
121
146
|
* Cleanup idle stores with refCount=0 past timeout.
|
|
122
147
|
*/
|
|
123
148
|
private cleanup;
|
|
149
|
+
/**
|
|
150
|
+
* Evict closed stores from local disk if they've been idle long enough
|
|
151
|
+
* and the eviction callback confirms safety (e.g. data is durable in S3).
|
|
152
|
+
*/
|
|
153
|
+
private evictFromDisk;
|
|
124
154
|
/**
|
|
125
155
|
* Evict least recently used store (with refCount=0).
|
|
126
156
|
*/
|
|
127
157
|
private evictLRU;
|
|
128
158
|
/**
|
|
129
159
|
* Close a specific store.
|
|
160
|
+
* Re-checks refCount to avoid closing a store acquired between the eviction
|
|
161
|
+
* decision and this call (race window across await boundaries).
|
|
130
162
|
*/
|
|
131
163
|
private closeStore;
|
|
132
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-manager.d.ts","sourceRoot":"","sources":["../../../src/service/store-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"store-manager.d.ts","sourceRoot":"","sources":["../../../src/service/store-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* parsing and path resolution via hooks in StoreManagerConfig.
|
|
10
10
|
*/
|
|
11
11
|
import { join } from 'node:path';
|
|
12
|
-
import {
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
13
|
+
import { mkdir, rm } from 'node:fs/promises';
|
|
13
14
|
import { StoreEventEmitter } from '@quereus/store';
|
|
14
15
|
import { LevelDBStore } from '@quereus/plugin-leveldb';
|
|
15
16
|
import { createSyncModule, } from '@quereus/sync';
|
|
@@ -58,12 +59,22 @@ export class StoreManager {
|
|
|
58
59
|
resolveStoragePath;
|
|
59
60
|
isValidDatabaseId;
|
|
60
61
|
stores = new Map();
|
|
62
|
+
pendingOpens = new Map();
|
|
63
|
+
onStoreCreated;
|
|
64
|
+
/** Tracks closed stores eligible for disk eviction: databaseId → { storagePath, closedAt } */
|
|
65
|
+
closedStores = new Map();
|
|
66
|
+
diskEvictionIdleMs;
|
|
67
|
+
onEvictStore;
|
|
61
68
|
cleanupTimer = null;
|
|
62
69
|
shutdownPromise = null;
|
|
70
|
+
_shuttingDown = false;
|
|
63
71
|
constructor(config = {}) {
|
|
64
72
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
65
73
|
this.resolveStoragePath = config.hooks?.resolveStoragePath ?? defaultResolveStoragePath;
|
|
66
74
|
this.isValidDatabaseId = config.hooks?.isValidDatabaseId ?? defaultIsValidDatabaseId;
|
|
75
|
+
this.onStoreCreated = config.onStoreCreated;
|
|
76
|
+
this.diskEvictionIdleMs = config.diskEvictionIdleMs ?? 0;
|
|
77
|
+
this.onEvictStore = config.onEvictStore;
|
|
67
78
|
}
|
|
68
79
|
/**
|
|
69
80
|
* Start the store manager (begins cleanup interval).
|
|
@@ -76,10 +87,13 @@ export class StoreManager {
|
|
|
76
87
|
}
|
|
77
88
|
/**
|
|
78
89
|
* Get or open a store for a database. Increments refCount.
|
|
90
|
+
* Uses pendingOpens to prevent concurrent open+restore for the same databaseId.
|
|
79
91
|
* @param databaseId The database identifier
|
|
80
92
|
* @param context Optional auth context for auth-aware path resolution
|
|
81
93
|
*/
|
|
82
94
|
async acquire(databaseId, context) {
|
|
95
|
+
// Remove from eviction candidates — store is being (re-)opened
|
|
96
|
+
this.closedStores.delete(databaseId);
|
|
83
97
|
// Check if already open
|
|
84
98
|
let entry = this.stores.get(databaseId);
|
|
85
99
|
if (entry) {
|
|
@@ -88,15 +102,31 @@ export class StoreManager {
|
|
|
88
102
|
serviceLog('Store acquired (cached): %s, refCount=%d', databaseId, entry.refCount);
|
|
89
103
|
return entry;
|
|
90
104
|
}
|
|
105
|
+
// Check if open+restore is already in progress for this databaseId
|
|
106
|
+
const pending = this.pendingOpens.get(databaseId);
|
|
107
|
+
if (pending) {
|
|
108
|
+
entry = await pending;
|
|
109
|
+
entry.refCount++;
|
|
110
|
+
entry.lastAccess = Date.now();
|
|
111
|
+
serviceLog('Store acquired (waited for pending open): %s, refCount=%d', databaseId, entry.refCount);
|
|
112
|
+
return entry;
|
|
113
|
+
}
|
|
91
114
|
// Check if we need to evict before opening new
|
|
92
115
|
if (this.stores.size >= this.config.maxOpenStores) {
|
|
93
116
|
await this.evictLRU();
|
|
94
117
|
}
|
|
95
|
-
// Open new store
|
|
96
|
-
|
|
97
|
-
this.
|
|
98
|
-
|
|
99
|
-
|
|
118
|
+
// Open new store with dedup via pendingOpens
|
|
119
|
+
const openPromise = this.openAndRestore(databaseId, context);
|
|
120
|
+
this.pendingOpens.set(databaseId, openPromise);
|
|
121
|
+
try {
|
|
122
|
+
entry = await openPromise;
|
|
123
|
+
this.stores.set(databaseId, entry);
|
|
124
|
+
serviceLog('Store acquired (opened): %s', databaseId);
|
|
125
|
+
return entry;
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
this.pendingOpens.delete(databaseId);
|
|
129
|
+
}
|
|
100
130
|
}
|
|
101
131
|
/**
|
|
102
132
|
* Release a store reference. Decrements refCount.
|
|
@@ -127,6 +157,12 @@ export class StoreManager {
|
|
|
127
157
|
get openCount() {
|
|
128
158
|
return this.stores.size;
|
|
129
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Get count of closed stores pending disk eviction.
|
|
162
|
+
*/
|
|
163
|
+
get evictionCandidateCount() {
|
|
164
|
+
return this.closedStores.size;
|
|
165
|
+
}
|
|
130
166
|
/**
|
|
131
167
|
* Check if a database ID is valid.
|
|
132
168
|
* @param databaseId The database identifier
|
|
@@ -141,6 +177,7 @@ export class StoreManager {
|
|
|
141
177
|
async shutdown() {
|
|
142
178
|
if (this.shutdownPromise)
|
|
143
179
|
return this.shutdownPromise;
|
|
180
|
+
this._shuttingDown = true;
|
|
144
181
|
this.shutdownPromise = (async () => {
|
|
145
182
|
if (this.cleanupTimer) {
|
|
146
183
|
clearInterval(this.cleanupTimer);
|
|
@@ -157,10 +194,28 @@ export class StoreManager {
|
|
|
157
194
|
});
|
|
158
195
|
await Promise.all(closePromises);
|
|
159
196
|
this.stores.clear();
|
|
197
|
+
this.closedStores.clear();
|
|
160
198
|
serviceLog('StoreManager shutdown complete');
|
|
161
199
|
})();
|
|
162
200
|
return this.shutdownPromise;
|
|
163
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Open a store and run the onStoreCreated callback if the store is new.
|
|
204
|
+
* On callback failure, closes the store and rethrows.
|
|
205
|
+
*/
|
|
206
|
+
async openAndRestore(databaseId, context) {
|
|
207
|
+
const entry = await this.openStore(databaseId, context);
|
|
208
|
+
if (entry.isNew && this.onStoreCreated) {
|
|
209
|
+
try {
|
|
210
|
+
await this.onStoreCreated(entry);
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
await entry.store.close();
|
|
214
|
+
throw err;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return entry;
|
|
218
|
+
}
|
|
164
219
|
async openStore(databaseId, context) {
|
|
165
220
|
// Validate database ID
|
|
166
221
|
if (!this.isValidDatabaseId(databaseId, context)) {
|
|
@@ -168,10 +223,12 @@ export class StoreManager {
|
|
|
168
223
|
}
|
|
169
224
|
const storagePath = this.resolveStoragePath(databaseId, context);
|
|
170
225
|
const fullPath = join(this.config.dataDir, storagePath);
|
|
226
|
+
// Detect whether local data already exists before creating directories
|
|
227
|
+
const isNew = !existsSync(fullPath);
|
|
171
228
|
// Ensure parent directories exist (org folder for new org-based format)
|
|
172
229
|
const parentPath = join(this.config.dataDir, storagePath.split('/')[0]);
|
|
173
230
|
await mkdir(parentPath, { recursive: true });
|
|
174
|
-
serviceLog('Opening store at: %s', fullPath);
|
|
231
|
+
serviceLog('Opening store at: %s (isNew=%s)', fullPath, isNew);
|
|
175
232
|
const store = await LevelDBStore.open({
|
|
176
233
|
path: fullPath,
|
|
177
234
|
createIfMissing: true,
|
|
@@ -185,12 +242,15 @@ export class StoreManager {
|
|
|
185
242
|
storeEvents,
|
|
186
243
|
refCount: 1,
|
|
187
244
|
lastAccess: Date.now(),
|
|
245
|
+
isNew,
|
|
188
246
|
};
|
|
189
247
|
}
|
|
190
248
|
/**
|
|
191
249
|
* Cleanup idle stores with refCount=0 past timeout.
|
|
192
250
|
*/
|
|
193
251
|
async cleanup() {
|
|
252
|
+
if (this._shuttingDown)
|
|
253
|
+
return;
|
|
194
254
|
const now = Date.now();
|
|
195
255
|
const toClose = [];
|
|
196
256
|
for (const [id, entry] of this.stores) {
|
|
@@ -204,6 +264,45 @@ export class StoreManager {
|
|
|
204
264
|
if (toClose.length > 0) {
|
|
205
265
|
serviceLog('Cleanup: closed %d idle stores', toClose.length);
|
|
206
266
|
}
|
|
267
|
+
// Disk eviction: delete local directories for closed stores past the eviction threshold
|
|
268
|
+
if (this.diskEvictionIdleMs > 0 && this.onEvictStore) {
|
|
269
|
+
await this.evictFromDisk(now);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Evict closed stores from local disk if they've been idle long enough
|
|
274
|
+
* and the eviction callback confirms safety (e.g. data is durable in S3).
|
|
275
|
+
*/
|
|
276
|
+
async evictFromDisk(now) {
|
|
277
|
+
const toEvict = [];
|
|
278
|
+
for (const [databaseId, info] of this.closedStores) {
|
|
279
|
+
// Skip if store was re-opened since being closed
|
|
280
|
+
if (this.stores.has(databaseId) || this.pendingOpens.has(databaseId)) {
|
|
281
|
+
this.closedStores.delete(databaseId);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (now - info.closedAt >= this.diskEvictionIdleMs) {
|
|
285
|
+
toEvict.push(databaseId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
for (const databaseId of toEvict) {
|
|
289
|
+
const info = this.closedStores.get(databaseId);
|
|
290
|
+
try {
|
|
291
|
+
const canEvict = await this.onEvictStore(databaseId);
|
|
292
|
+
if (!canEvict)
|
|
293
|
+
continue;
|
|
294
|
+
const fullPath = join(this.config.dataDir, info.storagePath);
|
|
295
|
+
await rm(fullPath, { recursive: true, force: true });
|
|
296
|
+
this.closedStores.delete(databaseId);
|
|
297
|
+
serviceLog('Disk eviction: deleted local directory for %s', databaseId);
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
serviceLog('Disk eviction failed for %s (non-fatal): %O', databaseId, err);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (toEvict.length > 0) {
|
|
304
|
+
serviceLog('Disk eviction: processed %d candidates', toEvict.length);
|
|
305
|
+
}
|
|
207
306
|
}
|
|
208
307
|
/**
|
|
209
308
|
* Evict least recently used store (with refCount=0).
|
|
@@ -228,15 +327,27 @@ export class StoreManager {
|
|
|
228
327
|
}
|
|
229
328
|
/**
|
|
230
329
|
* Close a specific store.
|
|
330
|
+
* Re-checks refCount to avoid closing a store acquired between the eviction
|
|
331
|
+
* decision and this call (race window across await boundaries).
|
|
231
332
|
*/
|
|
232
|
-
async closeStore(databaseId) {
|
|
333
|
+
async closeStore(databaseId, context) {
|
|
233
334
|
const entry = this.stores.get(databaseId);
|
|
234
335
|
if (!entry)
|
|
235
336
|
return;
|
|
337
|
+
// Guard against race: another async op may have acquired this store
|
|
338
|
+
// between the caller's refCount check and now.
|
|
339
|
+
if (entry.refCount > 0)
|
|
340
|
+
return;
|
|
341
|
+
// Resolve storage path before closing (needed for eviction tracking)
|
|
342
|
+
const storagePath = this.resolveStoragePath(databaseId, context);
|
|
236
343
|
try {
|
|
237
344
|
await entry.store.close();
|
|
238
345
|
this.stores.delete(databaseId);
|
|
239
346
|
serviceLog('Store closed: %s', databaseId);
|
|
347
|
+
// Track for disk eviction if configured
|
|
348
|
+
if (this.diskEvictionIdleMs > 0 && this.onEvictStore) {
|
|
349
|
+
this.closedStores.set(databaseId, { storagePath, closedAt: Date.now() });
|
|
350
|
+
}
|
|
240
351
|
}
|
|
241
352
|
catch (err) {
|
|
242
353
|
serviceLog('Error closing store %s: %O', databaseId, err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-manager.js","sourceRoot":"","sources":["../../../src/service/store-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"store-manager.js","sourceRoot":"","sources":["../../../src/service/store-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -133,9 +133,10 @@ export interface CoordinatorHooks {
|
|
|
133
133
|
*
|
|
134
134
|
* @param client - Authenticated client identity
|
|
135
135
|
* @param socket - The WebSocket connection
|
|
136
|
+
* @param databaseId - The database the client is connecting to
|
|
136
137
|
* @returns true to accept, false to reject
|
|
137
138
|
*/
|
|
138
|
-
onClientConnect?(client: ClientIdentity, socket: WebSocket): Promise<boolean>;
|
|
139
|
+
onClientConnect?(client: ClientIdentity, socket: WebSocket, databaseId: string): Promise<boolean>;
|
|
139
140
|
/**
|
|
140
141
|
* Called when a WebSocket client disconnects.
|
|
141
142
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/service/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EACV,MAAM,EACN,GAAG,EACH,SAAS,EACT,WAAW,EACZ,MAAM,eAAe,CAAC;AAMvB;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,gCAAgC;IAChC,WAAW,EAAE,GAAG,GAAG,SAAS,CAAC;IAC7B,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,MAAM,EAAE,SAAS,CAAC;CACnB;AAMD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,EAAE,GAAG,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAMhC;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0BAA0B;IAC1B,MAAM,EAAE,SAAS,CAAC;IAClB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,iCAAiC;IACjC,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAMD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,cAAc,CAAC,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAE/D;;;;;;;OAOG;IACH,WAAW,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjF;;;;;;;OAOG;IACH,oBAAoB,CAAC,CACnB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,SAAS,EAAE,GACnB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE7B;;;;;;;OAOG;IACH,mBAAmB,CAAC,CAClB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,SAAS,EAAE,EACpB,MAAM,EAAE,WAAW,GAClB,IAAI,CAAC;IAER
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/service/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quereus/sync-coordinator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Standalone coordinator backend for Quereus Sync - production-ready sync server",
|
|
6
6
|
"keywords": [
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"@aws-sdk/client-s3": "^3.970.0",
|
|
47
47
|
"@fastify/cors": "^11.2.0",
|
|
48
48
|
"@fastify/websocket": "^11.2.0",
|
|
49
|
-
"@quereus/isolation": "^0.
|
|
50
|
-
"@quereus/plugin-leveldb": "^0.
|
|
51
|
-
"@quereus/quereus": "^0.
|
|
52
|
-
"@quereus/store": "^0.
|
|
53
|
-
"@quereus/sync": "^0.
|
|
49
|
+
"@quereus/isolation": "^0.3.0",
|
|
50
|
+
"@quereus/plugin-leveldb": "^0.6.0",
|
|
51
|
+
"@quereus/quereus": "^0.18.0",
|
|
52
|
+
"@quereus/store": "^0.7.0",
|
|
53
|
+
"@quereus/sync": "^0.8.0",
|
|
54
54
|
"commander": "^14.0.2",
|
|
55
55
|
"debug": "^4.4.3",
|
|
56
56
|
"fastify": "^5.7.0"
|