@notkannan/cache-with-persistence 1.0.1 → 1.0.2
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/dist/HashMap.d.ts.map +1 -1
- package/dist/HashMap.js +7 -5
- package/dist/HashMap.js.map +1 -1
- package/dist/Store.d.ts +19 -3
- package/dist/Store.d.ts.map +1 -1
- package/dist/Store.js +63 -28
- package/dist/Store.js.map +1 -1
- package/dist/WAL.d.ts +14 -3
- package/dist/WAL.d.ts.map +1 -1
- package/dist/WAL.js +48 -11
- package/dist/WAL.js.map +1 -1
- package/package.json +1 -1
package/dist/HashMap.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HashMap.d.ts","sourceRoot":"","sources":["../src/HashMap.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"HashMap.d.ts","sourceRoot":"","sources":["../src/HashMap.ts"],"names":[],"mappings":"AAQA,qBAAa,OAAO,CAAC,CAAC;IAElB,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,SAAO;IAQ3B,OAAO,CAAC,IAAI;IASZ,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IA2BhC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAa/B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAuB5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,OAAO,IAAI,MAAM;IAKjB,KAAK,IAAI,IAAI;CAUhB"}
|
package/dist/HashMap.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
// HashMap class - core Key:Value logic
|
|
1
2
|
export class HashMap {
|
|
2
|
-
buckets;
|
|
3
|
+
buckets; // actual array that stores entries of type V
|
|
3
4
|
size; // how many key/value pairs are stored
|
|
4
5
|
capacity; // number of buckets in the HashMap
|
|
5
6
|
constructor(capacity = 8192) {
|
|
@@ -17,8 +18,9 @@ export class HashMap {
|
|
|
17
18
|
}
|
|
18
19
|
// Set function
|
|
19
20
|
set(key, value) {
|
|
20
|
-
const index = this.hash(key); //
|
|
21
|
-
let entry = this.buckets[index] ?? null;
|
|
21
|
+
const index = this.hash(key); // obtain index
|
|
22
|
+
let entry = this.buckets[index] ?? null; // index might be empty
|
|
23
|
+
// iterate the chain if idx not empty
|
|
22
24
|
while (entry !== null) {
|
|
23
25
|
if (entry.key === key) {
|
|
24
26
|
entry.value = value;
|
|
@@ -31,9 +33,9 @@ export class HashMap {
|
|
|
31
33
|
const newEntry = {
|
|
32
34
|
key,
|
|
33
35
|
value,
|
|
34
|
-
next: this.buckets[index] ?? null,
|
|
36
|
+
next: this.buckets[index] ?? null,
|
|
35
37
|
};
|
|
36
|
-
this.buckets[index] = newEntry;
|
|
38
|
+
this.buckets[index] = newEntry;
|
|
37
39
|
this.size++;
|
|
38
40
|
}
|
|
39
41
|
// get function
|
package/dist/HashMap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HashMap.js","sourceRoot":"","sources":["../src/HashMap.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,OAAO;
|
|
1
|
+
{"version":3,"file":"HashMap.js","sourceRoot":"","sources":["../src/HashMap.ts"],"names":[],"mappings":"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"}
|
package/dist/Store.d.ts
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
|
+
export interface StoreOptions {
|
|
2
|
+
dataDir?: string;
|
|
3
|
+
syncOnWrite?: boolean;
|
|
4
|
+
}
|
|
1
5
|
export declare class Store {
|
|
2
6
|
private map;
|
|
3
7
|
private wal;
|
|
4
|
-
|
|
8
|
+
private state;
|
|
9
|
+
private writeChain;
|
|
10
|
+
/** Private — use Store.open() */
|
|
11
|
+
private constructor();
|
|
12
|
+
/** Create store and replay WAL (async startup) */
|
|
13
|
+
static open(options?: StoreOptions): Promise<Store>;
|
|
5
14
|
private recover;
|
|
6
|
-
|
|
15
|
+
private assertOpen;
|
|
16
|
+
private enqueueWrite;
|
|
17
|
+
set(key: string, value: string, ttlSeconds?: number): Promise<void>;
|
|
18
|
+
/** Reads stay sync — memory only */
|
|
7
19
|
get(key: string): string | null;
|
|
8
|
-
del(key: string): boolean
|
|
20
|
+
del(key: string): Promise<boolean>;
|
|
9
21
|
exists(key: string): boolean;
|
|
10
22
|
ttl(key: string): number;
|
|
23
|
+
/** Wait for all pending writes, then fsync */
|
|
24
|
+
flush(): Promise<void>;
|
|
25
|
+
/** Drain writes, fsync, close file handle */
|
|
26
|
+
close(): Promise<void>;
|
|
11
27
|
}
|
|
12
28
|
//# sourceMappingURL=Store.d.ts.map
|
package/dist/Store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"AASA,qBAAa,KAAK;IAChB,OAAO,CAAC,GAAG,
|
|
1
|
+
{"version":3,"file":"Store.d.ts","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAID,qBAAa,KAAK;IAChB,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,GAAG,CAAM;IACjB,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,UAAU,CAAoC;IAEtD,iCAAiC;IACjC,OAAO;IAIP,kDAAkD;WACrC,IAAI,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,KAAK,CAAC;YAQ/C,OAAO;IAerB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,YAAY;IAQd,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBzE,oCAAoC;IACpC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAUzB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWxC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAQxB,8CAA8C;IACxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,6CAA6C;IACvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ7B"}
|
package/dist/Store.js
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
// src/Store.ts
|
|
2
2
|
import { HashMap } from './HashMap.js';
|
|
3
3
|
import { WAL } from './WAL.js';
|
|
4
4
|
export class Store {
|
|
5
|
-
map;
|
|
5
|
+
map = new HashMap();
|
|
6
6
|
wal;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
state = 'open';
|
|
8
|
+
writeChain = Promise.resolve();
|
|
9
|
+
/** Private — use Store.open() */
|
|
10
|
+
constructor(wal) {
|
|
11
|
+
this.wal = wal;
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
/** Create store and replay WAL (async startup) */
|
|
14
|
+
static async open(options = {}) {
|
|
15
|
+
const dataDir = options.dataDir ?? './data';
|
|
16
|
+
const wal = await WAL.open(dataDir, { ...(options.syncOnWrite !== undefined && { syncOnWrite: options.syncOnWrite }) });
|
|
17
|
+
const store = new Store(wal);
|
|
18
|
+
await store.recover();
|
|
19
|
+
return store;
|
|
20
|
+
}
|
|
21
|
+
async recover() {
|
|
22
|
+
const entries = await this.wal.readAll();
|
|
16
23
|
for (const entry of entries) {
|
|
17
24
|
if (entry.op === 'SET') {
|
|
18
25
|
const expiresAt = entry.ttlSeconds
|
|
@@ -27,42 +34,56 @@ export class Store {
|
|
|
27
34
|
}
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
assertOpen() {
|
|
38
|
+
if (this.state !== 'open') {
|
|
39
|
+
throw new Error(`Store is ${this.state}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
enqueueWrite(task) {
|
|
43
|
+
this.assertOpen();
|
|
44
|
+
const next = this.writeChain.then(task);
|
|
45
|
+
// Keep chain alive even if one write fails
|
|
46
|
+
this.writeChain = next.catch(() => { });
|
|
47
|
+
return next;
|
|
48
|
+
}
|
|
49
|
+
async set(key, value, ttlSeconds) {
|
|
50
|
+
const entry = {
|
|
33
51
|
op: 'SET',
|
|
34
52
|
key,
|
|
35
53
|
value,
|
|
36
54
|
timestamp: Date.now(),
|
|
37
|
-
...(ttlSeconds !== undefined && { ttlSeconds })
|
|
55
|
+
...(ttlSeconds !== undefined && { ttlSeconds }),
|
|
56
|
+
};
|
|
57
|
+
await this.enqueueWrite(async () => {
|
|
58
|
+
await this.wal.append(entry); // durable first
|
|
59
|
+
const expiresAt = ttlSeconds
|
|
60
|
+
? Date.now() + ttlSeconds * 1000
|
|
61
|
+
: null;
|
|
62
|
+
this.map.set(key, { value, expiresAt });
|
|
38
63
|
});
|
|
39
|
-
const expiresAt = ttlSeconds
|
|
40
|
-
? Date.now() + ttlSeconds * 1000
|
|
41
|
-
: null;
|
|
42
|
-
this.map.set(key, { value, expiresAt });
|
|
43
64
|
}
|
|
44
|
-
|
|
65
|
+
/** Reads stay sync — memory only */
|
|
45
66
|
get(key) {
|
|
46
67
|
const entry = this.map.get(key);
|
|
47
68
|
if (!entry)
|
|
48
69
|
return null;
|
|
49
|
-
// Lazy expiry — we check on read, not on a background timer
|
|
50
70
|
if (entry.expiresAt !== null && Date.now() > entry.expiresAt) {
|
|
51
|
-
this.map.delete(key);
|
|
71
|
+
this.map.delete(key);
|
|
52
72
|
return null;
|
|
53
73
|
}
|
|
54
74
|
return entry.value;
|
|
55
75
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.
|
|
59
|
-
|
|
76
|
+
async del(key) {
|
|
77
|
+
let deleted = false;
|
|
78
|
+
await this.enqueueWrite(async () => {
|
|
79
|
+
await this.wal.append({ op: 'DEL', key, timestamp: Date.now() });
|
|
80
|
+
deleted = this.map.delete(key);
|
|
81
|
+
});
|
|
82
|
+
return deleted;
|
|
60
83
|
}
|
|
61
|
-
// EXISTS key
|
|
62
84
|
exists(key) {
|
|
63
|
-
return this.get(key) !== null;
|
|
85
|
+
return this.get(key) !== null;
|
|
64
86
|
}
|
|
65
|
-
// TTL key → remaining milliseconds, -1 if no expiry, -2 if not found
|
|
66
87
|
ttl(key) {
|
|
67
88
|
const entry = this.map.get(key);
|
|
68
89
|
if (!entry)
|
|
@@ -72,5 +93,19 @@ export class Store {
|
|
|
72
93
|
const remaining = entry.expiresAt - Date.now();
|
|
73
94
|
return remaining > 0 ? remaining : -2;
|
|
74
95
|
}
|
|
96
|
+
/** Wait for all pending writes, then fsync */
|
|
97
|
+
async flush() {
|
|
98
|
+
await this.writeChain;
|
|
99
|
+
await this.wal.flush();
|
|
100
|
+
}
|
|
101
|
+
/** Drain writes, fsync, close file handle */
|
|
102
|
+
async close() {
|
|
103
|
+
if (this.state === 'closed')
|
|
104
|
+
return;
|
|
105
|
+
this.state = 'closing';
|
|
106
|
+
await this.writeChain; // wait for in-flight set/del
|
|
107
|
+
await this.wal.close();
|
|
108
|
+
this.state = 'closed';
|
|
109
|
+
}
|
|
75
110
|
}
|
|
76
111
|
//# sourceMappingURL=Store.js.map
|
package/dist/Store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Store.js","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"Store.js","sourceRoot":"","sources":["../src/Store.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,GAAG,EAAiB,MAAM,UAAU,CAAC;AAc9C,MAAM,OAAO,KAAK;IACR,GAAG,GAAG,IAAI,OAAO,EAAc,CAAC;IAChC,GAAG,CAAM;IACT,KAAK,GAAe,MAAM,CAAC;IAC3B,UAAU,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEtD,iCAAiC;IACjC,YAAoB,GAAQ;QAC1B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,kDAAkD;IAClD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,UAAwB,EAAE;QAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC;QAC5C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;QACxH,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,OAAO;QACnB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACzC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;gBACvB,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU;oBAChC,CAAC,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,UAAU,GAAG,IAAI;oBAC3C,CAAC,CAAC,IAAI,CAAC;gBACT,IAAI,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;oBAAE,SAAS;gBAC3D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YAC9D,CAAC;iBAAM,IAAI,KAAK,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC9B,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,IAAyB;QAC5C,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,2CAA2C;QAC3C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,UAAmB;QACvD,MAAM,KAAK,GAAa;YACtB,EAAE,EAAE,KAAK;YACT,GAAG;YACH,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,EAAE,UAAU,EAAE,CAAC;SAChD,CAAC;QAEF,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE;YACjC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB;YAE9C,MAAM,SAAS,GAAG,UAAU;gBAC1B,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,GAAG,IAAI;gBAChC,CAAC,CAAC,IAAI,CAAC;YACT,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oCAAoC;IACpC,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YAC7D,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE;YACjC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACjE,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;IAChC,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC,CAAC;QACtB,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI;YAAE,OAAO,CAAC,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC/C,OAAO,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,8CAA8C;IAC9C,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,UAAU,CAAC;QACtB,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,6CAA6C;IAC7C,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO;QAEpC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,MAAM,IAAI,CAAC,UAAU,CAAC,CAAE,6BAA6B;QACrD,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;IACxB,CAAC;CACF"}
|
package/dist/WAL.d.ts
CHANGED
|
@@ -5,10 +5,21 @@ export interface WALEntry {
|
|
|
5
5
|
ttlSeconds?: number;
|
|
6
6
|
timestamp: number;
|
|
7
7
|
}
|
|
8
|
+
export interface WALOptions {
|
|
9
|
+
/** fsync after every append (safest, slowest) */
|
|
10
|
+
syncOnWrite?: boolean;
|
|
11
|
+
}
|
|
8
12
|
export declare class WAL {
|
|
9
13
|
private filePath;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
private handle;
|
|
15
|
+
private syncOnWrite;
|
|
16
|
+
private constructor();
|
|
17
|
+
/** Async factory — replaces sync constructor */
|
|
18
|
+
static open(dataDir: string, options?: WALOptions): Promise<WAL>;
|
|
19
|
+
append(entry: WALEntry): Promise<void>;
|
|
20
|
+
/** Force any OS buffers to disk */
|
|
21
|
+
flush(): Promise<void>;
|
|
22
|
+
readAll(): Promise<WALEntry[]>;
|
|
23
|
+
close(): Promise<void>;
|
|
13
24
|
}
|
|
14
25
|
//# sourceMappingURL=WAL.d.ts.map
|
package/dist/WAL.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WAL.d.ts","sourceRoot":"","sources":["../src/WAL.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WAL.d.ts","sourceRoot":"","sources":["../src/WAL.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,GAAG;IACd,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,WAAW,CAAU;IAE7B,OAAO;IAKP,gDAAgD;WACnC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,GAAG,CAAC;IASpE,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAW5C,mCAAmC;IAC7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAsB9B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAM7B"}
|
package/dist/WAL.js
CHANGED
|
@@ -1,23 +1,53 @@
|
|
|
1
|
-
|
|
1
|
+
// src/WAL.ts
|
|
2
|
+
import { open, mkdir, readFile, stat } from 'fs/promises';
|
|
3
|
+
import { constants } from 'fs';
|
|
2
4
|
import * as path from 'path';
|
|
3
5
|
export class WAL {
|
|
4
6
|
filePath;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
handle = null;
|
|
8
|
+
syncOnWrite;
|
|
9
|
+
constructor(filePath, syncOnWrite) {
|
|
10
|
+
this.filePath = filePath;
|
|
11
|
+
this.syncOnWrite = syncOnWrite;
|
|
8
12
|
}
|
|
9
|
-
|
|
13
|
+
/** Async factory — replaces sync constructor */
|
|
14
|
+
static async open(dataDir, options = {}) {
|
|
15
|
+
await mkdir(dataDir, { recursive: true });
|
|
16
|
+
const filePath = path.join(dataDir, 'store.aof');
|
|
17
|
+
const wal = new WAL(filePath, options.syncOnWrite ?? false);
|
|
18
|
+
wal.handle = await open(filePath, constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY);
|
|
19
|
+
return wal;
|
|
20
|
+
}
|
|
21
|
+
async append(entry) {
|
|
22
|
+
if (!this.handle)
|
|
23
|
+
throw new Error('WAL is closed');
|
|
10
24
|
const line = JSON.stringify(entry) + '\n';
|
|
11
|
-
|
|
25
|
+
await this.handle.write(line, null, 'utf8');
|
|
26
|
+
if (this.syncOnWrite) {
|
|
27
|
+
await this.handle.sync(); // like fsync — data on disk before returning
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Force any OS buffers to disk */
|
|
31
|
+
async flush() {
|
|
32
|
+
if (!this.handle)
|
|
33
|
+
return;
|
|
34
|
+
await this.handle.sync();
|
|
12
35
|
}
|
|
13
|
-
readAll() {
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
36
|
+
async readAll() {
|
|
37
|
+
// readFile works even if handle is open (append-only)
|
|
38
|
+
let raw;
|
|
39
|
+
try {
|
|
40
|
+
raw = await readFile(this.filePath, 'utf8');
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
if (err.code === 'ENOENT')
|
|
44
|
+
return [];
|
|
45
|
+
throw err;
|
|
46
|
+
}
|
|
17
47
|
const entries = [];
|
|
18
48
|
for (const line of raw.split('\n')) {
|
|
19
49
|
if (!line.trim())
|
|
20
|
-
continue;
|
|
50
|
+
continue;
|
|
21
51
|
try {
|
|
22
52
|
entries.push(JSON.parse(line));
|
|
23
53
|
}
|
|
@@ -27,5 +57,12 @@ export class WAL {
|
|
|
27
57
|
}
|
|
28
58
|
return entries;
|
|
29
59
|
}
|
|
60
|
+
async close() {
|
|
61
|
+
if (!this.handle)
|
|
62
|
+
return;
|
|
63
|
+
await this.handle.sync(); // final durability guarantee
|
|
64
|
+
await this.handle.close();
|
|
65
|
+
this.handle = null;
|
|
66
|
+
}
|
|
30
67
|
}
|
|
31
68
|
//# sourceMappingURL=WAL.js.map
|
package/dist/WAL.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WAL.js","sourceRoot":"","sources":["../src/WAL.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"WAL.js","sourceRoot":"","sources":["../src/WAL.ts"],"names":[],"mappings":"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"}
|