-
Notifications
You must be signed in to change notification settings - Fork 36
/
mem-store.ts
96 lines (80 loc) · 2.22 KB
/
mem-store.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import {RWLock} from '@rocicorp/lock';
import type {Read, Store, Value, Write} from './store';
import {deleteSentinel, WriteImplBase} from './write-impl-base';
export class MemStore implements Store {
// protected to allow test sub class to use it.
protected readonly _map: Map<string, Value> = new Map();
private readonly _rwLock = new RWLock();
private _closed = false;
async read(): Promise<Read> {
const release = await this._rwLock.read();
return new ReadImpl(this._map, release);
}
async withRead<R>(fn: (read: Read) => R | Promise<R>): Promise<R> {
const read = await this.read();
try {
return await fn(read);
} finally {
read.release();
}
}
async write(): Promise<Write> {
const release = await this._rwLock.write();
return new WriteImpl(this._map, release);
}
async withWrite<R>(fn: (write: Write) => R | Promise<R>): Promise<R> {
const write = await this.write();
try {
return await fn(write);
} finally {
write.release();
}
}
async close(): Promise<void> {
this._closed = true;
}
get closed(): boolean {
return this._closed;
}
}
class ReadImpl implements Read {
private readonly _map: Map<string, Value>;
private readonly _release: () => void;
private _closed = false;
constructor(map: Map<string, Value>, relase: () => void) {
this._map = map;
this._release = relase;
}
release() {
this._release();
this._closed = true;
}
get closed(): boolean {
return this._closed;
}
async has(key: string): Promise<boolean> {
return this._map.has(key);
}
async get(key: string): Promise<Value | undefined> {
return this._map.get(key);
}
}
class WriteImpl extends WriteImplBase implements Write {
private readonly _map: Map<string, Value>;
constructor(map: Map<string, Value>, release: () => void) {
super(new ReadImpl(map, release));
this._map = map;
}
async commit(): Promise<void> {
// HOT. Do not allocate entry tuple and destructure.
this._pending.forEach((value, key) => {
if (value === deleteSentinel) {
this._map.delete(key);
} else {
this._map.set(key, value);
}
});
this._pending.clear();
this.release();
}
}