dataply 0.0.26-alpha.7 → 0.0.26-alpha.8
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.js +72 -44
- package/dist/types/core/Dataply.d.ts +13 -1
- package/dist/types/core/DataplyAPI.d.ts +4 -13
- package/dist/types/core/transaction/GlobalTransaction.d.ts +12 -3
- package/dist/types/core/transaction/Transaction.d.ts +1 -7
- package/package.json +2 -2
- package/readme.md +20 -43
package/dist/cjs/index.js
CHANGED
|
@@ -10967,6 +10967,7 @@ var Transaction = class {
|
|
|
10967
10967
|
this.pfs = pfs;
|
|
10968
10968
|
this.id = id;
|
|
10969
10969
|
this.rootTx = rootTx;
|
|
10970
|
+
this.mvccTx = rootTx.createNested();
|
|
10970
10971
|
}
|
|
10971
10972
|
/** Transaction ID */
|
|
10972
10973
|
id;
|
|
@@ -10977,22 +10978,11 @@ var Transaction = class {
|
|
|
10977
10978
|
/** List of callbacks to execute on commit */
|
|
10978
10979
|
commitHooks = [];
|
|
10979
10980
|
/** Nested MVCC Transaction for snapshot isolation (lazy init) */
|
|
10980
|
-
mvccTx
|
|
10981
|
+
mvccTx;
|
|
10981
10982
|
/** Root MVCC Transaction reference */
|
|
10982
10983
|
rootTx;
|
|
10983
10984
|
/** Release function for global write lock, set by DataplyAPI */
|
|
10984
10985
|
_writeLockRelease = null;
|
|
10985
|
-
/**
|
|
10986
|
-
* Lazily initializes the nested MVCC transaction.
|
|
10987
|
-
* This ensures the snapshot is taken at the time of first access,
|
|
10988
|
-
* picking up the latest committed root version.
|
|
10989
|
-
*/
|
|
10990
|
-
ensureMvccTx() {
|
|
10991
|
-
if (!this.mvccTx) {
|
|
10992
|
-
this.mvccTx = this.rootTx.createNested();
|
|
10993
|
-
}
|
|
10994
|
-
return this.mvccTx;
|
|
10995
|
-
}
|
|
10996
10986
|
/**
|
|
10997
10987
|
* Registers a commit hook.
|
|
10998
10988
|
* @param hook Function to execute
|
|
@@ -11019,8 +11009,7 @@ var Transaction = class {
|
|
|
11019
11009
|
* @returns Page data
|
|
11020
11010
|
*/
|
|
11021
11011
|
async __readPage(pageId) {
|
|
11022
|
-
const
|
|
11023
|
-
const data = await tx.read(pageId);
|
|
11012
|
+
const data = await this.mvccTx.read(pageId);
|
|
11024
11013
|
if (data === null) {
|
|
11025
11014
|
return new Uint8Array(this.pfs.pageSize);
|
|
11026
11015
|
}
|
|
@@ -11034,14 +11023,13 @@ var Transaction = class {
|
|
|
11034
11023
|
* @param data Page data
|
|
11035
11024
|
*/
|
|
11036
11025
|
async __writePage(pageId, data) {
|
|
11037
|
-
const
|
|
11038
|
-
const exists = await tx.exists(pageId);
|
|
11026
|
+
const exists = await this.mvccTx.exists(pageId);
|
|
11039
11027
|
if (exists) {
|
|
11040
11028
|
const copy = new Uint8Array(data.length);
|
|
11041
11029
|
copy.set(data);
|
|
11042
|
-
await
|
|
11030
|
+
await this.mvccTx.write(pageId, copy);
|
|
11043
11031
|
} else {
|
|
11044
|
-
await
|
|
11032
|
+
await this.mvccTx.create(pageId, data);
|
|
11045
11033
|
}
|
|
11046
11034
|
}
|
|
11047
11035
|
/**
|
|
@@ -11069,10 +11057,9 @@ var Transaction = class {
|
|
|
11069
11057
|
await hook();
|
|
11070
11058
|
}
|
|
11071
11059
|
});
|
|
11072
|
-
const tx = this.ensureMvccTx();
|
|
11073
11060
|
let shouldTriggerCheckpoint = false;
|
|
11074
11061
|
await this.pfs.runGlobalLock(async () => {
|
|
11075
|
-
const entries =
|
|
11062
|
+
const entries = this.mvccTx.getResultEntries();
|
|
11076
11063
|
const dirtyPages = /* @__PURE__ */ new Map();
|
|
11077
11064
|
for (const entry of [...entries.created, ...entries.updated]) {
|
|
11078
11065
|
dirtyPages.set(entry.key, entry.data);
|
|
@@ -11082,7 +11069,7 @@ var Transaction = class {
|
|
|
11082
11069
|
await this.pfs.wal.prepareCommit(dirtyPages);
|
|
11083
11070
|
await this.pfs.wal.writeCommitMarker();
|
|
11084
11071
|
}
|
|
11085
|
-
await
|
|
11072
|
+
await this.mvccTx.commit();
|
|
11086
11073
|
if (hasDirtyPages) {
|
|
11087
11074
|
await this.rootTx.commit();
|
|
11088
11075
|
}
|
|
@@ -11396,7 +11383,7 @@ var DataplyAPI = class {
|
|
|
11396
11383
|
if (this.initialized) {
|
|
11397
11384
|
return;
|
|
11398
11385
|
}
|
|
11399
|
-
await this.
|
|
11386
|
+
await this.withReadTransaction(async (tx) => {
|
|
11400
11387
|
await this.hook.trigger("init", tx, async (tx2) => {
|
|
11401
11388
|
await this.pfs.init();
|
|
11402
11389
|
await this.rowTableEngine.init();
|
|
@@ -11421,15 +11408,6 @@ var DataplyAPI = class {
|
|
|
11421
11408
|
this.pfs
|
|
11422
11409
|
);
|
|
11423
11410
|
}
|
|
11424
|
-
/**
|
|
11425
|
-
* Runs a callback function within a transaction context.
|
|
11426
|
-
* If no transaction is provided, a new transaction is created.
|
|
11427
|
-
* The transaction is committed if the callback completes successfully,
|
|
11428
|
-
* or rolled back if an error occurs.
|
|
11429
|
-
* @param callback The callback function to run within the transaction context.
|
|
11430
|
-
* @param tx The transaction to use. If not provided, a new transaction is created.
|
|
11431
|
-
* @returns The result of the callback function.
|
|
11432
|
-
*/
|
|
11433
11411
|
/**
|
|
11434
11412
|
* Acquires the global write lock.
|
|
11435
11413
|
* Returns a release function that MUST be called to unlock.
|
|
@@ -11454,7 +11432,7 @@ var DataplyAPI = class {
|
|
|
11454
11432
|
* @param tx Optional external transaction.
|
|
11455
11433
|
* @returns The result of the callback.
|
|
11456
11434
|
*/
|
|
11457
|
-
async
|
|
11435
|
+
async withWriteTransaction(callback, tx) {
|
|
11458
11436
|
this.logger.debug("Running with default write transaction");
|
|
11459
11437
|
if (!tx) {
|
|
11460
11438
|
const release = await this.acquireWriteLock();
|
|
@@ -11478,7 +11456,7 @@ var DataplyAPI = class {
|
|
|
11478
11456
|
}
|
|
11479
11457
|
return result;
|
|
11480
11458
|
}
|
|
11481
|
-
async
|
|
11459
|
+
async withReadTransaction(callback, tx) {
|
|
11482
11460
|
this.logger.debug("Running with default transaction");
|
|
11483
11461
|
const isInternalTx = !tx;
|
|
11484
11462
|
if (!tx) {
|
|
@@ -11506,7 +11484,7 @@ var DataplyAPI = class {
|
|
|
11506
11484
|
* @param tx The transaction to use. If not provided, a new transaction is created.
|
|
11507
11485
|
* @returns An AsyncGenerator that yields values from the callback.
|
|
11508
11486
|
*/
|
|
11509
|
-
async *
|
|
11487
|
+
async *withReadStreamTransaction(callback, tx) {
|
|
11510
11488
|
this.logger.debug("Streaming with default transaction");
|
|
11511
11489
|
const isInternalTx = !tx;
|
|
11512
11490
|
if (!tx) {
|
|
@@ -11539,7 +11517,7 @@ var DataplyAPI = class {
|
|
|
11539
11517
|
if (!this.initialized) {
|
|
11540
11518
|
throw new Error("Dataply instance is not initialized");
|
|
11541
11519
|
}
|
|
11542
|
-
return this.
|
|
11520
|
+
return this.withReadTransaction((tx2) => this.rowTableEngine.getMetadata(tx2), tx);
|
|
11543
11521
|
}
|
|
11544
11522
|
/**
|
|
11545
11523
|
* Inserts data. Returns the PK of the added row.
|
|
@@ -11553,7 +11531,7 @@ var DataplyAPI = class {
|
|
|
11553
11531
|
if (!this.initialized) {
|
|
11554
11532
|
throw new Error("Dataply instance is not initialized");
|
|
11555
11533
|
}
|
|
11556
|
-
return this.
|
|
11534
|
+
return this.withWriteTransaction(async (tx2) => {
|
|
11557
11535
|
incrementRowCount = incrementRowCount ?? true;
|
|
11558
11536
|
if (typeof data === "string") {
|
|
11559
11537
|
data = this.textCodec.encode(data);
|
|
@@ -11574,7 +11552,7 @@ var DataplyAPI = class {
|
|
|
11574
11552
|
if (!this.initialized) {
|
|
11575
11553
|
throw new Error("Dataply instance is not initialized");
|
|
11576
11554
|
}
|
|
11577
|
-
return this.
|
|
11555
|
+
return this.withWriteTransaction(async (tx2) => {
|
|
11578
11556
|
incrementRowCount = incrementRowCount ?? true;
|
|
11579
11557
|
if (typeof data === "string") {
|
|
11580
11558
|
data = this.textCodec.encode(data);
|
|
@@ -11596,7 +11574,7 @@ var DataplyAPI = class {
|
|
|
11596
11574
|
if (!this.initialized) {
|
|
11597
11575
|
throw new Error("Dataply instance is not initialized");
|
|
11598
11576
|
}
|
|
11599
|
-
return this.
|
|
11577
|
+
return this.withWriteTransaction(async (tx2) => {
|
|
11600
11578
|
incrementRowCount = incrementRowCount ?? true;
|
|
11601
11579
|
const encodedList = dataList.map(
|
|
11602
11580
|
(data) => typeof data === "string" ? this.textCodec.encode(data) : data
|
|
@@ -11615,7 +11593,7 @@ var DataplyAPI = class {
|
|
|
11615
11593
|
if (!this.initialized) {
|
|
11616
11594
|
throw new Error("Dataply instance is not initialized");
|
|
11617
11595
|
}
|
|
11618
|
-
return this.
|
|
11596
|
+
return this.withWriteTransaction(async (tx2) => {
|
|
11619
11597
|
if (typeof data === "string") {
|
|
11620
11598
|
data = this.textCodec.encode(data);
|
|
11621
11599
|
}
|
|
@@ -11633,7 +11611,7 @@ var DataplyAPI = class {
|
|
|
11633
11611
|
if (!this.initialized) {
|
|
11634
11612
|
throw new Error("Dataply instance is not initialized");
|
|
11635
11613
|
}
|
|
11636
|
-
return this.
|
|
11614
|
+
return this.withWriteTransaction(async (tx2) => {
|
|
11637
11615
|
decrementRowCount = decrementRowCount ?? true;
|
|
11638
11616
|
await this.rowTableEngine.delete(pk, decrementRowCount, tx2);
|
|
11639
11617
|
}, tx);
|
|
@@ -11643,7 +11621,7 @@ var DataplyAPI = class {
|
|
|
11643
11621
|
if (!this.initialized) {
|
|
11644
11622
|
throw new Error("Dataply instance is not initialized");
|
|
11645
11623
|
}
|
|
11646
|
-
return this.
|
|
11624
|
+
return this.withReadTransaction(async (tx2) => {
|
|
11647
11625
|
const data = await this.rowTableEngine.selectByPK(pk, tx2);
|
|
11648
11626
|
if (data === null) return null;
|
|
11649
11627
|
if (asRaw) return data;
|
|
@@ -11655,7 +11633,7 @@ var DataplyAPI = class {
|
|
|
11655
11633
|
if (!this.initialized) {
|
|
11656
11634
|
throw new Error("Dataply instance is not initialized");
|
|
11657
11635
|
}
|
|
11658
|
-
return this.
|
|
11636
|
+
return this.withReadTransaction(async (tx2) => {
|
|
11659
11637
|
const results = await this.rowTableEngine.selectMany(pks, tx2);
|
|
11660
11638
|
return results.map((data) => {
|
|
11661
11639
|
if (data === null) return null;
|
|
@@ -11672,7 +11650,7 @@ var DataplyAPI = class {
|
|
|
11672
11650
|
if (!this.initialized) {
|
|
11673
11651
|
throw new Error("Dataply instance is not initialized");
|
|
11674
11652
|
}
|
|
11675
|
-
return this.
|
|
11653
|
+
return this.withWriteTransaction(() => {
|
|
11676
11654
|
return this.hook.trigger("close", void 0, async () => {
|
|
11677
11655
|
await this.pfs.close();
|
|
11678
11656
|
import_node_fs3.default.closeSync(this.fileHandle);
|
|
@@ -11703,6 +11681,24 @@ var Dataply = class {
|
|
|
11703
11681
|
createTransaction() {
|
|
11704
11682
|
return this.api.createTransaction();
|
|
11705
11683
|
}
|
|
11684
|
+
/**
|
|
11685
|
+
* Runs a write callback within a transaction context.
|
|
11686
|
+
*/
|
|
11687
|
+
async withWriteTransaction(callback, tx) {
|
|
11688
|
+
return this.api.withWriteTransaction(callback, tx);
|
|
11689
|
+
}
|
|
11690
|
+
/**
|
|
11691
|
+
* Runs a read callback within a transaction context.
|
|
11692
|
+
*/
|
|
11693
|
+
async withReadTransaction(callback, tx) {
|
|
11694
|
+
return this.api.withReadTransaction(callback, tx);
|
|
11695
|
+
}
|
|
11696
|
+
/**
|
|
11697
|
+
* Runs a generator callback function within a transaction context.
|
|
11698
|
+
*/
|
|
11699
|
+
async *withReadStreamTransaction(callback, tx) {
|
|
11700
|
+
return this.api.withReadStreamTransaction(callback, tx);
|
|
11701
|
+
}
|
|
11706
11702
|
/**
|
|
11707
11703
|
* Initializes the dataply instance.
|
|
11708
11704
|
* Must be called before using the dataply instance.
|
|
@@ -11769,10 +11765,42 @@ var Dataply = class {
|
|
|
11769
11765
|
};
|
|
11770
11766
|
|
|
11771
11767
|
// src/core/transaction/GlobalTransaction.ts
|
|
11772
|
-
var GlobalTransaction = class {
|
|
11768
|
+
var GlobalTransaction = class _GlobalTransaction {
|
|
11773
11769
|
transactions = [];
|
|
11774
11770
|
isCommitted = false;
|
|
11775
11771
|
isRolledBack = false;
|
|
11772
|
+
/**
|
|
11773
|
+
* Executes a global transaction across multiple Dataply instances using a callback.
|
|
11774
|
+
* Locks are acquired in the order instances are provided.
|
|
11775
|
+
* @param dbs Array of Dataply instances
|
|
11776
|
+
* @param callback Function to execute with the array of Transactions
|
|
11777
|
+
*/
|
|
11778
|
+
static async Run(dbs, callback) {
|
|
11779
|
+
const globalTx = new _GlobalTransaction();
|
|
11780
|
+
const txs = [];
|
|
11781
|
+
const releases = [];
|
|
11782
|
+
try {
|
|
11783
|
+
for (const db of dbs) {
|
|
11784
|
+
const release = await db.api.acquireWriteLock();
|
|
11785
|
+
releases.push(release);
|
|
11786
|
+
const tx = db.api.createTransaction();
|
|
11787
|
+
tx.__setWriteLockRelease(release);
|
|
11788
|
+
txs.push(tx);
|
|
11789
|
+
globalTx.add(tx);
|
|
11790
|
+
}
|
|
11791
|
+
const result = await callback(txs);
|
|
11792
|
+
await globalTx.commit();
|
|
11793
|
+
return result;
|
|
11794
|
+
} catch (e) {
|
|
11795
|
+
await globalTx.rollback();
|
|
11796
|
+
for (let i = txs.length; i < releases.length; i++) {
|
|
11797
|
+
releases[i]();
|
|
11798
|
+
}
|
|
11799
|
+
throw e;
|
|
11800
|
+
}
|
|
11801
|
+
}
|
|
11802
|
+
constructor() {
|
|
11803
|
+
}
|
|
11776
11804
|
/**
|
|
11777
11805
|
* Adds a transaction to the global transaction.
|
|
11778
11806
|
* @param tx Transaction to add
|
|
@@ -18,7 +18,19 @@ export declare class Dataply {
|
|
|
18
18
|
* A transaction must be terminated by calling either `commit` or `rollback`.
|
|
19
19
|
* @returns Transaction object
|
|
20
20
|
*/
|
|
21
|
-
createTransaction(): Transaction;
|
|
21
|
+
protected createTransaction(): Transaction;
|
|
22
|
+
/**
|
|
23
|
+
* Runs a write callback within a transaction context.
|
|
24
|
+
*/
|
|
25
|
+
withWriteTransaction<T>(callback: (tx: Transaction) => Promise<T>, tx?: Transaction): Promise<T>;
|
|
26
|
+
/**
|
|
27
|
+
* Runs a read callback within a transaction context.
|
|
28
|
+
*/
|
|
29
|
+
withReadTransaction<T>(callback: (tx: Transaction) => Promise<T>, tx?: Transaction): Promise<T>;
|
|
30
|
+
/**
|
|
31
|
+
* Runs a generator callback function within a transaction context.
|
|
32
|
+
*/
|
|
33
|
+
withReadStreamTransaction<T>(callback: (tx: Transaction) => AsyncGenerator<T>, tx?: Transaction): AsyncGenerator<T>;
|
|
22
34
|
/**
|
|
23
35
|
* Initializes the dataply instance.
|
|
24
36
|
* Must be called before using the dataply instance.
|
|
@@ -89,22 +89,13 @@ export declare class DataplyAPI {
|
|
|
89
89
|
* @returns Transaction object
|
|
90
90
|
*/
|
|
91
91
|
createTransaction(): Transaction;
|
|
92
|
-
/**
|
|
93
|
-
* Runs a callback function within a transaction context.
|
|
94
|
-
* If no transaction is provided, a new transaction is created.
|
|
95
|
-
* The transaction is committed if the callback completes successfully,
|
|
96
|
-
* or rolled back if an error occurs.
|
|
97
|
-
* @param callback The callback function to run within the transaction context.
|
|
98
|
-
* @param tx The transaction to use. If not provided, a new transaction is created.
|
|
99
|
-
* @returns The result of the callback function.
|
|
100
|
-
*/
|
|
101
92
|
/**
|
|
102
93
|
* Acquires the global write lock.
|
|
103
94
|
* Returns a release function that MUST be called to unlock.
|
|
104
95
|
* Used internally by runWithDefaultWrite.
|
|
105
96
|
* @returns A release function
|
|
106
97
|
*/
|
|
107
|
-
|
|
98
|
+
acquireWriteLock(): Promise<() => void>;
|
|
108
99
|
/**
|
|
109
100
|
* Runs a write callback within a transaction context with global write serialization.
|
|
110
101
|
* If no transaction is provided, a new transaction is created, committed on success, rolled back on error.
|
|
@@ -114,8 +105,8 @@ export declare class DataplyAPI {
|
|
|
114
105
|
* @param tx Optional external transaction.
|
|
115
106
|
* @returns The result of the callback.
|
|
116
107
|
*/
|
|
117
|
-
|
|
118
|
-
|
|
108
|
+
withWriteTransaction<T>(callback: (tx: Transaction) => Promise<T>, tx?: Transaction): Promise<T>;
|
|
109
|
+
withReadTransaction<T>(callback: (tx: Transaction) => Promise<T>, tx?: Transaction): Promise<T>;
|
|
119
110
|
/**
|
|
120
111
|
* Runs a generator callback function within a transaction context.
|
|
121
112
|
* Similar to runWithDefault but allows yielding values from an AsyncGenerator.
|
|
@@ -126,7 +117,7 @@ export declare class DataplyAPI {
|
|
|
126
117
|
* @param tx The transaction to use. If not provided, a new transaction is created.
|
|
127
118
|
* @returns An AsyncGenerator that yields values from the callback.
|
|
128
119
|
*/
|
|
129
|
-
|
|
120
|
+
withReadStreamTransaction<T>(callback: (tx: Transaction) => AsyncGenerator<T>, tx?: Transaction): AsyncGenerator<T>;
|
|
130
121
|
/**
|
|
131
122
|
* Retrieves metadata from the dataply.
|
|
132
123
|
* @returns Metadata of the dataply.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Transaction } from './Transaction';
|
|
2
|
+
import { Dataply } from '../Dataply';
|
|
2
3
|
/**
|
|
3
4
|
* Global Transaction Manager.
|
|
4
5
|
* Coordinates transactions across multiple instances (shards).
|
|
@@ -9,19 +10,27 @@ export declare class GlobalTransaction {
|
|
|
9
10
|
private transactions;
|
|
10
11
|
private isCommitted;
|
|
11
12
|
private isRolledBack;
|
|
13
|
+
/**
|
|
14
|
+
* Executes a global transaction across multiple Dataply instances using a callback.
|
|
15
|
+
* Locks are acquired in the order instances are provided.
|
|
16
|
+
* @param dbs Array of Dataply instances
|
|
17
|
+
* @param callback Function to execute with the array of Transactions
|
|
18
|
+
*/
|
|
19
|
+
static Run<T>(dbs: Dataply[], callback: (txs: Transaction[]) => Promise<T>): Promise<T>;
|
|
20
|
+
protected constructor();
|
|
12
21
|
/**
|
|
13
22
|
* Adds a transaction to the global transaction.
|
|
14
23
|
* @param tx Transaction to add
|
|
15
24
|
*/
|
|
16
|
-
add(tx: Transaction): void;
|
|
25
|
+
protected add(tx: Transaction): void;
|
|
17
26
|
/**
|
|
18
27
|
* Commits all transactions.
|
|
19
28
|
* Note: This is now a single-phase commit. For true atomicity across shards,
|
|
20
29
|
* each instance's WAL provides durability, but cross-shard atomicity is best-effort.
|
|
21
30
|
*/
|
|
22
|
-
commit(): Promise<void>;
|
|
31
|
+
protected commit(): Promise<void>;
|
|
23
32
|
/**
|
|
24
33
|
* Rolls back all transactions.
|
|
25
34
|
*/
|
|
26
|
-
rollback(): Promise<void>;
|
|
35
|
+
protected rollback(): Promise<void>;
|
|
27
36
|
}
|
|
@@ -21,7 +21,7 @@ export declare class Transaction {
|
|
|
21
21
|
/** List of callbacks to execute on commit */
|
|
22
22
|
private commitHooks;
|
|
23
23
|
/** Nested MVCC Transaction for snapshot isolation (lazy init) */
|
|
24
|
-
private mvccTx;
|
|
24
|
+
private readonly mvccTx;
|
|
25
25
|
/** Root MVCC Transaction reference */
|
|
26
26
|
private readonly rootTx;
|
|
27
27
|
/** Release function for global write lock, set by DataplyAPI */
|
|
@@ -34,12 +34,6 @@ export declare class Transaction {
|
|
|
34
34
|
* @param pfs Page File System
|
|
35
35
|
*/
|
|
36
36
|
constructor(id: number, context: TransactionContext, rootTx: AsyncMVCCTransaction<PageMVCCStrategy, number, Uint8Array>, lockManager: LockManager, pfs: PageFileSystem);
|
|
37
|
-
/**
|
|
38
|
-
* Lazily initializes the nested MVCC transaction.
|
|
39
|
-
* This ensures the snapshot is taken at the time of first access,
|
|
40
|
-
* picking up the latest committed root version.
|
|
41
|
-
*/
|
|
42
|
-
private ensureMvccTx;
|
|
43
37
|
/**
|
|
44
38
|
* Registers a commit hook.
|
|
45
39
|
* @param hook Function to execute
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dataply",
|
|
3
|
-
"version": "0.0.26-alpha.
|
|
3
|
+
"version": "0.0.26-alpha.8",
|
|
4
4
|
"description": "A lightweight storage engine for Node.js with support for MVCC, WAL.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "izure <admin@izure.org>",
|
|
@@ -51,4 +51,4 @@
|
|
|
51
51
|
"ryoiki": "^1.2.0",
|
|
52
52
|
"serializable-bptree": "^9.0.1"
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
}
|
package/readme.md
CHANGED
|
@@ -105,23 +105,17 @@ db.init().then(() => {
|
|
|
105
105
|
## Transaction Management
|
|
106
106
|
|
|
107
107
|
### Explicit Transactions
|
|
108
|
-
You can group multiple operations into a single unit of work to ensure atomicity.
|
|
108
|
+
You can group multiple operations into a single unit of work to ensure atomicity. The `withWriteTransaction` method handles the transaction lifecycle automatically, committing on success and rolling back on failure.
|
|
109
109
|
|
|
110
110
|
```typescript
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
await dataply.insert('Data 1', tx)
|
|
111
|
+
await dataply.withWriteTransaction(async (tx) => {
|
|
112
|
+
const pk = await dataply.insert('Data 1', tx)
|
|
115
113
|
await dataply.update(pk, 'Updated Data', tx)
|
|
116
|
-
|
|
117
|
-
await tx.commit() // Persist changes to disk and clear WAL on success
|
|
118
|
-
} catch (error) {
|
|
119
|
-
await tx.rollback() // Revert all changes on failure (Undo)
|
|
120
|
-
}
|
|
114
|
+
}) // Persists changes automatically on success or rolls back on failure
|
|
121
115
|
```
|
|
122
116
|
|
|
123
117
|
### Global Transactions
|
|
124
|
-
You can perform atomic operations across multiple `Dataply` instances using the `GlobalTransaction` class. This
|
|
118
|
+
You can perform atomic operations across multiple `Dataply` instances using the `GlobalTransaction` class. This safely acquires write locks on all instances sequentially and manages the transaction lifecycle to ensure either all instances commit successfully or all are rolled back.
|
|
125
119
|
|
|
126
120
|
```typescript
|
|
127
121
|
import { Dataply, GlobalTransaction } from 'dataply'
|
|
@@ -132,22 +126,13 @@ const db2 = new Dataply('./db2.db', { wal: './db2.wal' })
|
|
|
132
126
|
await db1.init()
|
|
133
127
|
await db2.init()
|
|
134
128
|
|
|
135
|
-
const tx1 = db1.createTransaction()
|
|
136
|
-
const tx2 = db2.createTransaction()
|
|
137
|
-
|
|
138
|
-
const globalTx = new GlobalTransaction()
|
|
139
|
-
globalTx.add(tx1)
|
|
140
|
-
globalTx.add(tx2)
|
|
141
|
-
|
|
142
129
|
try {
|
|
143
|
-
await
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
// Note: This is a best-effort atomic commit.
|
|
148
|
-
await globalTx.commit()
|
|
130
|
+
await GlobalTransaction.Run([db1, db2], async ([tx1, tx2]) => {
|
|
131
|
+
await db1.insert('Data for DB1', tx1)
|
|
132
|
+
await db2.insert('Data for DB2', tx2)
|
|
133
|
+
})
|
|
149
134
|
} catch (error) {
|
|
150
|
-
|
|
135
|
+
console.error('Global transaction failed and rolled back.', error)
|
|
151
136
|
}
|
|
152
137
|
```
|
|
153
138
|
|
|
@@ -196,30 +181,22 @@ Marks data as deleted.
|
|
|
196
181
|
#### `async getMetadata(tx?: Transaction): Promise<DataplyMetadata>`
|
|
197
182
|
Returns the current metadata of the dataply, including `pageSize`, `pageCount`, and `rowCount`.
|
|
198
183
|
|
|
199
|
-
#### `
|
|
200
|
-
|
|
184
|
+
#### `async withWriteTransaction<T>(callback: (tx: Transaction) => Promise<T>, tx?: Transaction): Promise<T>`
|
|
185
|
+
Executes write operations within a serialized write-lock transaction. Automatically commits on success and rolls back on failure if creating a new internal transaction.
|
|
201
186
|
|
|
202
|
-
#### `async
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
### Transaction Class
|
|
187
|
+
#### `async withReadTransaction<T>(callback: (tx: Transaction) => Promise<T>, tx?: Transaction): Promise<T>`
|
|
188
|
+
Executes read operations within a transaction context.
|
|
206
189
|
|
|
207
|
-
#### `async
|
|
208
|
-
|
|
190
|
+
#### `async *withReadStreamTransaction<T>(callback: (tx: Transaction) => AsyncGenerator<T>, tx?: Transaction): AsyncGenerator<T>`
|
|
191
|
+
Executes streaming read operations using an async generator in a transaction.
|
|
209
192
|
|
|
210
|
-
#### `async
|
|
211
|
-
|
|
193
|
+
#### `async close(): Promise<void>`
|
|
194
|
+
Closes the file handles and shuts down safely.
|
|
212
195
|
|
|
213
196
|
### GlobalTransaction Class
|
|
214
197
|
|
|
215
|
-
#### `
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
#### `async commit(): Promise<void>`
|
|
219
|
-
Executes a coordinated commit across all registered transactions. Note that without a prepare phase, this is a best-effort atomic commit.
|
|
220
|
-
|
|
221
|
-
#### `async rollback(): Promise<void>`
|
|
222
|
-
Rolls back all registered transactions simultaneously.
|
|
198
|
+
#### `static async Run<T>(dbs: Dataply[], callback: (txs: Transaction[]) => Promise<T>): Promise<T>`
|
|
199
|
+
Executes a callback-based global transaction across multiple Dataply instances sequentially locking them to prevent deadlocks, providing true atomicity within the Dataply nodes. Automatically commits on success and rolls back on failure.
|
|
223
200
|
|
|
224
201
|
## Extending Dataply
|
|
225
202
|
|