mvcc-api 1.2.0 → 1.2.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/README.md
CHANGED
|
@@ -74,9 +74,10 @@ import { AsyncMVCCTransaction } from 'mvcc-api'
|
|
|
74
74
|
const root = new AsyncMVCCTransaction(new FileStrategy())
|
|
75
75
|
const tx = root.createNested()
|
|
76
76
|
|
|
77
|
-
tx.create('new.json', '{}') // Create new key
|
|
78
|
-
tx.write('config.json', '{"v":2}') // Update existing key
|
|
79
|
-
tx.delete('old.json') // Delete key
|
|
77
|
+
await tx.create('new.json', '{}') // Create new key
|
|
78
|
+
await tx.write('config.json', '{"v":2}') // Update existing key
|
|
79
|
+
await tx.delete('old.json') // Delete key
|
|
80
|
+
await tx.exists('config.json') // true
|
|
80
81
|
|
|
81
82
|
const result = await tx.commit()
|
|
82
83
|
// result.created = [{ key: 'new.json', data: '{}' }]
|
|
@@ -177,6 +178,7 @@ const bResult = b.commit()
|
|
|
177
178
|
| `write(key, value)` | Update existing key | `this` |
|
|
178
179
|
| `delete(key)` | Delete key | `this` |
|
|
179
180
|
| `read(key)` | Read value | `T \| null` |
|
|
181
|
+
| `exists(key)` | Check if key exists | `boolean` |
|
|
180
182
|
| `commit()` | Apply changes | `TransactionResult<K, T>` |
|
|
181
183
|
| `rollback()` | Discard changes | `TransactionResult<K, T>` |
|
|
182
184
|
| `createNested()` | Create child transaction | `MVCCTransaction` |
|
|
@@ -201,4 +203,5 @@ type TransactionEntry<K, T> = { key: K, data: T }
|
|
|
201
203
|
Bug reports, feature suggestions, and PRs are always welcome! Please feel free to leave your feedback via GitHub Issues.
|
|
202
204
|
|
|
203
205
|
## License
|
|
206
|
+
|
|
204
207
|
MIT
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -42,6 +42,8 @@ var MVCCTransaction = class {
|
|
|
42
42
|
// create()로 생성된 키 추적
|
|
43
43
|
deletedValues;
|
|
44
44
|
// delete 시 삭제 전 값 저장
|
|
45
|
+
originallyExisted;
|
|
46
|
+
// 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
|
|
45
47
|
// Nested Transaction Properties
|
|
46
48
|
parent;
|
|
47
49
|
localVersion;
|
|
@@ -61,6 +63,7 @@ var MVCCTransaction = class {
|
|
|
61
63
|
this.deleteBuffer = /* @__PURE__ */ new Set();
|
|
62
64
|
this.createdKeys = /* @__PURE__ */ new Set();
|
|
63
65
|
this.deletedValues = /* @__PURE__ */ new Map();
|
|
66
|
+
this.originallyExisted = /* @__PURE__ */ new Set();
|
|
64
67
|
this.committed = false;
|
|
65
68
|
this.parent = parent;
|
|
66
69
|
this.keyVersions = /* @__PURE__ */ new Map();
|
|
@@ -87,6 +90,7 @@ var MVCCTransaction = class {
|
|
|
87
90
|
this.writeBuffer.set(key, value);
|
|
88
91
|
this.createdKeys.add(key);
|
|
89
92
|
this.deleteBuffer.delete(key);
|
|
93
|
+
this.originallyExisted.delete(key);
|
|
90
94
|
this.keyVersions.set(key, this.localVersion);
|
|
91
95
|
}
|
|
92
96
|
_bufferWrite(key, value) {
|
|
@@ -119,6 +123,7 @@ var MVCCTransaction = class {
|
|
|
119
123
|
}
|
|
120
124
|
const deleted = [];
|
|
121
125
|
for (const key of this.deleteBuffer) {
|
|
126
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
122
127
|
const data = this.deletedValues.get(key);
|
|
123
128
|
if (data !== void 0) {
|
|
124
129
|
deleted.push({ key, data });
|
|
@@ -128,6 +133,7 @@ var MVCCTransaction = class {
|
|
|
128
133
|
this.deleteBuffer.clear();
|
|
129
134
|
this.createdKeys.clear();
|
|
130
135
|
this.deletedValues.clear();
|
|
136
|
+
this.originallyExisted.clear();
|
|
131
137
|
this.committed = true;
|
|
132
138
|
if (this.root !== this) {
|
|
133
139
|
this.root.activeTransactions.delete(this);
|
|
@@ -161,8 +167,10 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
161
167
|
delete(key) {
|
|
162
168
|
if (this.committed) throw new Error("Transaction already committed");
|
|
163
169
|
let valueToDelete = null;
|
|
170
|
+
let wasInWriteBuffer = false;
|
|
164
171
|
if (this.writeBuffer.has(key)) {
|
|
165
172
|
valueToDelete = this.writeBuffer.get(key);
|
|
173
|
+
wasInWriteBuffer = true;
|
|
166
174
|
} else if (!this.deleteBuffer.has(key)) {
|
|
167
175
|
valueToDelete = this.read(key);
|
|
168
176
|
}
|
|
@@ -170,6 +178,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
170
178
|
throw new Error(`Key not found: ${key}`);
|
|
171
179
|
}
|
|
172
180
|
this.deletedValues.set(key, valueToDelete);
|
|
181
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
182
|
+
this.originallyExisted.add(key);
|
|
183
|
+
}
|
|
173
184
|
this._bufferDelete(key);
|
|
174
185
|
return this;
|
|
175
186
|
}
|
|
@@ -186,6 +197,12 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
186
197
|
if (this.deleteBuffer.has(key)) return null;
|
|
187
198
|
return this.root._diskRead(key, this.snapshotVersion);
|
|
188
199
|
}
|
|
200
|
+
exists(key) {
|
|
201
|
+
if (this.committed) throw new Error("Transaction already committed");
|
|
202
|
+
if (this.deleteBuffer.has(key)) return false;
|
|
203
|
+
if (this.writeBuffer.has(key)) return true;
|
|
204
|
+
return this.root._diskExists(key, this.snapshotVersion);
|
|
205
|
+
}
|
|
189
206
|
_readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
190
207
|
if (this.writeBuffer.has(key)) {
|
|
191
208
|
const keyModVersion = this.keyVersions.get(key);
|
|
@@ -220,6 +237,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
220
237
|
}
|
|
221
238
|
const deleted = [];
|
|
222
239
|
for (const key of this.deleteBuffer) {
|
|
240
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
223
241
|
const data = this.deletedValues.get(key);
|
|
224
242
|
if (data !== void 0) {
|
|
225
243
|
deleted.push({ key, data });
|
|
@@ -241,6 +259,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
241
259
|
this.deleteBuffer.clear();
|
|
242
260
|
this.createdKeys.clear();
|
|
243
261
|
this.deletedValues.clear();
|
|
262
|
+
this.originallyExisted.clear();
|
|
244
263
|
this.keyVersions.clear();
|
|
245
264
|
this.localVersion = 0;
|
|
246
265
|
}
|
|
@@ -279,6 +298,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
279
298
|
if (deletedValue !== void 0) {
|
|
280
299
|
this.deletedValues.set(key, deletedValue);
|
|
281
300
|
}
|
|
301
|
+
if (child.originallyExisted.has(key)) {
|
|
302
|
+
this.originallyExisted.add(key);
|
|
303
|
+
}
|
|
282
304
|
}
|
|
283
305
|
this.localVersion = newLocalVersion;
|
|
284
306
|
this.root.activeTransactions.delete(child);
|
|
@@ -350,6 +372,24 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
350
372
|
}
|
|
351
373
|
return null;
|
|
352
374
|
}
|
|
375
|
+
_diskExists(key, snapshotVersion) {
|
|
376
|
+
const strategy = this.strategy;
|
|
377
|
+
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
378
|
+
const versions = this.versionIndex.get(key);
|
|
379
|
+
if (!versions) {
|
|
380
|
+
return strategy.exists(key);
|
|
381
|
+
}
|
|
382
|
+
let targetVerObj = null;
|
|
383
|
+
for (const v of versions) {
|
|
384
|
+
if (v.version <= snapshotVersion) {
|
|
385
|
+
targetVerObj = v;
|
|
386
|
+
} else {
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (!targetVerObj) return strategy.exists(key);
|
|
391
|
+
return targetVerObj.exists;
|
|
392
|
+
}
|
|
353
393
|
_diskDelete(key, snapshotVersion) {
|
|
354
394
|
const strategy = this.strategy;
|
|
355
395
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
@@ -679,8 +719,10 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
679
719
|
async delete(key) {
|
|
680
720
|
if (this.committed) throw new Error("Transaction already committed");
|
|
681
721
|
let valueToDelete = null;
|
|
722
|
+
let wasInWriteBuffer = false;
|
|
682
723
|
if (this.writeBuffer.has(key)) {
|
|
683
724
|
valueToDelete = this.writeBuffer.get(key);
|
|
725
|
+
wasInWriteBuffer = true;
|
|
684
726
|
} else if (!this.deleteBuffer.has(key)) {
|
|
685
727
|
valueToDelete = await this.read(key);
|
|
686
728
|
}
|
|
@@ -688,6 +730,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
688
730
|
throw new Error(`Key not found: ${key}`);
|
|
689
731
|
}
|
|
690
732
|
this.deletedValues.set(key, valueToDelete);
|
|
733
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
734
|
+
this.originallyExisted.add(key);
|
|
735
|
+
}
|
|
691
736
|
this._bufferDelete(key);
|
|
692
737
|
return this;
|
|
693
738
|
}
|
|
@@ -704,6 +749,12 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
704
749
|
if (this.deleteBuffer.has(key)) return null;
|
|
705
750
|
return this.root._diskRead(key, this.snapshotVersion);
|
|
706
751
|
}
|
|
752
|
+
async exists(key) {
|
|
753
|
+
if (this.committed) throw new Error("Transaction already committed");
|
|
754
|
+
if (this.deleteBuffer.has(key)) return false;
|
|
755
|
+
if (this.writeBuffer.has(key)) return true;
|
|
756
|
+
return this.root._diskExists(key, this.snapshotVersion);
|
|
757
|
+
}
|
|
707
758
|
async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
708
759
|
if (this.writeBuffer.has(key)) {
|
|
709
760
|
const keyModVersion = this.keyVersions.get(key);
|
|
@@ -739,6 +790,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
739
790
|
}
|
|
740
791
|
const deleted = [];
|
|
741
792
|
for (const key of this.deleteBuffer) {
|
|
793
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
742
794
|
const data = this.deletedValues.get(key);
|
|
743
795
|
if (data !== void 0) {
|
|
744
796
|
deleted.push({ key, data });
|
|
@@ -760,6 +812,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
760
812
|
this.deleteBuffer.clear();
|
|
761
813
|
this.createdKeys.clear();
|
|
762
814
|
this.deletedValues.clear();
|
|
815
|
+
this.originallyExisted.clear();
|
|
763
816
|
this.keyVersions.clear();
|
|
764
817
|
this.localVersion = 0;
|
|
765
818
|
}
|
|
@@ -800,6 +853,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
800
853
|
if (deletedValue !== void 0) {
|
|
801
854
|
this.deletedValues.set(key, deletedValue);
|
|
802
855
|
}
|
|
856
|
+
if (child.originallyExisted.has(key)) {
|
|
857
|
+
this.originallyExisted.add(key);
|
|
858
|
+
}
|
|
803
859
|
}
|
|
804
860
|
this.localVersion = newLocalVersion;
|
|
805
861
|
this.root.activeTransactions.delete(child);
|
|
@@ -872,6 +928,24 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
872
928
|
}
|
|
873
929
|
return null;
|
|
874
930
|
}
|
|
931
|
+
async _diskExists(key, snapshotVersion) {
|
|
932
|
+
const strategy = this.strategy;
|
|
933
|
+
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
934
|
+
const versions = this.versionIndex.get(key);
|
|
935
|
+
if (!versions) {
|
|
936
|
+
return strategy.exists(key);
|
|
937
|
+
}
|
|
938
|
+
let targetVerObj = null;
|
|
939
|
+
for (const v of versions) {
|
|
940
|
+
if (v.version <= snapshotVersion) {
|
|
941
|
+
targetVerObj = v;
|
|
942
|
+
} else {
|
|
943
|
+
break;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (!targetVerObj) return strategy.exists(key);
|
|
947
|
+
return targetVerObj.exists;
|
|
948
|
+
}
|
|
875
949
|
async _diskDelete(key, snapshotVersion) {
|
|
876
950
|
const strategy = this.strategy;
|
|
877
951
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
package/dist/esm/index.mjs
CHANGED
|
@@ -13,6 +13,8 @@ var MVCCTransaction = class {
|
|
|
13
13
|
// create()로 생성된 키 추적
|
|
14
14
|
deletedValues;
|
|
15
15
|
// delete 시 삭제 전 값 저장
|
|
16
|
+
originallyExisted;
|
|
17
|
+
// 트랜잭션 시작 시점에 디스크에 존재했던 키 (deleted 결과 필터링용)
|
|
16
18
|
// Nested Transaction Properties
|
|
17
19
|
parent;
|
|
18
20
|
localVersion;
|
|
@@ -32,6 +34,7 @@ var MVCCTransaction = class {
|
|
|
32
34
|
this.deleteBuffer = /* @__PURE__ */ new Set();
|
|
33
35
|
this.createdKeys = /* @__PURE__ */ new Set();
|
|
34
36
|
this.deletedValues = /* @__PURE__ */ new Map();
|
|
37
|
+
this.originallyExisted = /* @__PURE__ */ new Set();
|
|
35
38
|
this.committed = false;
|
|
36
39
|
this.parent = parent;
|
|
37
40
|
this.keyVersions = /* @__PURE__ */ new Map();
|
|
@@ -58,6 +61,7 @@ var MVCCTransaction = class {
|
|
|
58
61
|
this.writeBuffer.set(key, value);
|
|
59
62
|
this.createdKeys.add(key);
|
|
60
63
|
this.deleteBuffer.delete(key);
|
|
64
|
+
this.originallyExisted.delete(key);
|
|
61
65
|
this.keyVersions.set(key, this.localVersion);
|
|
62
66
|
}
|
|
63
67
|
_bufferWrite(key, value) {
|
|
@@ -90,6 +94,7 @@ var MVCCTransaction = class {
|
|
|
90
94
|
}
|
|
91
95
|
const deleted = [];
|
|
92
96
|
for (const key of this.deleteBuffer) {
|
|
97
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
93
98
|
const data = this.deletedValues.get(key);
|
|
94
99
|
if (data !== void 0) {
|
|
95
100
|
deleted.push({ key, data });
|
|
@@ -99,6 +104,7 @@ var MVCCTransaction = class {
|
|
|
99
104
|
this.deleteBuffer.clear();
|
|
100
105
|
this.createdKeys.clear();
|
|
101
106
|
this.deletedValues.clear();
|
|
107
|
+
this.originallyExisted.clear();
|
|
102
108
|
this.committed = true;
|
|
103
109
|
if (this.root !== this) {
|
|
104
110
|
this.root.activeTransactions.delete(this);
|
|
@@ -132,8 +138,10 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
132
138
|
delete(key) {
|
|
133
139
|
if (this.committed) throw new Error("Transaction already committed");
|
|
134
140
|
let valueToDelete = null;
|
|
141
|
+
let wasInWriteBuffer = false;
|
|
135
142
|
if (this.writeBuffer.has(key)) {
|
|
136
143
|
valueToDelete = this.writeBuffer.get(key);
|
|
144
|
+
wasInWriteBuffer = true;
|
|
137
145
|
} else if (!this.deleteBuffer.has(key)) {
|
|
138
146
|
valueToDelete = this.read(key);
|
|
139
147
|
}
|
|
@@ -141,6 +149,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
141
149
|
throw new Error(`Key not found: ${key}`);
|
|
142
150
|
}
|
|
143
151
|
this.deletedValues.set(key, valueToDelete);
|
|
152
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
153
|
+
this.originallyExisted.add(key);
|
|
154
|
+
}
|
|
144
155
|
this._bufferDelete(key);
|
|
145
156
|
return this;
|
|
146
157
|
}
|
|
@@ -157,6 +168,12 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
157
168
|
if (this.deleteBuffer.has(key)) return null;
|
|
158
169
|
return this.root._diskRead(key, this.snapshotVersion);
|
|
159
170
|
}
|
|
171
|
+
exists(key) {
|
|
172
|
+
if (this.committed) throw new Error("Transaction already committed");
|
|
173
|
+
if (this.deleteBuffer.has(key)) return false;
|
|
174
|
+
if (this.writeBuffer.has(key)) return true;
|
|
175
|
+
return this.root._diskExists(key, this.snapshotVersion);
|
|
176
|
+
}
|
|
160
177
|
_readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
161
178
|
if (this.writeBuffer.has(key)) {
|
|
162
179
|
const keyModVersion = this.keyVersions.get(key);
|
|
@@ -191,6 +208,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
191
208
|
}
|
|
192
209
|
const deleted = [];
|
|
193
210
|
for (const key of this.deleteBuffer) {
|
|
211
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
194
212
|
const data = this.deletedValues.get(key);
|
|
195
213
|
if (data !== void 0) {
|
|
196
214
|
deleted.push({ key, data });
|
|
@@ -212,6 +230,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
212
230
|
this.deleteBuffer.clear();
|
|
213
231
|
this.createdKeys.clear();
|
|
214
232
|
this.deletedValues.clear();
|
|
233
|
+
this.originallyExisted.clear();
|
|
215
234
|
this.keyVersions.clear();
|
|
216
235
|
this.localVersion = 0;
|
|
217
236
|
}
|
|
@@ -250,6 +269,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
250
269
|
if (deletedValue !== void 0) {
|
|
251
270
|
this.deletedValues.set(key, deletedValue);
|
|
252
271
|
}
|
|
272
|
+
if (child.originallyExisted.has(key)) {
|
|
273
|
+
this.originallyExisted.add(key);
|
|
274
|
+
}
|
|
253
275
|
}
|
|
254
276
|
this.localVersion = newLocalVersion;
|
|
255
277
|
this.root.activeTransactions.delete(child);
|
|
@@ -321,6 +343,24 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
321
343
|
}
|
|
322
344
|
return null;
|
|
323
345
|
}
|
|
346
|
+
_diskExists(key, snapshotVersion) {
|
|
347
|
+
const strategy = this.strategy;
|
|
348
|
+
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
349
|
+
const versions = this.versionIndex.get(key);
|
|
350
|
+
if (!versions) {
|
|
351
|
+
return strategy.exists(key);
|
|
352
|
+
}
|
|
353
|
+
let targetVerObj = null;
|
|
354
|
+
for (const v of versions) {
|
|
355
|
+
if (v.version <= snapshotVersion) {
|
|
356
|
+
targetVerObj = v;
|
|
357
|
+
} else {
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
if (!targetVerObj) return strategy.exists(key);
|
|
362
|
+
return targetVerObj.exists;
|
|
363
|
+
}
|
|
324
364
|
_diskDelete(key, snapshotVersion) {
|
|
325
365
|
const strategy = this.strategy;
|
|
326
366
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
@@ -650,8 +690,10 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
650
690
|
async delete(key) {
|
|
651
691
|
if (this.committed) throw new Error("Transaction already committed");
|
|
652
692
|
let valueToDelete = null;
|
|
693
|
+
let wasInWriteBuffer = false;
|
|
653
694
|
if (this.writeBuffer.has(key)) {
|
|
654
695
|
valueToDelete = this.writeBuffer.get(key);
|
|
696
|
+
wasInWriteBuffer = true;
|
|
655
697
|
} else if (!this.deleteBuffer.has(key)) {
|
|
656
698
|
valueToDelete = await this.read(key);
|
|
657
699
|
}
|
|
@@ -659,6 +701,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
659
701
|
throw new Error(`Key not found: ${key}`);
|
|
660
702
|
}
|
|
661
703
|
this.deletedValues.set(key, valueToDelete);
|
|
704
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
705
|
+
this.originallyExisted.add(key);
|
|
706
|
+
}
|
|
662
707
|
this._bufferDelete(key);
|
|
663
708
|
return this;
|
|
664
709
|
}
|
|
@@ -675,6 +720,12 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
675
720
|
if (this.deleteBuffer.has(key)) return null;
|
|
676
721
|
return this.root._diskRead(key, this.snapshotVersion);
|
|
677
722
|
}
|
|
723
|
+
async exists(key) {
|
|
724
|
+
if (this.committed) throw new Error("Transaction already committed");
|
|
725
|
+
if (this.deleteBuffer.has(key)) return false;
|
|
726
|
+
if (this.writeBuffer.has(key)) return true;
|
|
727
|
+
return this.root._diskExists(key, this.snapshotVersion);
|
|
728
|
+
}
|
|
678
729
|
async _readSnapshot(key, snapshotVersion, snapshotLocalVersion) {
|
|
679
730
|
if (this.writeBuffer.has(key)) {
|
|
680
731
|
const keyModVersion = this.keyVersions.get(key);
|
|
@@ -710,6 +761,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
710
761
|
}
|
|
711
762
|
const deleted = [];
|
|
712
763
|
for (const key of this.deleteBuffer) {
|
|
764
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
713
765
|
const data = this.deletedValues.get(key);
|
|
714
766
|
if (data !== void 0) {
|
|
715
767
|
deleted.push({ key, data });
|
|
@@ -731,6 +783,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
731
783
|
this.deleteBuffer.clear();
|
|
732
784
|
this.createdKeys.clear();
|
|
733
785
|
this.deletedValues.clear();
|
|
786
|
+
this.originallyExisted.clear();
|
|
734
787
|
this.keyVersions.clear();
|
|
735
788
|
this.localVersion = 0;
|
|
736
789
|
}
|
|
@@ -771,6 +824,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
771
824
|
if (deletedValue !== void 0) {
|
|
772
825
|
this.deletedValues.set(key, deletedValue);
|
|
773
826
|
}
|
|
827
|
+
if (child.originallyExisted.has(key)) {
|
|
828
|
+
this.originallyExisted.add(key);
|
|
829
|
+
}
|
|
774
830
|
}
|
|
775
831
|
this.localVersion = newLocalVersion;
|
|
776
832
|
this.root.activeTransactions.delete(child);
|
|
@@ -843,6 +899,24 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
843
899
|
}
|
|
844
900
|
return null;
|
|
845
901
|
}
|
|
902
|
+
async _diskExists(key, snapshotVersion) {
|
|
903
|
+
const strategy = this.strategy;
|
|
904
|
+
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
905
|
+
const versions = this.versionIndex.get(key);
|
|
906
|
+
if (!versions) {
|
|
907
|
+
return strategy.exists(key);
|
|
908
|
+
}
|
|
909
|
+
let targetVerObj = null;
|
|
910
|
+
for (const v of versions) {
|
|
911
|
+
if (v.version <= snapshotVersion) {
|
|
912
|
+
targetVerObj = v;
|
|
913
|
+
} else {
|
|
914
|
+
break;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
if (!targetVerObj) return strategy.exists(key);
|
|
918
|
+
return targetVerObj.exists;
|
|
919
|
+
}
|
|
846
920
|
async _diskDelete(key, snapshotVersion) {
|
|
847
921
|
const strategy = this.strategy;
|
|
848
922
|
if (!strategy) throw new Error("Root Transaction missing strategy");
|
|
@@ -9,11 +9,13 @@ export declare class AsyncMVCCTransaction<S extends AsyncMVCCStrategy<K, T>, K,
|
|
|
9
9
|
delete(key: K): Promise<this>;
|
|
10
10
|
createNested(): this;
|
|
11
11
|
read(key: K): Promise<T | null>;
|
|
12
|
+
exists(key: K): Promise<boolean>;
|
|
12
13
|
_readSnapshot(key: K, snapshotVersion: number, snapshotLocalVersion?: number): Promise<T | null>;
|
|
13
14
|
commit(): Promise<TransactionResult<K, T>>;
|
|
14
15
|
_merge(child: MVCCTransaction<S, K, T>): Promise<string | null>;
|
|
15
16
|
_diskWrite(key: K, value: T, version: number): Promise<void>;
|
|
16
17
|
_diskRead(key: K, snapshotVersion: number): Promise<T | null>;
|
|
18
|
+
_diskExists(key: K, snapshotVersion: number): Promise<boolean>;
|
|
17
19
|
_diskDelete(key: K, snapshotVersion: number): Promise<void>;
|
|
18
20
|
_cleanupDeletedCache(): void;
|
|
19
21
|
}
|
|
@@ -16,6 +16,7 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
16
16
|
readonly deleteBuffer: Set<K>;
|
|
17
17
|
readonly createdKeys: Set<K>;
|
|
18
18
|
readonly deletedValues: Map<K, T>;
|
|
19
|
+
readonly originallyExisted: Set<K>;
|
|
19
20
|
readonly parent?: MVCCTransaction<S, K, T>;
|
|
20
21
|
localVersion: number;
|
|
21
22
|
readonly keyVersions: Map<K, number>;
|
|
@@ -71,6 +72,12 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
71
72
|
* @returns The value, or null if not found.
|
|
72
73
|
*/
|
|
73
74
|
abstract read(key: K): Deferred<T | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a key exists in the transaction's snapshot.
|
|
77
|
+
* @param key The key to check.
|
|
78
|
+
* @returns True if the key exists, false otherwise.
|
|
79
|
+
*/
|
|
80
|
+
abstract exists(key: K): Deferred<boolean>;
|
|
74
81
|
/**
|
|
75
82
|
* Commits the transaction.
|
|
76
83
|
* If root, persists to storage.
|
|
@@ -7,11 +7,13 @@ export declare class SyncMVCCTransaction<S extends SyncMVCCStrategy<K, T>, K, T>
|
|
|
7
7
|
delete(key: K): this;
|
|
8
8
|
createNested(): this;
|
|
9
9
|
read(key: K): T | null;
|
|
10
|
+
exists(key: K): boolean;
|
|
10
11
|
_readSnapshot(key: K, snapshotVersion: number, snapshotLocalVersion?: number): T | null;
|
|
11
12
|
commit(): TransactionResult<K, T>;
|
|
12
13
|
_merge(child: MVCCTransaction<S, K, T>): string | null;
|
|
13
14
|
_diskWrite(key: K, value: T, version: number): void;
|
|
14
15
|
_diskRead(key: K, snapshotVersion: number): T | null;
|
|
16
|
+
_diskExists(key: K, snapshotVersion: number): boolean;
|
|
15
17
|
_diskDelete(key: K, snapshotVersion: number): void;
|
|
16
18
|
_cleanupDeletedCache(): void;
|
|
17
19
|
}
|