From c0b6a030fd3ab9bfe31e411d8a46e7f82a424fa5 Mon Sep 17 00:00:00 2001 From: Kris Zyp Date: Tue, 30 Jan 2024 06:32:04 -0700 Subject: [PATCH] Add method to get current transaction id, #267 --- README.md | 5 +++++ index.d.ts | 7 +++++++ src/env.cpp | 13 +++++++++++++ src/lmdb-js.h | 1 + test/index.test.js | 3 +++ write.js | 3 +++ 6 files changed, 32 insertions(+) diff --git a/README.md b/README.md index a4093dea8..75152e9d5 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,11 @@ This will run the provided callback in a transaction much like `transaction` exc The `childTransaction` function can be executed on its own (to run the child transaction inside the next queued transaction), or it can be executed inside another transaction callback, executing the child transaction within the current transaction. +### `db.getWriteTxnId(): number` +Returns the transaction id of the currently executing transaction. This is an integer that increments with each +transaction. This is only available inside transaction callbacks (for transactionSync or asynchronous transaction), +and does not provide access transaction ids for asynchronous put/delete methods (the `aftercommit` method can be +used for that). ### `db.committed: Promise` This is a promise-like object that resolves when all previous writes have been committed. diff --git a/index.d.ts b/index.d.ts index d1ba67742..301fbce1c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -187,6 +187,13 @@ declare namespace lmdb { * @param action The function to execute within the transaction **/ childTransaction(action: () => T): Promise + /** + * Returns the transaction id of the currently executing transaction. This is an integer that increments with each + * transaction. This is only available inside transaction callbacks (for transactionSync or asynchronous transaction), + * and does not provide access transaction ids for asynchronous put/delete methods (the 'aftercommit' method can be + * used for that). + */ + getWriteTxnId(): number /** * Returns the current transaction and marks it as in use. This can then be explicitly used for read operations * @returns The transaction object diff --git a/src/env.cpp b/src/env.cpp index 3d5a09a5b..80e45b818 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -970,6 +970,18 @@ Napi::Value EnvWrap::abortTxn(const CallbackInfo& info) { delete currentTxn; return info.Env().Undefined(); } +Napi::Value EnvWrap::getWriteTxnId(const Napi::CallbackInfo& info) { + TxnTracked *currentTxn = this->writeTxn; + size_t txn_id; + if (currentTxn) { + txn_id = mdb_txn_id(currentTxn->txn); + } else if (this->writeWorker) { + txn_id = mdb_txn_id(this->writeWorker->txn); + } else return throwError(info.Env(), "There is no active write transaction."); + return Number::New(info.Env(), txn_id); +} + + /*Napi::Value EnvWrap::openDbi(const CallbackInfo& info) { @@ -1171,6 +1183,7 @@ void EnvWrap::setupExports(Napi::Env env, Object exports) { EnvWrap::InstanceMethod("beginTxn", &EnvWrap::beginTxn), EnvWrap::InstanceMethod("commitTxn", &EnvWrap::commitTxn), EnvWrap::InstanceMethod("abortTxn", &EnvWrap::abortTxn), + EnvWrap::InstanceMethod("getWriteTxnId", &EnvWrap::getWriteTxnId), EnvWrap::InstanceMethod("sync", &EnvWrap::sync), EnvWrap::InstanceMethod("resumeWriting", &EnvWrap::resumeWriting), EnvWrap::InstanceMethod("startWriting", &EnvWrap::startWriting), diff --git a/src/lmdb-js.h b/src/lmdb-js.h index 1d05a00b7..37cc35767 100644 --- a/src/lmdb-js.h +++ b/src/lmdb-js.h @@ -426,6 +426,7 @@ class EnvWrap : public ObjectWrap { Napi::Value beginTxn(const CallbackInfo& info); Napi::Value commitTxn(const CallbackInfo& info); Napi::Value abortTxn(const CallbackInfo& info); + Napi::Value getWriteTxnId(const CallbackInfo& info); /* Flushes all data to the disk asynchronously. diff --git a/test/index.test.js b/test/index.test.js index 29f20d6ff..f2ac8669b 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -946,6 +946,7 @@ describe('lmdb-js', function () { } db2.put('key2-async', 'async test 2'); should.equal(db2.get('key2-async'), 'async test 2'); + expect(db.getWriteTxnId()).gte(1); }); should.equal(db.get('key1'), 'async test 1'); should.equal(db2.get('key2-async'), 'async test 2'); @@ -1152,9 +1153,11 @@ describe('lmdb-js', function () { db.childTransaction(() => { iterator = db.getRange({ start: 'c1' })[Symbol.iterator](); should.equal(iterator.next().value.value, 'value1'); + expect(db.getWriteTxnId()).gte(1); }); } should.equal(iterator.next().value.value, 'value2'); + expect(db.getWriteTxnId()).gte(1); }); should.equal(iterator.next().value.value, 'value3'); }); diff --git a/write.js b/write.js index 1cf2232b3..2505a2b8a 100644 --- a/write.js +++ b/write.js @@ -840,6 +840,9 @@ export function addWriteMethods(LMDBStore, { env, fixedBuffer, resetReadTxn, use throw error; } }, + getWriteTxnId() { + return env.getWriteTxnId(); + }, transactionSyncStart(callback) { return this.transactionSync(callback, 0); },