sliftutils 0.65.0 → 0.67.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/index.d.ts
CHANGED
|
@@ -938,9 +938,6 @@ declare module "sliftutils/storage/StorageObservable" {
|
|
|
938
938
|
synced: {
|
|
939
939
|
keySeqNum: number;
|
|
940
940
|
};
|
|
941
|
-
resynced: {
|
|
942
|
-
seqNum: number;
|
|
943
|
-
};
|
|
944
941
|
constructor(storage: IStorage<T>);
|
|
945
942
|
get(key: string): T | undefined;
|
|
946
943
|
set(key: string, value: T): void;
|
|
@@ -989,6 +986,7 @@ declare module "sliftutils/storage/TransactionStorage" {
|
|
|
989
986
|
watchResync(callback: () => void): void;
|
|
990
987
|
private init;
|
|
991
988
|
private getCurrentChunk;
|
|
989
|
+
private updateDiskFileTimestamp;
|
|
992
990
|
private onAddToChunk;
|
|
993
991
|
get(key: string): Promise<Buffer | undefined>;
|
|
994
992
|
set(key: string, value: Buffer): Promise<void>;
|
package/package.json
CHANGED
|
@@ -11,16 +11,17 @@ export class StorageSync<T> implements IStorageSync<T> {
|
|
|
11
11
|
keySeqNum: 0,
|
|
12
12
|
}, undefined, { deep: false });
|
|
13
13
|
|
|
14
|
-
resynced = observable({ seqNum: 0 });
|
|
15
|
-
|
|
16
14
|
constructor(public storage: IStorage<T>) {
|
|
17
15
|
storage.watchResync?.(() => {
|
|
18
|
-
this.
|
|
16
|
+
this.cached.clear();
|
|
17
|
+
this.infoCached.clear();
|
|
18
|
+
this.keys.clear();
|
|
19
|
+
this.loadedKeys = false;
|
|
20
|
+
this.synced.keySeqNum++;
|
|
19
21
|
});
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
public get(key: string): T | undefined {
|
|
23
|
-
this.resynced.seqNum;
|
|
24
25
|
if (!this.cached.has(key)) {
|
|
25
26
|
this.cached.set(key, undefined);
|
|
26
27
|
void this.getPromise(key);
|
|
@@ -48,14 +49,12 @@ export class StorageSync<T> implements IStorageSync<T> {
|
|
|
48
49
|
}
|
|
49
50
|
private loadedKeys = false;
|
|
50
51
|
public getKeys(): string[] {
|
|
51
|
-
this.resynced.seqNum;
|
|
52
52
|
void this.getKeysPromise();
|
|
53
53
|
this.synced.keySeqNum;
|
|
54
54
|
return Array.from(this.keys);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
public getInfo(key: string): { size: number; lastModified: number } | undefined {
|
|
58
|
-
this.resynced.seqNum;
|
|
59
58
|
if (!this.infoCached.has(key)) {
|
|
60
59
|
this.infoCached.set(key, { size: 0, lastModified: 0 });
|
|
61
60
|
void this.storage.getInfo(key).then(info => {
|
|
@@ -22,6 +22,7 @@ export declare class TransactionStorage implements IStorage<Buffer> {
|
|
|
22
22
|
watchResync(callback: () => void): void;
|
|
23
23
|
private init;
|
|
24
24
|
private getCurrentChunk;
|
|
25
|
+
private updateDiskFileTimestamp;
|
|
25
26
|
private onAddToChunk;
|
|
26
27
|
get(key: string): Promise<Buffer | undefined>;
|
|
27
28
|
set(key: string, value: Buffer): Promise<void>;
|
|
@@ -78,7 +78,8 @@ function getNextChunkPath(): string {
|
|
|
78
78
|
|
|
79
79
|
export class TransactionStorage implements IStorage<Buffer> {
|
|
80
80
|
public cache: Map<string, TransactionEntry> = new Map();
|
|
81
|
-
|
|
81
|
+
// Maps file name to our last known write timestamp
|
|
82
|
+
private diskFiles: Map<string, number> = new Map();
|
|
82
83
|
private currentChunk: {
|
|
83
84
|
path: string;
|
|
84
85
|
size: number;
|
|
@@ -123,10 +124,14 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
123
124
|
size: 0,
|
|
124
125
|
timeCreated: Date.now()
|
|
125
126
|
};
|
|
126
|
-
|
|
127
|
+
// Timestamp will be updated after actual write
|
|
128
|
+
this.diskFiles.set(this.currentChunk.path, 0);
|
|
127
129
|
}
|
|
128
130
|
return this.currentChunk.path;
|
|
129
131
|
}
|
|
132
|
+
private updateDiskFileTimestamp(file: string): void {
|
|
133
|
+
this.diskFiles.set(file, Date.now());
|
|
134
|
+
}
|
|
130
135
|
private onAddToChunk(size: number): void {
|
|
131
136
|
if (!this.currentChunk) return;
|
|
132
137
|
this.currentChunk.size += size;
|
|
@@ -222,6 +227,7 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
222
227
|
}
|
|
223
228
|
let content = chunk.buffer;
|
|
224
229
|
await this.rawStorage.append(file, content);
|
|
230
|
+
this.updateDiskFileTimestamp(file);
|
|
225
231
|
this.onAddToChunk(content.length);
|
|
226
232
|
}
|
|
227
233
|
|
|
@@ -255,8 +261,18 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
255
261
|
const anyChanges = async () => {
|
|
256
262
|
let keys = await this.rawStorage.getKeys();
|
|
257
263
|
let diskFiles = keys.filter(key => key.endsWith(CHUNK_EXT));
|
|
258
|
-
|
|
259
|
-
|
|
264
|
+
// Check if any known files have been modified externally (disk timestamp newer than ours)
|
|
265
|
+
for (let file of diskFiles) {
|
|
266
|
+
let ourTimestamp = this.diskFiles.get(file);
|
|
267
|
+
if (ourTimestamp === undefined) {
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
let info = await this.rawStorage.getInfo(file);
|
|
271
|
+
if (info && info.lastModified > ourTimestamp) {
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
260
276
|
};
|
|
261
277
|
if (!await anyChanges()) return;
|
|
262
278
|
|
|
@@ -278,7 +294,12 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
278
294
|
let time = Date.now();
|
|
279
295
|
const keys = await this.rawStorage.getKeys();
|
|
280
296
|
const transactionFiles = keys.filter(key => key.endsWith(CHUNK_EXT));
|
|
281
|
-
|
|
297
|
+
// Populate diskFiles with actual timestamps from disk
|
|
298
|
+
this.diskFiles = new Map();
|
|
299
|
+
for (let file of transactionFiles) {
|
|
300
|
+
let info = await this.rawStorage.getInfo(file);
|
|
301
|
+
this.diskFiles.set(file, info?.lastModified ?? Date.now());
|
|
302
|
+
}
|
|
282
303
|
|
|
283
304
|
let entryList: TransactionEntry[][] = [];
|
|
284
305
|
for (let file of transactionFiles) {
|
|
@@ -568,6 +589,7 @@ export class TransactionStorage implements IStorage<Buffer> {
|
|
|
568
589
|
}
|
|
569
590
|
let buffer = Buffer.concat([headerBuffer, content]);
|
|
570
591
|
await this.rawStorage.set(file, buffer);
|
|
592
|
+
this.updateDiskFileTimestamp(file);
|
|
571
593
|
let verified = await this.rawStorage.get(file);
|
|
572
594
|
if (!verified?.equals(buffer)) {
|
|
573
595
|
console.error(`Failed to verify transaction file ${file} in ${this.debugName}`);
|