mvcc-api 1.2.1 → 1.2.3
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/cjs/index.cjs +57 -40
- package/dist/esm/index.mjs +57 -40
- package/dist/types/core/base/Transaction.d.ts +13 -1
- package/package.json +1 -1
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();
|
|
@@ -81,12 +84,26 @@ var MVCCTransaction = class {
|
|
|
81
84
|
isRoot() {
|
|
82
85
|
return !this.parent;
|
|
83
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
|
+
}
|
|
84
100
|
// --- Internal buffer manipulation helpers ---
|
|
85
101
|
_bufferCreate(key, value) {
|
|
86
102
|
this.localVersion++;
|
|
87
103
|
this.writeBuffer.set(key, value);
|
|
88
104
|
this.createdKeys.add(key);
|
|
89
105
|
this.deleteBuffer.delete(key);
|
|
106
|
+
this.originallyExisted.delete(key);
|
|
90
107
|
this.keyVersions.set(key, this.localVersion);
|
|
91
108
|
}
|
|
92
109
|
_bufferWrite(key, value) {
|
|
@@ -102,12 +119,7 @@ var MVCCTransaction = class {
|
|
|
102
119
|
this.createdKeys.delete(key);
|
|
103
120
|
this.keyVersions.set(key, this.localVersion);
|
|
104
121
|
}
|
|
105
|
-
|
|
106
|
-
* Rolls back the transaction.
|
|
107
|
-
* Clears all buffers and marks the transaction as finished.
|
|
108
|
-
* @returns The result object with success, created, updated, and deleted keys.
|
|
109
|
-
*/
|
|
110
|
-
rollback() {
|
|
122
|
+
_getResultEntries() {
|
|
111
123
|
const created = [];
|
|
112
124
|
const updated = [];
|
|
113
125
|
for (const [key, data] of this.writeBuffer.entries()) {
|
|
@@ -119,15 +131,26 @@ var MVCCTransaction = class {
|
|
|
119
131
|
}
|
|
120
132
|
const deleted = [];
|
|
121
133
|
for (const key of this.deleteBuffer) {
|
|
134
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
122
135
|
const data = this.deletedValues.get(key);
|
|
123
136
|
if (data !== void 0) {
|
|
124
137
|
deleted.push({ key, data });
|
|
125
138
|
}
|
|
126
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();
|
|
127
149
|
this.writeBuffer.clear();
|
|
128
150
|
this.deleteBuffer.clear();
|
|
129
151
|
this.createdKeys.clear();
|
|
130
152
|
this.deletedValues.clear();
|
|
153
|
+
this.originallyExisted.clear();
|
|
131
154
|
this.committed = true;
|
|
132
155
|
if (this.root !== this) {
|
|
133
156
|
this.root.activeTransactions.delete(this);
|
|
@@ -161,8 +184,10 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
161
184
|
delete(key) {
|
|
162
185
|
if (this.committed) throw new Error("Transaction already committed");
|
|
163
186
|
let valueToDelete = null;
|
|
187
|
+
let wasInWriteBuffer = false;
|
|
164
188
|
if (this.writeBuffer.has(key)) {
|
|
165
189
|
valueToDelete = this.writeBuffer.get(key);
|
|
190
|
+
wasInWriteBuffer = true;
|
|
166
191
|
} else if (!this.deleteBuffer.has(key)) {
|
|
167
192
|
valueToDelete = this.read(key);
|
|
168
193
|
}
|
|
@@ -170,6 +195,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
170
195
|
throw new Error(`Key not found: ${key}`);
|
|
171
196
|
}
|
|
172
197
|
this.deletedValues.set(key, valueToDelete);
|
|
198
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
199
|
+
this.originallyExisted.add(key);
|
|
200
|
+
}
|
|
173
201
|
this._bufferDelete(key);
|
|
174
202
|
return this;
|
|
175
203
|
}
|
|
@@ -212,29 +240,17 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
212
240
|
}
|
|
213
241
|
}
|
|
214
242
|
commit() {
|
|
243
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
215
244
|
if (this.committed) {
|
|
216
|
-
return { success: false, error: "Transaction already committed", created
|
|
245
|
+
return { success: false, error: "Transaction already committed", created, updated, deleted };
|
|
217
246
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
for (const [key, data] of this.writeBuffer.entries()) {
|
|
221
|
-
if (this.createdKeys.has(key)) {
|
|
222
|
-
created.push({ key, data });
|
|
223
|
-
} else {
|
|
224
|
-
updated.push({ key, data });
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
const deleted = [];
|
|
228
|
-
for (const key of this.deleteBuffer) {
|
|
229
|
-
const data = this.deletedValues.get(key);
|
|
230
|
-
if (data !== void 0) {
|
|
231
|
-
deleted.push({ key, data });
|
|
232
|
-
}
|
|
247
|
+
if (this.hasCommittedAncestor()) {
|
|
248
|
+
return { success: false, error: "Ancestor transaction already committed", created, updated, deleted };
|
|
233
249
|
}
|
|
234
250
|
if (this.parent) {
|
|
235
251
|
const error = this.parent._merge(this);
|
|
236
252
|
if (error) {
|
|
237
|
-
return { success: false, error, created
|
|
253
|
+
return { success: false, error, created, updated, deleted };
|
|
238
254
|
}
|
|
239
255
|
this.committed = true;
|
|
240
256
|
} else {
|
|
@@ -247,6 +263,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
247
263
|
this.deleteBuffer.clear();
|
|
248
264
|
this.createdKeys.clear();
|
|
249
265
|
this.deletedValues.clear();
|
|
266
|
+
this.originallyExisted.clear();
|
|
250
267
|
this.keyVersions.clear();
|
|
251
268
|
this.localVersion = 0;
|
|
252
269
|
}
|
|
@@ -285,6 +302,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
285
302
|
if (deletedValue !== void 0) {
|
|
286
303
|
this.deletedValues.set(key, deletedValue);
|
|
287
304
|
}
|
|
305
|
+
if (child.originallyExisted.has(key)) {
|
|
306
|
+
this.originallyExisted.add(key);
|
|
307
|
+
}
|
|
288
308
|
}
|
|
289
309
|
this.localVersion = newLocalVersion;
|
|
290
310
|
this.root.activeTransactions.delete(child);
|
|
@@ -703,8 +723,10 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
703
723
|
async delete(key) {
|
|
704
724
|
if (this.committed) throw new Error("Transaction already committed");
|
|
705
725
|
let valueToDelete = null;
|
|
726
|
+
let wasInWriteBuffer = false;
|
|
706
727
|
if (this.writeBuffer.has(key)) {
|
|
707
728
|
valueToDelete = this.writeBuffer.get(key);
|
|
729
|
+
wasInWriteBuffer = true;
|
|
708
730
|
} else if (!this.deleteBuffer.has(key)) {
|
|
709
731
|
valueToDelete = await this.read(key);
|
|
710
732
|
}
|
|
@@ -712,6 +734,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
712
734
|
throw new Error(`Key not found: ${key}`);
|
|
713
735
|
}
|
|
714
736
|
this.deletedValues.set(key, valueToDelete);
|
|
737
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
738
|
+
this.originallyExisted.add(key);
|
|
739
|
+
}
|
|
715
740
|
this._bufferDelete(key);
|
|
716
741
|
return this;
|
|
717
742
|
}
|
|
@@ -755,29 +780,17 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
755
780
|
}
|
|
756
781
|
async commit() {
|
|
757
782
|
return this.writeLock(async () => {
|
|
783
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
758
784
|
if (this.committed) {
|
|
759
|
-
return { success: false, error: "Transaction already committed", created
|
|
760
|
-
}
|
|
761
|
-
const created = [];
|
|
762
|
-
const updated = [];
|
|
763
|
-
for (const [key, data] of this.writeBuffer.entries()) {
|
|
764
|
-
if (this.createdKeys.has(key)) {
|
|
765
|
-
created.push({ key, data });
|
|
766
|
-
} else {
|
|
767
|
-
updated.push({ key, data });
|
|
768
|
-
}
|
|
785
|
+
return { success: false, error: "Transaction already committed", created, updated, deleted };
|
|
769
786
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
const data = this.deletedValues.get(key);
|
|
773
|
-
if (data !== void 0) {
|
|
774
|
-
deleted.push({ key, data });
|
|
775
|
-
}
|
|
787
|
+
if (this.hasCommittedAncestor()) {
|
|
788
|
+
return { success: false, error: "Ancestor transaction already committed", created, updated, deleted };
|
|
776
789
|
}
|
|
777
790
|
if (this.parent) {
|
|
778
791
|
const error = await this.parent._merge(this);
|
|
779
792
|
if (error) {
|
|
780
|
-
return { success: false, error, created
|
|
793
|
+
return { success: false, error, created, updated, deleted };
|
|
781
794
|
}
|
|
782
795
|
this.committed = true;
|
|
783
796
|
} else {
|
|
@@ -790,6 +803,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
790
803
|
this.deleteBuffer.clear();
|
|
791
804
|
this.createdKeys.clear();
|
|
792
805
|
this.deletedValues.clear();
|
|
806
|
+
this.originallyExisted.clear();
|
|
793
807
|
this.keyVersions.clear();
|
|
794
808
|
this.localVersion = 0;
|
|
795
809
|
}
|
|
@@ -830,6 +844,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
830
844
|
if (deletedValue !== void 0) {
|
|
831
845
|
this.deletedValues.set(key, deletedValue);
|
|
832
846
|
}
|
|
847
|
+
if (child.originallyExisted.has(key)) {
|
|
848
|
+
this.originallyExisted.add(key);
|
|
849
|
+
}
|
|
833
850
|
}
|
|
834
851
|
this.localVersion = newLocalVersion;
|
|
835
852
|
this.root.activeTransactions.delete(child);
|
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();
|
|
@@ -52,12 +55,26 @@ var MVCCTransaction = class {
|
|
|
52
55
|
isRoot() {
|
|
53
56
|
return !this.parent;
|
|
54
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
|
+
}
|
|
55
71
|
// --- Internal buffer manipulation helpers ---
|
|
56
72
|
_bufferCreate(key, value) {
|
|
57
73
|
this.localVersion++;
|
|
58
74
|
this.writeBuffer.set(key, value);
|
|
59
75
|
this.createdKeys.add(key);
|
|
60
76
|
this.deleteBuffer.delete(key);
|
|
77
|
+
this.originallyExisted.delete(key);
|
|
61
78
|
this.keyVersions.set(key, this.localVersion);
|
|
62
79
|
}
|
|
63
80
|
_bufferWrite(key, value) {
|
|
@@ -73,12 +90,7 @@ var MVCCTransaction = class {
|
|
|
73
90
|
this.createdKeys.delete(key);
|
|
74
91
|
this.keyVersions.set(key, this.localVersion);
|
|
75
92
|
}
|
|
76
|
-
|
|
77
|
-
* Rolls back the transaction.
|
|
78
|
-
* Clears all buffers and marks the transaction as finished.
|
|
79
|
-
* @returns The result object with success, created, updated, and deleted keys.
|
|
80
|
-
*/
|
|
81
|
-
rollback() {
|
|
93
|
+
_getResultEntries() {
|
|
82
94
|
const created = [];
|
|
83
95
|
const updated = [];
|
|
84
96
|
for (const [key, data] of this.writeBuffer.entries()) {
|
|
@@ -90,15 +102,26 @@ var MVCCTransaction = class {
|
|
|
90
102
|
}
|
|
91
103
|
const deleted = [];
|
|
92
104
|
for (const key of this.deleteBuffer) {
|
|
105
|
+
if (!this.originallyExisted.has(key)) continue;
|
|
93
106
|
const data = this.deletedValues.get(key);
|
|
94
107
|
if (data !== void 0) {
|
|
95
108
|
deleted.push({ key, data });
|
|
96
109
|
}
|
|
97
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();
|
|
98
120
|
this.writeBuffer.clear();
|
|
99
121
|
this.deleteBuffer.clear();
|
|
100
122
|
this.createdKeys.clear();
|
|
101
123
|
this.deletedValues.clear();
|
|
124
|
+
this.originallyExisted.clear();
|
|
102
125
|
this.committed = true;
|
|
103
126
|
if (this.root !== this) {
|
|
104
127
|
this.root.activeTransactions.delete(this);
|
|
@@ -132,8 +155,10 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
132
155
|
delete(key) {
|
|
133
156
|
if (this.committed) throw new Error("Transaction already committed");
|
|
134
157
|
let valueToDelete = null;
|
|
158
|
+
let wasInWriteBuffer = false;
|
|
135
159
|
if (this.writeBuffer.has(key)) {
|
|
136
160
|
valueToDelete = this.writeBuffer.get(key);
|
|
161
|
+
wasInWriteBuffer = true;
|
|
137
162
|
} else if (!this.deleteBuffer.has(key)) {
|
|
138
163
|
valueToDelete = this.read(key);
|
|
139
164
|
}
|
|
@@ -141,6 +166,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
141
166
|
throw new Error(`Key not found: ${key}`);
|
|
142
167
|
}
|
|
143
168
|
this.deletedValues.set(key, valueToDelete);
|
|
169
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
170
|
+
this.originallyExisted.add(key);
|
|
171
|
+
}
|
|
144
172
|
this._bufferDelete(key);
|
|
145
173
|
return this;
|
|
146
174
|
}
|
|
@@ -183,29 +211,17 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
183
211
|
}
|
|
184
212
|
}
|
|
185
213
|
commit() {
|
|
214
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
186
215
|
if (this.committed) {
|
|
187
|
-
return { success: false, error: "Transaction already committed", created
|
|
216
|
+
return { success: false, error: "Transaction already committed", created, updated, deleted };
|
|
188
217
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
for (const [key, data] of this.writeBuffer.entries()) {
|
|
192
|
-
if (this.createdKeys.has(key)) {
|
|
193
|
-
created.push({ key, data });
|
|
194
|
-
} else {
|
|
195
|
-
updated.push({ key, data });
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
const deleted = [];
|
|
199
|
-
for (const key of this.deleteBuffer) {
|
|
200
|
-
const data = this.deletedValues.get(key);
|
|
201
|
-
if (data !== void 0) {
|
|
202
|
-
deleted.push({ key, data });
|
|
203
|
-
}
|
|
218
|
+
if (this.hasCommittedAncestor()) {
|
|
219
|
+
return { success: false, error: "Ancestor transaction already committed", created, updated, deleted };
|
|
204
220
|
}
|
|
205
221
|
if (this.parent) {
|
|
206
222
|
const error = this.parent._merge(this);
|
|
207
223
|
if (error) {
|
|
208
|
-
return { success: false, error, created
|
|
224
|
+
return { success: false, error, created, updated, deleted };
|
|
209
225
|
}
|
|
210
226
|
this.committed = true;
|
|
211
227
|
} else {
|
|
@@ -218,6 +234,7 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
218
234
|
this.deleteBuffer.clear();
|
|
219
235
|
this.createdKeys.clear();
|
|
220
236
|
this.deletedValues.clear();
|
|
237
|
+
this.originallyExisted.clear();
|
|
221
238
|
this.keyVersions.clear();
|
|
222
239
|
this.localVersion = 0;
|
|
223
240
|
}
|
|
@@ -256,6 +273,9 @@ var SyncMVCCTransaction = class _SyncMVCCTransaction extends MVCCTransaction {
|
|
|
256
273
|
if (deletedValue !== void 0) {
|
|
257
274
|
this.deletedValues.set(key, deletedValue);
|
|
258
275
|
}
|
|
276
|
+
if (child.originallyExisted.has(key)) {
|
|
277
|
+
this.originallyExisted.add(key);
|
|
278
|
+
}
|
|
259
279
|
}
|
|
260
280
|
this.localVersion = newLocalVersion;
|
|
261
281
|
this.root.activeTransactions.delete(child);
|
|
@@ -674,8 +694,10 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
674
694
|
async delete(key) {
|
|
675
695
|
if (this.committed) throw new Error("Transaction already committed");
|
|
676
696
|
let valueToDelete = null;
|
|
697
|
+
let wasInWriteBuffer = false;
|
|
677
698
|
if (this.writeBuffer.has(key)) {
|
|
678
699
|
valueToDelete = this.writeBuffer.get(key);
|
|
700
|
+
wasInWriteBuffer = true;
|
|
679
701
|
} else if (!this.deleteBuffer.has(key)) {
|
|
680
702
|
valueToDelete = await this.read(key);
|
|
681
703
|
}
|
|
@@ -683,6 +705,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
683
705
|
throw new Error(`Key not found: ${key}`);
|
|
684
706
|
}
|
|
685
707
|
this.deletedValues.set(key, valueToDelete);
|
|
708
|
+
if (!wasInWriteBuffer || !this.createdKeys.has(key)) {
|
|
709
|
+
this.originallyExisted.add(key);
|
|
710
|
+
}
|
|
686
711
|
this._bufferDelete(key);
|
|
687
712
|
return this;
|
|
688
713
|
}
|
|
@@ -726,29 +751,17 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
726
751
|
}
|
|
727
752
|
async commit() {
|
|
728
753
|
return this.writeLock(async () => {
|
|
754
|
+
const { created, updated, deleted } = this._getResultEntries();
|
|
729
755
|
if (this.committed) {
|
|
730
|
-
return { success: false, error: "Transaction already committed", created
|
|
731
|
-
}
|
|
732
|
-
const created = [];
|
|
733
|
-
const updated = [];
|
|
734
|
-
for (const [key, data] of this.writeBuffer.entries()) {
|
|
735
|
-
if (this.createdKeys.has(key)) {
|
|
736
|
-
created.push({ key, data });
|
|
737
|
-
} else {
|
|
738
|
-
updated.push({ key, data });
|
|
739
|
-
}
|
|
756
|
+
return { success: false, error: "Transaction already committed", created, updated, deleted };
|
|
740
757
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
const data = this.deletedValues.get(key);
|
|
744
|
-
if (data !== void 0) {
|
|
745
|
-
deleted.push({ key, data });
|
|
746
|
-
}
|
|
758
|
+
if (this.hasCommittedAncestor()) {
|
|
759
|
+
return { success: false, error: "Ancestor transaction already committed", created, updated, deleted };
|
|
747
760
|
}
|
|
748
761
|
if (this.parent) {
|
|
749
762
|
const error = await this.parent._merge(this);
|
|
750
763
|
if (error) {
|
|
751
|
-
return { success: false, error, created
|
|
764
|
+
return { success: false, error, created, updated, deleted };
|
|
752
765
|
}
|
|
753
766
|
this.committed = true;
|
|
754
767
|
} else {
|
|
@@ -761,6 +774,7 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
761
774
|
this.deleteBuffer.clear();
|
|
762
775
|
this.createdKeys.clear();
|
|
763
776
|
this.deletedValues.clear();
|
|
777
|
+
this.originallyExisted.clear();
|
|
764
778
|
this.keyVersions.clear();
|
|
765
779
|
this.localVersion = 0;
|
|
766
780
|
}
|
|
@@ -801,6 +815,9 @@ var AsyncMVCCTransaction = class _AsyncMVCCTransaction extends MVCCTransaction {
|
|
|
801
815
|
if (deletedValue !== void 0) {
|
|
802
816
|
this.deletedValues.set(key, deletedValue);
|
|
803
817
|
}
|
|
818
|
+
if (child.originallyExisted.has(key)) {
|
|
819
|
+
this.originallyExisted.add(key);
|
|
820
|
+
}
|
|
804
821
|
}
|
|
805
822
|
this.localVersion = newLocalVersion;
|
|
806
823
|
this.root.activeTransactions.delete(child);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Deferred, TransactionResult } from '../../types';
|
|
1
|
+
import type { Deferred, TransactionResult, TransactionEntry } from '../../types';
|
|
2
2
|
import type { MVCCStrategy } from './Strategy';
|
|
3
3
|
/**
|
|
4
4
|
* MVCC Transaction abstract class.
|
|
@@ -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>;
|
|
@@ -33,6 +34,12 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
33
34
|
protected activeTransactions: Set<MVCCTransaction<S, K, T>>;
|
|
34
35
|
constructor(strategy?: S, parent?: MVCCTransaction<S, K, T>, snapshotVersion?: number);
|
|
35
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;
|
|
36
43
|
/**
|
|
37
44
|
* Schedules a creation (insert) of a key-value pair.
|
|
38
45
|
* Throws if the key already exists.
|
|
@@ -59,6 +66,11 @@ export declare abstract class MVCCTransaction<S extends MVCCStrategy<K, T>, K, T
|
|
|
59
66
|
protected _bufferCreate(key: K, value: T): void;
|
|
60
67
|
protected _bufferWrite(key: K, value: T): void;
|
|
61
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
|
+
};
|
|
62
74
|
/**
|
|
63
75
|
* Rolls back the transaction.
|
|
64
76
|
* Clears all buffers and marks the transaction as finished.
|