mvcc-api 1.2.2 → 1.2.4
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 +17 -0
- package/dist/cjs/index.cjs +244 -94
- package/dist/esm/index.mjs +244 -94
- package/dist/types/core/async/Transaction.d.ts +3 -3
- package/dist/types/core/base/Transaction.d.ts +15 -3
- package/dist/types/core/sync/Transaction.d.ts +3 -3
- package/dist/types/types/index.d.ts +19 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,8 +38,23 @@ It easily and powerfully solves complex concurrency problems that are difficult
|
|
|
38
38
|
|
|
39
39
|
## Installation
|
|
40
40
|
|
|
41
|
+
### Node.js
|
|
42
|
+
|
|
41
43
|
```bash
|
|
42
44
|
npm install mvcc-api
|
|
45
|
+
# or
|
|
46
|
+
npx jsr add @izure/mvcc-api
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Browser
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
import {
|
|
53
|
+
SyncMVCCStrategy,
|
|
54
|
+
SyncMVCCTransaction,
|
|
55
|
+
AsyncMVCCStrategy,
|
|
56
|
+
AsyncMVCCTransaction
|
|
57
|
+
} from 'https://cdn.jsdelivr.net/npm/mvcc-api@7/+esm'
|
|
43
58
|
```
|
|
44
59
|
|
|
45
60
|
## Usage
|
|
@@ -187,10 +202,12 @@ const bResult = b.commit()
|
|
|
187
202
|
|
|
188
203
|
```typescript
|
|
189
204
|
type TransactionEntry<K, T> = { key: K, data: T }
|
|
205
|
+
type TransactionConflict<K, T> = { key: K, parent: T, child: T }
|
|
190
206
|
|
|
191
207
|
{
|
|
192
208
|
success: boolean // Success status
|
|
193
209
|
error?: string // Error message on failure (e.g. conflict)
|
|
210
|
+
conflict?: TransactionConflict<K, T> // Conflict information on failure
|
|
194
211
|
created: TransactionEntry[] // Keys and values created via create()
|
|
195
212
|
updated: TransactionEntry[] // Keys and values updated via write()
|
|
196
213
|
deleted: TransactionEntry[] // Keys deleted via delete() and their previous values
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -84,6 +84,19 @@ var MVCCTransaction = class {
|
|
|
84
84
|
isRoot() {
|
|
85
85
|
return !this.parent;
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Checks if any ancestor transaction has already been committed.
|
|
89
|
+
* A nested transaction cannot commit if its parent or any higher ancestor is committed.
|
|
90
|
+
* @returns True if at least one ancestor is committed, false otherwise.
|
|
91
|
+
*/
|
|
92
|
+
hasCommittedAncestor() {
|
|
93
|
+
let current = this.parent;
|
|
94
|
+
while (current) {
|
|
95
|
+
if (current.committed) return true;
|
|
96
|
+
current = current.parent;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
87
100
|
// --- Internal buffer manipulation helpers ---
|
|
88
101
|
_bufferCreate(key, value) {
|
|
89
102
|
this.localVersion++;
|
|
@@ -106,12 +119,7 @@ var MVCCTransaction = class {
|
|
|
106
119
|
this.createdKeys.delete(key);
|
|
107
120
|
this.keyVersions.set(key, this.localVersion);
|
|
108
121
|
}
|
|
109
|
-
|
|
110
|
-
* Rolls back the transaction.
|
|
111
|
-
* Clears all buffers and marks the transaction as finished.
|
|
112
|
-
* @returns The result object with success, created, updated, and deleted keys.
|
|
113
|
-
*/
|
|
114
|
-
rollback() {
|
|
122
|
+
_getResultEntries() {
|
|
115
123
|
const created = [];
|
|
116
124
|
const updated = [];
|
|
117
125
|
for (const [key, data] of this.writeBuffer.entries()) {
|
|
@@ -129,6 +137,15 @@ var MVCCTransaction = class {
|
|
|
129
137
|
deleted.push({ key, data });
|
|
130
138
|
}
|
|
131
139
|
}
|
|
140
|
+
return { created, updated, deleted };
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Rolls back the transaction.
|
|
144
|
+
* Clears all buffers and marks the transaction as finished.
|
|
145
|
+
* @returns The result object with success, created, updated, and deleted keys.
|
|
146
|
+
*/
|
|
147
|
+
rollback() {
|
|
148
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
132
149
|
this.writeBuffer.clear();
|
|
133
150
|
this.deleteBuffer.clear();
|
|
134
151
|
this.createdKeys.clear();
|
|
@@ -222,38 +239,57 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
222
239
|
return this._diskRead(key, snapshotVersion);
|
|
223
240
|
}
|
|
224
241
|
}
|
|
225
|
-
commit() {
|
|
242
|
+
commit(label) {
|
|
243
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
226
244
|
if (this.committed) {
|
|
227
|
-
return {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
245
|
+
return {
|
|
246
|
+
label,
|
|
247
|
+
success: false,
|
|
248
|
+
error: "Transaction already committed",
|
|
249
|
+
conflict: void 0,
|
|
250
|
+
created,
|
|
251
|
+
updated,
|
|
252
|
+
deleted
|
|
253
|
+
};
|
|
237
254
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
255
|
+
if (this.hasCommittedAncestor()) {
|
|
256
|
+
return {
|
|
257
|
+
label,
|
|
258
|
+
success: false,
|
|
259
|
+
error: "Ancestor transaction already committed",
|
|
260
|
+
conflict: void 0,
|
|
261
|
+
created,
|
|
262
|
+
updated,
|
|
263
|
+
deleted
|
|
264
|
+
};
|
|
245
265
|
}
|
|
246
266
|
if (this.parent) {
|
|
247
|
-
const
|
|
248
|
-
if (
|
|
249
|
-
return {
|
|
267
|
+
const failure = this.parent._merge(this);
|
|
268
|
+
if (failure) {
|
|
269
|
+
return {
|
|
270
|
+
label,
|
|
271
|
+
success: false,
|
|
272
|
+
error: failure.error,
|
|
273
|
+
conflict: failure.conflict,
|
|
274
|
+
created,
|
|
275
|
+
updated,
|
|
276
|
+
deleted
|
|
277
|
+
};
|
|
250
278
|
}
|
|
251
279
|
this.committed = true;
|
|
252
280
|
} else {
|
|
253
281
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
254
|
-
const
|
|
255
|
-
if (
|
|
256
|
-
return {
|
|
282
|
+
const failure = this._merge(this);
|
|
283
|
+
if (failure) {
|
|
284
|
+
return {
|
|
285
|
+
label,
|
|
286
|
+
success: false,
|
|
287
|
+
error: failure.error,
|
|
288
|
+
conflict: failure.conflict,
|
|
289
|
+
created: [],
|
|
290
|
+
updated: [],
|
|
291
|
+
deleted: []
|
|
292
|
+
};
|
|
257
293
|
}
|
|
258
294
|
this.writeBuffer.clear();
|
|
259
295
|
this.deleteBuffer.clear();
|
|
@@ -264,20 +300,40 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
264
300
|
this.localVersion = 0;
|
|
265
301
|
}
|
|
266
302
|
}
|
|
267
|
-
return {
|
|
303
|
+
return {
|
|
304
|
+
label,
|
|
305
|
+
success: true,
|
|
306
|
+
created,
|
|
307
|
+
updated,
|
|
308
|
+
deleted
|
|
309
|
+
};
|
|
268
310
|
}
|
|
269
311
|
_merge(child) {
|
|
270
312
|
if (this.parent) {
|
|
271
313
|
for (const key of child.writeBuffer.keys()) {
|
|
272
314
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
273
315
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
274
|
-
return
|
|
316
|
+
return {
|
|
317
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
318
|
+
conflict: {
|
|
319
|
+
key,
|
|
320
|
+
parent: this.read(key),
|
|
321
|
+
child: child.read(key)
|
|
322
|
+
}
|
|
323
|
+
};
|
|
275
324
|
}
|
|
276
325
|
}
|
|
277
326
|
for (const key of child.deleteBuffer) {
|
|
278
327
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
279
328
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
280
|
-
return
|
|
329
|
+
return {
|
|
330
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
331
|
+
conflict: {
|
|
332
|
+
key,
|
|
333
|
+
parent: this.read(key),
|
|
334
|
+
child: child.read(key)
|
|
335
|
+
}
|
|
336
|
+
};
|
|
281
337
|
}
|
|
282
338
|
}
|
|
283
339
|
const newLocalVersion = this.localVersion + 1;
|
|
@@ -305,18 +361,45 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
305
361
|
this.localVersion = newLocalVersion;
|
|
306
362
|
this.root.activeTransactions.delete(child);
|
|
307
363
|
} else {
|
|
308
|
-
this.root.activeTransactions.delete(child);
|
|
309
364
|
const newVersion = this.version + 1;
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
365
|
+
if (child !== this) {
|
|
366
|
+
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
367
|
+
for (const key of modifiedKeys) {
|
|
368
|
+
const versions = this.versionIndex.get(key);
|
|
369
|
+
if (versions && versions.length > 0) {
|
|
370
|
+
const lastVer = versions[versions.length - 1].version;
|
|
371
|
+
if (lastVer > child.snapshotVersion) {
|
|
372
|
+
return {
|
|
373
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
374
|
+
conflict: {
|
|
375
|
+
key,
|
|
376
|
+
parent: this.read(key),
|
|
377
|
+
child: child.read(key)
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
}
|
|
317
381
|
}
|
|
318
382
|
}
|
|
319
383
|
}
|
|
384
|
+
for (const [key, value] of child.writeBuffer) {
|
|
385
|
+
this.writeBuffer.set(key, value);
|
|
386
|
+
this.deleteBuffer.delete(key);
|
|
387
|
+
if (child.createdKeys.has(key)) {
|
|
388
|
+
this.createdKeys.add(key);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (const key of child.deleteBuffer) {
|
|
392
|
+
this.deleteBuffer.add(key);
|
|
393
|
+
this.writeBuffer.delete(key);
|
|
394
|
+
this.createdKeys.delete(key);
|
|
395
|
+
const deletedValue = child.deletedValues.get(key);
|
|
396
|
+
if (deletedValue !== void 0) {
|
|
397
|
+
this.deletedValues.set(key, deletedValue);
|
|
398
|
+
}
|
|
399
|
+
if (child.originallyExisted.has(key)) {
|
|
400
|
+
this.originallyExisted.add(key);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
320
403
|
for (const [key, value] of child.writeBuffer) {
|
|
321
404
|
this._diskWrite(key, value, newVersion);
|
|
322
405
|
}
|
|
@@ -324,6 +407,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
324
407
|
this._diskDelete(key, newVersion);
|
|
325
408
|
}
|
|
326
409
|
this.version = newVersion;
|
|
410
|
+
this.root.activeTransactions.delete(child);
|
|
327
411
|
this._cleanupDeletedCache();
|
|
328
412
|
}
|
|
329
413
|
return null;
|
|
@@ -774,51 +858,74 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
774
858
|
return this._diskRead(key, snapshotVersion);
|
|
775
859
|
}
|
|
776
860
|
}
|
|
777
|
-
async commit() {
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
861
|
+
async commit(label) {
|
|
862
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
863
|
+
if (this.committed) {
|
|
864
|
+
return {
|
|
865
|
+
label,
|
|
866
|
+
success: false,
|
|
867
|
+
error: "Transaction already committed",
|
|
868
|
+
conflict: void 0,
|
|
869
|
+
created,
|
|
870
|
+
updated,
|
|
871
|
+
deleted
|
|
872
|
+
};
|
|
873
|
+
}
|
|
874
|
+
if (this.hasCommittedAncestor()) {
|
|
875
|
+
return {
|
|
876
|
+
label,
|
|
877
|
+
success: false,
|
|
878
|
+
error: "Ancestor transaction already committed",
|
|
879
|
+
conflict: void 0,
|
|
880
|
+
created,
|
|
881
|
+
updated,
|
|
882
|
+
deleted
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
if (this.parent) {
|
|
886
|
+
const failure = await this.parent._merge(this);
|
|
887
|
+
if (failure) {
|
|
888
|
+
return {
|
|
889
|
+
label,
|
|
890
|
+
success: false,
|
|
891
|
+
error: failure.error,
|
|
892
|
+
conflict: failure.conflict,
|
|
893
|
+
created,
|
|
894
|
+
updated,
|
|
895
|
+
deleted
|
|
896
|
+
};
|
|
798
897
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
this.createdKeys.clear();
|
|
814
|
-
this.deletedValues.clear();
|
|
815
|
-
this.originallyExisted.clear();
|
|
816
|
-
this.keyVersions.clear();
|
|
817
|
-
this.localVersion = 0;
|
|
898
|
+
this.committed = true;
|
|
899
|
+
} else {
|
|
900
|
+
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
901
|
+
const failure = await this._merge(this);
|
|
902
|
+
if (failure) {
|
|
903
|
+
return {
|
|
904
|
+
label,
|
|
905
|
+
success: false,
|
|
906
|
+
error: failure.error,
|
|
907
|
+
conflict: failure.conflict,
|
|
908
|
+
created: [],
|
|
909
|
+
updated: [],
|
|
910
|
+
deleted: []
|
|
911
|
+
};
|
|
818
912
|
}
|
|
913
|
+
this.writeBuffer.clear();
|
|
914
|
+
this.deleteBuffer.clear();
|
|
915
|
+
this.createdKeys.clear();
|
|
916
|
+
this.deletedValues.clear();
|
|
917
|
+
this.originallyExisted.clear();
|
|
918
|
+
this.keyVersions.clear();
|
|
919
|
+
this.localVersion = 0;
|
|
819
920
|
}
|
|
820
|
-
|
|
821
|
-
|
|
921
|
+
}
|
|
922
|
+
return {
|
|
923
|
+
label,
|
|
924
|
+
success: true,
|
|
925
|
+
created,
|
|
926
|
+
updated,
|
|
927
|
+
deleted
|
|
928
|
+
};
|
|
822
929
|
}
|
|
823
930
|
async _merge(child) {
|
|
824
931
|
return this.writeLock(async () => {
|
|
@@ -826,13 +933,27 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
826
933
|
for (const key of child.writeBuffer.keys()) {
|
|
827
934
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
828
935
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
829
|
-
return
|
|
936
|
+
return {
|
|
937
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
938
|
+
conflict: {
|
|
939
|
+
key,
|
|
940
|
+
parent: await this.read(key),
|
|
941
|
+
child: await child.read(key)
|
|
942
|
+
}
|
|
943
|
+
};
|
|
830
944
|
}
|
|
831
945
|
}
|
|
832
946
|
for (const key of child.deleteBuffer) {
|
|
833
947
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
834
948
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
835
|
-
return
|
|
949
|
+
return {
|
|
950
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
951
|
+
conflict: {
|
|
952
|
+
key,
|
|
953
|
+
parent: await this.read(key),
|
|
954
|
+
child: await child.read(key)
|
|
955
|
+
}
|
|
956
|
+
};
|
|
836
957
|
}
|
|
837
958
|
}
|
|
838
959
|
const newLocalVersion = this.localVersion + 1;
|
|
@@ -859,19 +980,47 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
859
980
|
}
|
|
860
981
|
this.localVersion = newLocalVersion;
|
|
861
982
|
this.root.activeTransactions.delete(child);
|
|
983
|
+
return null;
|
|
862
984
|
} else {
|
|
863
|
-
this.root.activeTransactions.delete(child);
|
|
864
985
|
const newVersion = this.version + 1;
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
986
|
+
if (child !== this) {
|
|
987
|
+
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
988
|
+
for (const key of modifiedKeys) {
|
|
989
|
+
const versions = this.versionIndex.get(key);
|
|
990
|
+
if (versions && versions.length > 0) {
|
|
991
|
+
const lastVer = versions[versions.length - 1].version;
|
|
992
|
+
if (lastVer > child.snapshotVersion) {
|
|
993
|
+
return {
|
|
994
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
995
|
+
conflict: {
|
|
996
|
+
key,
|
|
997
|
+
parent: await this.read(key),
|
|
998
|
+
child: await child.read(key)
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
872
1002
|
}
|
|
873
1003
|
}
|
|
874
1004
|
}
|
|
1005
|
+
for (const [key, value] of child.writeBuffer) {
|
|
1006
|
+
this.writeBuffer.set(key, value);
|
|
1007
|
+
this.deleteBuffer.delete(key);
|
|
1008
|
+
if (child.createdKeys.has(key)) {
|
|
1009
|
+
this.createdKeys.add(key);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
for (const key of child.deleteBuffer) {
|
|
1013
|
+
this.deleteBuffer.add(key);
|
|
1014
|
+
this.writeBuffer.delete(key);
|
|
1015
|
+
this.createdKeys.delete(key);
|
|
1016
|
+
const deletedValue = child.deletedValues.get(key);
|
|
1017
|
+
if (deletedValue !== void 0) {
|
|
1018
|
+
this.deletedValues.set(key, deletedValue);
|
|
1019
|
+
}
|
|
1020
|
+
if (child.originallyExisted.has(key)) {
|
|
1021
|
+
this.originallyExisted.add(key);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
875
1024
|
for (const [key, value] of child.writeBuffer) {
|
|
876
1025
|
await this._diskWrite(key, value, newVersion);
|
|
877
1026
|
}
|
|
@@ -879,9 +1028,10 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
879
1028
|
await this._diskDelete(key, newVersion);
|
|
880
1029
|
}
|
|
881
1030
|
this.version = newVersion;
|
|
1031
|
+
this.root.activeTransactions.delete(child);
|
|
882
1032
|
this._cleanupDeletedCache();
|
|
1033
|
+
return null;
|
|
883
1034
|
}
|
|
884
|
-
return null;
|
|
885
1035
|
});
|
|
886
1036
|
}
|
|
887
1037
|
// --- Internal IO Helpers (Root Only) ---
|
package/dist/esm/index.mjs
CHANGED
|
@@ -55,6 +55,19 @@ var MVCCTransaction = class {
|
|
|
55
55
|
isRoot() {
|
|
56
56
|
return !this.parent;
|
|
57
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Checks if any ancestor transaction has already been committed.
|
|
60
|
+
* A nested transaction cannot commit if its parent or any higher ancestor is committed.
|
|
61
|
+
* @returns True if at least one ancestor is committed, false otherwise.
|
|
62
|
+
*/
|
|
63
|
+
hasCommittedAncestor() {
|
|
64
|
+
let current = this.parent;
|
|
65
|
+
while (current) {
|
|
66
|
+
if (current.committed) return true;
|
|
67
|
+
current = current.parent;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
58
71
|
// --- Internal buffer manipulation helpers ---
|
|
59
72
|
_bufferCreate(key, value) {
|
|
60
73
|
this.localVersion++;
|
|
@@ -77,12 +90,7 @@ var MVCCTransaction = class {
|
|
|
77
90
|
this.createdKeys.delete(key);
|
|
78
91
|
this.keyVersions.set(key, this.localVersion);
|
|
79
92
|
}
|
|
80
|
-
|
|
81
|
-
* Rolls back the transaction.
|
|
82
|
-
* Clears all buffers and marks the transaction as finished.
|
|
83
|
-
* @returns The result object with success, created, updated, and deleted keys.
|
|
84
|
-
*/
|
|
85
|
-
rollback() {
|
|
93
|
+
_getResultEntries() {
|
|
86
94
|
const created = [];
|
|
87
95
|
const updated = [];
|
|
88
96
|
for (const [key, data] of this.writeBuffer.entries()) {
|
|
@@ -100,6 +108,15 @@ var MVCCTransaction = class {
|
|
|
100
108
|
deleted.push({ key, data });
|
|
101
109
|
}
|
|
102
110
|
}
|
|
111
|
+
return { created, updated, deleted };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Rolls back the transaction.
|
|
115
|
+
* Clears all buffers and marks the transaction as finished.
|
|
116
|
+
* @returns The result object with success, created, updated, and deleted keys.
|
|
117
|
+
*/
|
|
118
|
+
rollback() {
|
|
119
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
103
120
|
this.writeBuffer.clear();
|
|
104
121
|
this.deleteBuffer.clear();
|
|
105
122
|
this.createdKeys.clear();
|
|
@@ -193,38 +210,57 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
193
210
|
return this._diskRead(key, snapshotVersion);
|
|
194
211
|
}
|
|
195
212
|
}
|
|
196
|
-
commit() {
|
|
213
|
+
commit(label) {
|
|
214
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
197
215
|
if (this.committed) {
|
|
198
|
-
return {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
216
|
+
return {
|
|
217
|
+
label,
|
|
218
|
+
success: false,
|
|
219
|
+
error: "Transaction already committed",
|
|
220
|
+
conflict: void 0,
|
|
221
|
+
created,
|
|
222
|
+
updated,
|
|
223
|
+
deleted
|
|
224
|
+
};
|
|
208
225
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
226
|
+
if (this.hasCommittedAncestor()) {
|
|
227
|
+
return {
|
|
228
|
+
label,
|
|
229
|
+
success: false,
|
|
230
|
+
error: "Ancestor transaction already committed",
|
|
231
|
+
conflict: void 0,
|
|
232
|
+
created,
|
|
233
|
+
updated,
|
|
234
|
+
deleted
|
|
235
|
+
};
|
|
216
236
|
}
|
|
217
237
|
if (this.parent) {
|
|
218
|
-
const
|
|
219
|
-
if (
|
|
220
|
-
return {
|
|
238
|
+
const failure = this.parent._merge(this);
|
|
239
|
+
if (failure) {
|
|
240
|
+
return {
|
|
241
|
+
label,
|
|
242
|
+
success: false,
|
|
243
|
+
error: failure.error,
|
|
244
|
+
conflict: failure.conflict,
|
|
245
|
+
created,
|
|
246
|
+
updated,
|
|
247
|
+
deleted
|
|
248
|
+
};
|
|
221
249
|
}
|
|
222
250
|
this.committed = true;
|
|
223
251
|
} else {
|
|
224
252
|
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
225
|
-
const
|
|
226
|
-
if (
|
|
227
|
-
return {
|
|
253
|
+
const failure = this._merge(this);
|
|
254
|
+
if (failure) {
|
|
255
|
+
return {
|
|
256
|
+
label,
|
|
257
|
+
success: false,
|
|
258
|
+
error: failure.error,
|
|
259
|
+
conflict: failure.conflict,
|
|
260
|
+
created: [],
|
|
261
|
+
updated: [],
|
|
262
|
+
deleted: []
|
|
263
|
+
};
|
|
228
264
|
}
|
|
229
265
|
this.writeBuffer.clear();
|
|
230
266
|
this.deleteBuffer.clear();
|
|
@@ -235,20 +271,40 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
235
271
|
this.localVersion = 0;
|
|
236
272
|
}
|
|
237
273
|
}
|
|
238
|
-
return {
|
|
274
|
+
return {
|
|
275
|
+
label,
|
|
276
|
+
success: true,
|
|
277
|
+
created,
|
|
278
|
+
updated,
|
|
279
|
+
deleted
|
|
280
|
+
};
|
|
239
281
|
}
|
|
240
282
|
_merge(child) {
|
|
241
283
|
if (this.parent) {
|
|
242
284
|
for (const key of child.writeBuffer.keys()) {
|
|
243
285
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
244
286
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
245
|
-
return
|
|
287
|
+
return {
|
|
288
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
289
|
+
conflict: {
|
|
290
|
+
key,
|
|
291
|
+
parent: this.read(key),
|
|
292
|
+
child: child.read(key)
|
|
293
|
+
}
|
|
294
|
+
};
|
|
246
295
|
}
|
|
247
296
|
}
|
|
248
297
|
for (const key of child.deleteBuffer) {
|
|
249
298
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
250
299
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
251
|
-
return
|
|
300
|
+
return {
|
|
301
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
302
|
+
conflict: {
|
|
303
|
+
key,
|
|
304
|
+
parent: this.read(key),
|
|
305
|
+
child: child.read(key)
|
|
306
|
+
}
|
|
307
|
+
};
|
|
252
308
|
}
|
|
253
309
|
}
|
|
254
310
|
const newLocalVersion = this.localVersion + 1;
|
|
@@ -276,18 +332,45 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
276
332
|
this.localVersion = newLocalVersion;
|
|
277
333
|
this.root.activeTransactions.delete(child);
|
|
278
334
|
} else {
|
|
279
|
-
this.root.activeTransactions.delete(child);
|
|
280
335
|
const newVersion = this.version + 1;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
336
|
+
if (child !== this) {
|
|
337
|
+
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
338
|
+
for (const key of modifiedKeys) {
|
|
339
|
+
const versions = this.versionIndex.get(key);
|
|
340
|
+
if (versions && versions.length > 0) {
|
|
341
|
+
const lastVer = versions[versions.length - 1].version;
|
|
342
|
+
if (lastVer > child.snapshotVersion) {
|
|
343
|
+
return {
|
|
344
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
345
|
+
conflict: {
|
|
346
|
+
key,
|
|
347
|
+
parent: this.read(key),
|
|
348
|
+
child: child.read(key)
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
}
|
|
288
352
|
}
|
|
289
353
|
}
|
|
290
354
|
}
|
|
355
|
+
for (const [key, value] of child.writeBuffer) {
|
|
356
|
+
this.writeBuffer.set(key, value);
|
|
357
|
+
this.deleteBuffer.delete(key);
|
|
358
|
+
if (child.createdKeys.has(key)) {
|
|
359
|
+
this.createdKeys.add(key);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const key of child.deleteBuffer) {
|
|
363
|
+
this.deleteBuffer.add(key);
|
|
364
|
+
this.writeBuffer.delete(key);
|
|
365
|
+
this.createdKeys.delete(key);
|
|
366
|
+
const deletedValue = child.deletedValues.get(key);
|
|
367
|
+
if (deletedValue !== void 0) {
|
|
368
|
+
this.deletedValues.set(key, deletedValue);
|
|
369
|
+
}
|
|
370
|
+
if (child.originallyExisted.has(key)) {
|
|
371
|
+
this.originallyExisted.add(key);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
291
374
|
for (const [key, value] of child.writeBuffer) {
|
|
292
375
|
this._diskWrite(key, value, newVersion);
|
|
293
376
|
}
|
|
@@ -295,6 +378,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
295
378
|
this._diskDelete(key, newVersion);
|
|
296
379
|
}
|
|
297
380
|
this.version = newVersion;
|
|
381
|
+
this.root.activeTransactions.delete(child);
|
|
298
382
|
this._cleanupDeletedCache();
|
|
299
383
|
}
|
|
300
384
|
return null;
|
|
@@ -745,51 +829,74 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
745
829
|
return this._diskRead(key, snapshotVersion);
|
|
746
830
|
}
|
|
747
831
|
}
|
|
748
|
-
async commit() {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
832
|
+
async commit(label) {
|
|
833
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
834
|
+
if (this.committed) {
|
|
835
|
+
return {
|
|
836
|
+
label,
|
|
837
|
+
success: false,
|
|
838
|
+
error: "Transaction already committed",
|
|
839
|
+
conflict: void 0,
|
|
840
|
+
created,
|
|
841
|
+
updated,
|
|
842
|
+
deleted
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
if (this.hasCommittedAncestor()) {
|
|
846
|
+
return {
|
|
847
|
+
label,
|
|
848
|
+
success: false,
|
|
849
|
+
error: "Ancestor transaction already committed",
|
|
850
|
+
conflict: void 0,
|
|
851
|
+
created,
|
|
852
|
+
updated,
|
|
853
|
+
deleted
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
if (this.parent) {
|
|
857
|
+
const failure = await this.parent._merge(this);
|
|
858
|
+
if (failure) {
|
|
859
|
+
return {
|
|
860
|
+
label,
|
|
861
|
+
success: false,
|
|
862
|
+
error: failure.error,
|
|
863
|
+
conflict: failure.conflict,
|
|
864
|
+
created,
|
|
865
|
+
updated,
|
|
866
|
+
deleted
|
|
867
|
+
};
|
|
769
868
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
this.createdKeys.clear();
|
|
785
|
-
this.deletedValues.clear();
|
|
786
|
-
this.originallyExisted.clear();
|
|
787
|
-
this.keyVersions.clear();
|
|
788
|
-
this.localVersion = 0;
|
|
869
|
+
this.committed = true;
|
|
870
|
+
} else {
|
|
871
|
+
if (this.writeBuffer.size > 0 || this.deleteBuffer.size > 0) {
|
|
872
|
+
const failure = await this._merge(this);
|
|
873
|
+
if (failure) {
|
|
874
|
+
return {
|
|
875
|
+
label,
|
|
876
|
+
success: false,
|
|
877
|
+
error: failure.error,
|
|
878
|
+
conflict: failure.conflict,
|
|
879
|
+
created: [],
|
|
880
|
+
updated: [],
|
|
881
|
+
deleted: []
|
|
882
|
+
};
|
|
789
883
|
}
|
|
884
|
+
this.writeBuffer.clear();
|
|
885
|
+
this.deleteBuffer.clear();
|
|
886
|
+
this.createdKeys.clear();
|
|
887
|
+
this.deletedValues.clear();
|
|
888
|
+
this.originallyExisted.clear();
|
|
889
|
+
this.keyVersions.clear();
|
|
890
|
+
this.localVersion = 0;
|
|
790
891
|
}
|
|
791
|
-
|
|
792
|
-
|
|
892
|
+
}
|
|
893
|
+
return {
|
|
894
|
+
label,
|
|
895
|
+
success: true,
|
|
896
|
+
created,
|
|
897
|
+
updated,
|
|
898
|
+
deleted
|
|
899
|
+
};
|
|
793
900
|
}
|
|
794
901
|
async _merge(child) {
|
|
795
902
|
return this.writeLock(async () => {
|
|
@@ -797,13 +904,27 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
797
904
|
for (const key of child.writeBuffer.keys()) {
|
|
798
905
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
799
906
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
800
|
-
return
|
|
907
|
+
return {
|
|
908
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
909
|
+
conflict: {
|
|
910
|
+
key,
|
|
911
|
+
parent: await this.read(key),
|
|
912
|
+
child: await child.read(key)
|
|
913
|
+
}
|
|
914
|
+
};
|
|
801
915
|
}
|
|
802
916
|
}
|
|
803
917
|
for (const key of child.deleteBuffer) {
|
|
804
918
|
const lastModLocalVer = this.keyVersions.get(key);
|
|
805
919
|
if (lastModLocalVer !== void 0 && lastModLocalVer > child.snapshotLocalVersion) {
|
|
806
|
-
return
|
|
920
|
+
return {
|
|
921
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (Local v${lastModLocalVer})`,
|
|
922
|
+
conflict: {
|
|
923
|
+
key,
|
|
924
|
+
parent: await this.read(key),
|
|
925
|
+
child: await child.read(key)
|
|
926
|
+
}
|
|
927
|
+
};
|
|
807
928
|
}
|
|
808
929
|
}
|
|
809
930
|
const newLocalVersion = this.localVersion + 1;
|
|
@@ -830,19 +951,47 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
830
951
|
}
|
|
831
952
|
this.localVersion = newLocalVersion;
|
|
832
953
|
this.root.activeTransactions.delete(child);
|
|
954
|
+
return null;
|
|
833
955
|
} else {
|
|
834
|
-
this.root.activeTransactions.delete(child);
|
|
835
956
|
const newVersion = this.version + 1;
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
957
|
+
if (child !== this) {
|
|
958
|
+
const modifiedKeys = /* @__PURE__ */ new Set([...child.writeBuffer.keys(), ...child.deleteBuffer]);
|
|
959
|
+
for (const key of modifiedKeys) {
|
|
960
|
+
const versions = this.versionIndex.get(key);
|
|
961
|
+
if (versions && versions.length > 0) {
|
|
962
|
+
const lastVer = versions[versions.length - 1].version;
|
|
963
|
+
if (lastVer > child.snapshotVersion) {
|
|
964
|
+
return {
|
|
965
|
+
error: `Commit conflict: Key '${key}' was modified by a newer transaction (v${lastVer})`,
|
|
966
|
+
conflict: {
|
|
967
|
+
key,
|
|
968
|
+
parent: await this.read(key),
|
|
969
|
+
child: await child.read(key)
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
}
|
|
843
973
|
}
|
|
844
974
|
}
|
|
845
975
|
}
|
|
976
|
+
for (const [key, value] of child.writeBuffer) {
|
|
977
|
+
this.writeBuffer.set(key, value);
|
|
978
|
+
this.deleteBuffer.delete(key);
|
|
979
|
+
if (child.createdKeys.has(key)) {
|
|
980
|
+
this.createdKeys.add(key);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
for (const key of child.deleteBuffer) {
|
|
984
|
+
this.deleteBuffer.add(key);
|
|
985
|
+
this.writeBuffer.delete(key);
|
|
986
|
+
this.createdKeys.delete(key);
|
|
987
|
+
const deletedValue = child.deletedValues.get(key);
|
|
988
|
+
if (deletedValue !== void 0) {
|
|
989
|
+
this.deletedValues.set(key, deletedValue);
|
|
990
|
+
}
|
|
991
|
+
if (child.originallyExisted.has(key)) {
|
|
992
|
+
this.originallyExisted.add(key);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
846
995
|
for (const [key, value] of child.writeBuffer) {
|
|
847
996
|
await this._diskWrite(key, value, newVersion);
|
|
848
997
|
}
|
|
@@ -850,9 +999,10 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
850
999
|
await this._diskDelete(key, newVersion);
|
|
851
1000
|
}
|
|
852
1001
|
this.version = newVersion;
|
|
1002
|
+
this.root.activeTransactions.delete(child);
|
|
853
1003
|
this._cleanupDeletedCache();
|
|
1004
|
+
return null;
|
|
854
1005
|
}
|
|
855
|
-
return null;
|
|
856
1006
|
});
|
|
857
1007
|
}
|
|
858
1008
|
// --- Internal IO Helpers (Root Only) ---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AsyncMVCCStrategy } from './Strategy';
|
|
2
|
-
import type { TransactionResult } from '../../types';
|
|
2
|
+
import type { TransactionMergeFailure, TransactionResult } from '../../types';
|
|
3
3
|
import { MVCCTransaction } from '../base';
|
|
4
4
|
export declare class AsyncMVCCTransaction<S extends AsyncMVCCStrategy<K, T>, K, T> extends MVCCTransaction<S, K, T> {
|
|
5
5
|
private lock;
|
|
@@ -11,8 +11,8 @@ export declare class AsyncMVCCTransaction<S extends AsyncMVCCStrategy<K, T>, K,
|
|
|
11
11
|
read(key: K): Promise<T | null>;
|
|
12
12
|
exists(key: K): Promise<boolean>;
|
|
13
13
|
_readSnapshot(key: K, snapshotVersion: number, snapshotLocalVersion?: number): Promise<T | null>;
|
|
14
|
-
commit(): Promise<TransactionResult<K, T>>;
|
|
15
|
-
_merge(child: MVCCTransaction<S, K, T>): Promise<
|
|
14
|
+
commit(label?: string): Promise<TransactionResult<K, T>>;
|
|
15
|
+
_merge(child: MVCCTransaction<S, K, T>): Promise<TransactionMergeFailure<K, T> | null>;
|
|
16
16
|
_diskWrite(key: K, value: T, version: number): Promise<void>;
|
|
17
17
|
_diskRead(key: K, snapshotVersion: number): Promise<T | null>;
|
|
18
18
|
_diskExists(key: K, snapshotVersion: number): Promise<boolean>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Deferred, TransactionResult } from '../../types';
|
|
1
|
+
import type { Deferred, TransactionResult, TransactionEntry, TransactionMergeFailure } from '../../types';
|
|
2
2
|
import type { MVCCStrategy } from './Strategy';
|
|
3
3
|
/**
|
|
4
4
|
* MVCC Transaction abstract class.
|
|
@@ -34,6 +34,12 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
34
34
|
protected activeTransactions: Set<MVCCTransaction<S, K, T>>;
|
|
35
35
|
constructor(strategy?: S, parent?: MVCCTransaction<S, K, T>, snapshotVersion?: number);
|
|
36
36
|
isRoot(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Checks if any ancestor transaction has already been committed.
|
|
39
|
+
* A nested transaction cannot commit if its parent or any higher ancestor is committed.
|
|
40
|
+
* @returns True if at least one ancestor is committed, false otherwise.
|
|
41
|
+
*/
|
|
42
|
+
hasCommittedAncestor(): boolean;
|
|
37
43
|
/**
|
|
38
44
|
* Schedules a creation (insert) of a key-value pair.
|
|
39
45
|
* Throws if the key already exists.
|
|
@@ -60,6 +66,11 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
60
66
|
protected _bufferCreate(key: K, value: T): void;
|
|
61
67
|
protected _bufferWrite(key: K, value: T): void;
|
|
62
68
|
protected _bufferDelete(key: K): void;
|
|
69
|
+
protected _getResultEntries(): {
|
|
70
|
+
created: TransactionEntry<K, T>[];
|
|
71
|
+
updated: TransactionEntry<K, T>[];
|
|
72
|
+
deleted: TransactionEntry<K, T>[];
|
|
73
|
+
};
|
|
63
74
|
/**
|
|
64
75
|
* Rolls back the transaction.
|
|
65
76
|
* Clears all buffers and marks the transaction as finished.
|
|
@@ -82,9 +93,10 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
82
93
|
* Commits the transaction.
|
|
83
94
|
* If root, persists to storage.
|
|
84
95
|
* If nested, merges to parent.
|
|
96
|
+
* @param label The label for the commit.
|
|
85
97
|
* @returns The result object with success, created, and obsolete keys.
|
|
86
98
|
*/
|
|
87
|
-
abstract commit(): Deferred<TransactionResult<K, T>>;
|
|
99
|
+
abstract commit(label?: string): Deferred<TransactionResult<K, T>>;
|
|
88
100
|
/**
|
|
89
101
|
* Creates a nested transaction (child) from this transaction.
|
|
90
102
|
* @returns A new nested transaction instance.
|
|
@@ -95,7 +107,7 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
95
107
|
* @param child The committed child transaction.
|
|
96
108
|
* @returns Error message if conflict, null if success.
|
|
97
109
|
*/
|
|
98
|
-
abstract _merge(child: MVCCTransaction<S, K, T>): Deferred<
|
|
110
|
+
abstract _merge(child: MVCCTransaction<S, K, T>): Deferred<TransactionMergeFailure<K, T> | null>;
|
|
99
111
|
/**
|
|
100
112
|
* Reads a value at a specific snapshot version.
|
|
101
113
|
* Used by child transactions to read from parent respecting the child's snapshot.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SyncMVCCStrategy } from './Strategy';
|
|
2
|
-
import type { TransactionResult } from '../../types';
|
|
2
|
+
import type { TransactionResult, TransactionMergeFailure } from '../../types';
|
|
3
3
|
import { MVCCTransaction } from '../base';
|
|
4
4
|
export declare class SyncMVCCTransaction<S extends SyncMVCCStrategy<K, T>, K, T> extends MVCCTransaction<S, K, T> {
|
|
5
5
|
create(key: K, value: T): this;
|
|
@@ -9,8 +9,8 @@ export declare class SyncMVCCTransaction<S extends SyncMVCCStrategy<K, T>, K, T>
|
|
|
9
9
|
read(key: K): T | null;
|
|
10
10
|
exists(key: K): boolean;
|
|
11
11
|
_readSnapshot(key: K, snapshotVersion: number, snapshotLocalVersion?: number): T | null;
|
|
12
|
-
commit(): TransactionResult<K, T>;
|
|
13
|
-
_merge(child:
|
|
12
|
+
commit(label?: string): TransactionResult<K, T>;
|
|
13
|
+
_merge(child: SyncMVCCTransaction<S, K, T>): TransactionMergeFailure<K, T> | null;
|
|
14
14
|
_diskWrite(key: K, value: T, version: number): void;
|
|
15
15
|
_diskRead(key: K, snapshotVersion: number): T | null;
|
|
16
16
|
_diskExists(key: K, snapshotVersion: number): boolean;
|
|
@@ -7,9 +7,26 @@ export type TransactionEntry<K, T> = {
|
|
|
7
7
|
key: K;
|
|
8
8
|
data: T;
|
|
9
9
|
};
|
|
10
|
+
export type TransactionConflict<K, T> = {
|
|
11
|
+
key: K;
|
|
12
|
+
parent: T;
|
|
13
|
+
child: T;
|
|
14
|
+
};
|
|
15
|
+
export type TransactionMergeFailure<K, T> = {
|
|
16
|
+
error: string;
|
|
17
|
+
conflict: TransactionConflict<K, T>;
|
|
18
|
+
};
|
|
10
19
|
export type TransactionResult<K, T> = {
|
|
11
|
-
|
|
12
|
-
|
|
20
|
+
label?: string;
|
|
21
|
+
success: true;
|
|
22
|
+
created: TransactionEntry<K, T>[];
|
|
23
|
+
updated: TransactionEntry<K, T>[];
|
|
24
|
+
deleted: TransactionEntry<K, T>[];
|
|
25
|
+
} | {
|
|
26
|
+
label?: string;
|
|
27
|
+
success: false;
|
|
28
|
+
error: string;
|
|
29
|
+
conflict?: TransactionConflict<K, T>;
|
|
13
30
|
created: TransactionEntry<K, T>[];
|
|
14
31
|
updated: TransactionEntry<K, T>[];
|
|
15
32
|
deleted: TransactionEntry<K, T>[];
|