@harperfast/rocksdb-js 2.1.0 → 2.3.0
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 +292 -12
- package/bin/rocksdb-js.mjs +290 -2
- package/dist/index.cjs +257 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +355 -14
- package/dist/index.d.mts +355 -14
- package/dist/index.mjs +257 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -16
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
|
-
import { closeSync, openSync, readFileSync, readSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, statSync } from "node:fs";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { mkdir } from "node:fs/promises";
|
|
6
7
|
import * as orderedBinary from "ordered-binary";
|
|
7
8
|
import { ExtendedIterable } from "@harperfast/extended-iterable";
|
|
8
9
|
import { Encoder } from "msgpackr";
|
|
@@ -55,6 +56,7 @@ function locateBinding() {
|
|
|
55
56
|
}
|
|
56
57
|
const binding = req(locateBinding());
|
|
57
58
|
const config = binding.config;
|
|
59
|
+
const FRESH_VERSION_FLAG$1 = binding.constants.FRESH_VERSION_FLAG;
|
|
58
60
|
const addGlobalListener = binding.addListener;
|
|
59
61
|
const removeGlobalListener = binding.removeListener;
|
|
60
62
|
const globalListenerCount = binding.listenerCount;
|
|
@@ -67,9 +69,95 @@ const TransactionLog = binding.TransactionLog;
|
|
|
67
69
|
const registryStatus = binding.registryStatus;
|
|
68
70
|
const shutdown = binding.shutdown;
|
|
69
71
|
const currentThreadId = binding.currentThreadId;
|
|
72
|
+
/**
|
|
73
|
+
* Advises the kernel that the file-backed pages of every mapped transaction log
|
|
74
|
+
* are cold (Linux MADV_COLD), so they are reclaimed first under memory pressure
|
|
75
|
+
* without being freed — useful during replication catch-up, where a full read of
|
|
76
|
+
* the logs would otherwise inflate the container's reclaimable cache toward its
|
|
77
|
+
* cgroup limit. No-op on kernels < 5.4, macOS, and Windows.
|
|
78
|
+
*
|
|
79
|
+
* The transaction log registry is a process-global singleton shared across all
|
|
80
|
+
* worker threads, so a single call cools every worker's maps. Call it on an
|
|
81
|
+
* interval from one thread (e.g. an `unref()`ed timer on the main thread).
|
|
82
|
+
*
|
|
83
|
+
* @returns the number of maps cooled and total file-backed bytes advised.
|
|
84
|
+
*/
|
|
85
|
+
const coolTransactionLogs = binding.coolTransactionLogs;
|
|
86
|
+
/**
|
|
87
|
+
* Number of live transaction-log memory maps across the process. Internal —
|
|
88
|
+
* used by tests to verify that releasing a frozen log's external buffer unmaps
|
|
89
|
+
* the underlying mapping rather than leaving it retained.
|
|
90
|
+
*/
|
|
91
|
+
const transactionLogMapCount = binding.transactionLogMapCount;
|
|
92
|
+
const nativeBackupRestore = binding.backupRestore;
|
|
93
|
+
const nativeBackupList = binding.backupList;
|
|
94
|
+
const nativeBackupDelete = binding.backupDelete;
|
|
95
|
+
const nativeBackupPurge = binding.backupPurge;
|
|
96
|
+
const nativeBackupVerify = binding.backupVerify;
|
|
70
97
|
const stats = binding.stats;
|
|
71
98
|
const version = binding.version;
|
|
72
99
|
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/backup.ts
|
|
102
|
+
/**
|
|
103
|
+
* Backup management operations that act on a backup directory and do not
|
|
104
|
+
* require an open database. To create a backup, use the `db.backup()` instance
|
|
105
|
+
* method instead (it needs a live database for a consistent snapshot).
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* import { backups } from '@harperfast/rocksdb-js';
|
|
110
|
+
*
|
|
111
|
+
* const id = await db.backup('/path/to/backups');
|
|
112
|
+
* db.close();
|
|
113
|
+
* await backups.restore('/path/to/backups', '/path/to/restored-db');
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
const backups = {
|
|
117
|
+
/**
|
|
118
|
+
* Restores a database from a backup directory into a (closed) database
|
|
119
|
+
* directory. The default mode purges the destination directory, so it must
|
|
120
|
+
* not point at a live database.
|
|
121
|
+
*/
|
|
122
|
+
async restore(backupDir, dbDir, options) {
|
|
123
|
+
if (resolve(backupDir) === resolve(dbDir)) throw new Error("Backup directory and database directory must be different");
|
|
124
|
+
const walDir = options?.walDir ?? dbDir;
|
|
125
|
+
await mkdir(dbDir, { recursive: true });
|
|
126
|
+
if (walDir !== dbDir) await mkdir(walDir, { recursive: true });
|
|
127
|
+
return new Promise((resolve, reject) => nativeBackupRestore(resolve, reject, backupDir, dbDir, walDir, {
|
|
128
|
+
backupId: options?.backupId,
|
|
129
|
+
keepLogFiles: options?.keepLogFiles,
|
|
130
|
+
mode: options?.mode
|
|
131
|
+
}));
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Lists the non-corrupt backups in a backup directory, ordered by id.
|
|
135
|
+
*/
|
|
136
|
+
list(backupDir) {
|
|
137
|
+
return new Promise((resolve, reject) => nativeBackupList(resolve, reject, backupDir));
|
|
138
|
+
},
|
|
139
|
+
/**
|
|
140
|
+
* Deletes a specific backup. Shared files are reference-counted and only
|
|
141
|
+
* removed once no remaining backup references them.
|
|
142
|
+
*/
|
|
143
|
+
delete(backupDir, backupId) {
|
|
144
|
+
return new Promise((resolve, reject) => nativeBackupDelete(resolve, reject, backupDir, backupId));
|
|
145
|
+
},
|
|
146
|
+
/**
|
|
147
|
+
* Deletes all but the newest `keepCount` backups.
|
|
148
|
+
*/
|
|
149
|
+
purge(backupDir, keepCount) {
|
|
150
|
+
return new Promise((resolve, reject) => nativeBackupPurge(resolve, reject, backupDir, keepCount));
|
|
151
|
+
},
|
|
152
|
+
/**
|
|
153
|
+
* Verifies a backup's file sizes, and optionally their checksums (which
|
|
154
|
+
* requires reading all backed-up data).
|
|
155
|
+
*/
|
|
156
|
+
verify(backupDir, backupId, options) {
|
|
157
|
+
return new Promise((resolve, reject) => nativeBackupVerify(resolve, reject, backupDir, backupId, options?.verifyWithChecksum ?? false));
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
73
161
|
//#endregion
|
|
74
162
|
//#region src/util.ts
|
|
75
163
|
/**
|
|
@@ -188,11 +276,11 @@ var DBI = class DBI {
|
|
|
188
276
|
*/
|
|
189
277
|
get(key, options) {
|
|
190
278
|
if (this.store.decoderCopies) return when(() => this.getBinaryFast(key, options), (result) => {
|
|
191
|
-
if (result === void 0) return;
|
|
279
|
+
if (result === void 0 || result === FRESH_VERSION_FLAG$1) return result;
|
|
192
280
|
if (options?.skipDecode) return result;
|
|
193
281
|
return this.store.decodeValue(result);
|
|
194
282
|
});
|
|
195
|
-
return when(() => this.getBinary(key, options), (result) => result === void 0 ?
|
|
283
|
+
return when(() => this.getBinary(key, options), (result) => result === void 0 || result === FRESH_VERSION_FLAG$1 ? result : this.store.encoding === "binary" || !this.store.decoder || options?.skipDecode ? result : this.store.decodeValue(result));
|
|
196
284
|
}
|
|
197
285
|
/**
|
|
198
286
|
* Retrieves the binary data for the given key. This is just like `get()`,
|
|
@@ -202,7 +290,7 @@ var DBI = class DBI {
|
|
|
202
290
|
*/
|
|
203
291
|
getBinary(key, options) {
|
|
204
292
|
if (!this.store.isOpen()) return Promise.reject(/* @__PURE__ */ new Error("Database not open"));
|
|
205
|
-
return this.store.get(this._context, key, true,
|
|
293
|
+
return this.store.get(this._context, key, true, options);
|
|
206
294
|
}
|
|
207
295
|
/**
|
|
208
296
|
* Synchronously retrieves the binary data for the given key.
|
|
@@ -223,7 +311,7 @@ var DBI = class DBI {
|
|
|
223
311
|
*/
|
|
224
312
|
getBinaryFast(key, options) {
|
|
225
313
|
if (!this.store.isOpen()) return Promise.reject(/* @__PURE__ */ new Error("Database not open"));
|
|
226
|
-
return this.store.get(this._context, key, false,
|
|
314
|
+
return this.store.get(this._context, key, false, options);
|
|
227
315
|
}
|
|
228
316
|
/**
|
|
229
317
|
* Synchronously retrieves the binary data for the given key using a
|
|
@@ -282,12 +370,12 @@ var DBI = class DBI {
|
|
|
282
370
|
getSync(key, options) {
|
|
283
371
|
if (this.store.decoderCopies) {
|
|
284
372
|
const bytes = this.getBinaryFastSync(key, options);
|
|
285
|
-
return bytes === void 0 ?
|
|
373
|
+
return bytes === void 0 || bytes === FRESH_VERSION_FLAG$1 ? bytes : this.store.decodeValue(bytes);
|
|
286
374
|
}
|
|
287
375
|
if (this.store.encoding === "binary") return this.getBinarySync(key, options);
|
|
288
376
|
if (this.store.decoder) {
|
|
289
377
|
const result = this.getBinarySync(key, options);
|
|
290
|
-
return result ? this.store.decodeValue(result)
|
|
378
|
+
return !result || result === FRESH_VERSION_FLAG$1 ? result : this.store.decodeValue(result);
|
|
291
379
|
}
|
|
292
380
|
if (!this.store.isOpen()) throw new Error("Database not open");
|
|
293
381
|
return this.store.decodeValue(this.store.getSync(this._context, key, true, options));
|
|
@@ -450,17 +538,25 @@ var DBIterator = class {
|
|
|
450
538
|
iterator;
|
|
451
539
|
store;
|
|
452
540
|
#includeValues;
|
|
453
|
-
|
|
541
|
+
#limit;
|
|
542
|
+
#yielded = 0;
|
|
543
|
+
constructor(iterator, store, includeValues, limit) {
|
|
454
544
|
this.iterator = iterator;
|
|
455
545
|
this.store = store;
|
|
456
546
|
this.#includeValues = includeValues;
|
|
547
|
+
this.#limit = limit ?? void 0;
|
|
457
548
|
}
|
|
458
549
|
[Symbol.iterator]() {
|
|
459
550
|
return this;
|
|
460
551
|
}
|
|
461
552
|
next() {
|
|
553
|
+
if (this.#limit !== void 0 && this.#yielded >= this.#limit) {
|
|
554
|
+
this.iterator.return?.();
|
|
555
|
+
return DONE_RESULT;
|
|
556
|
+
}
|
|
462
557
|
const result = this.iterator.next();
|
|
463
558
|
if (result === ITERATOR_RESULT_DONE) return DONE_RESULT;
|
|
559
|
+
this.#yielded++;
|
|
464
560
|
const includeValues = this.#includeValues;
|
|
465
561
|
const value = {};
|
|
466
562
|
if (result === ITERATOR_RESULT_FAST) {
|
|
@@ -562,7 +658,7 @@ function createFixedBuffer(size) {
|
|
|
562
658
|
|
|
563
659
|
//#endregion
|
|
564
660
|
//#region src/store.ts
|
|
565
|
-
const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG } = constants;
|
|
661
|
+
const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, FRESH_VERSION_FLAG, POPULATE_VERSION_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG } = constants;
|
|
566
662
|
const KEY_BUFFER_SIZE = 4096;
|
|
567
663
|
const KEY_BUFFER = createFixedBuffer(KEY_BUFFER_SIZE);
|
|
568
664
|
const VALUE_BUFFER = createFixedBuffer(64 * 1024);
|
|
@@ -721,6 +817,10 @@ var Store = class {
|
|
|
721
817
|
*/
|
|
722
818
|
transactionLogsPath;
|
|
723
819
|
/**
|
|
820
|
+
* Whether this store's column family participates in the VerificationTable.
|
|
821
|
+
*/
|
|
822
|
+
verificationTable;
|
|
823
|
+
/**
|
|
724
824
|
* The per-column-family memtable size in bytes at which the memtable is
|
|
725
825
|
* sealed and flushed.
|
|
726
826
|
*/
|
|
@@ -767,6 +867,7 @@ var Store = class {
|
|
|
767
867
|
this.transactionLogMaxSize = options?.transactionLogMaxSize;
|
|
768
868
|
this.transactionLogRetention = options?.transactionLogRetention;
|
|
769
869
|
this.transactionLogsPath = options?.transactionLogsPath;
|
|
870
|
+
this.verificationTable = options?.verificationTable;
|
|
770
871
|
this.writeBufferSize = options?.writeBufferSize;
|
|
771
872
|
this.writeKey = writeKey;
|
|
772
873
|
}
|
|
@@ -800,6 +901,20 @@ var Store = class {
|
|
|
800
901
|
return new Promise((resolve, reject) => this.db.compact(resolve, reject, startBuffer, endBuffer));
|
|
801
902
|
}
|
|
802
903
|
/**
|
|
904
|
+
* Creates a backup of the entire database (all column families) into the
|
|
905
|
+
* given directory and resolves with the new backup id. Parent directories
|
|
906
|
+
* are created as needed. See `backups` for restore and management.
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* ```typescript
|
|
910
|
+
* const id = await db.backup('/path/to/backups');
|
|
911
|
+
* ```
|
|
912
|
+
*/
|
|
913
|
+
async backup(backupDir, options) {
|
|
914
|
+
await mkdir(backupDir, { recursive: true });
|
|
915
|
+
return new Promise((resolve, reject) => this.db.backup(resolve, reject, backupDir, options));
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
803
918
|
* Compacts the entire key range of the database synchronously.
|
|
804
919
|
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
805
920
|
*
|
|
@@ -872,16 +987,19 @@ var Store = class {
|
|
|
872
987
|
if (value instanceof Uint8Array) return value;
|
|
873
988
|
throw new Error(`Invalid value put in database (${typeof value}), consider using an encoder`);
|
|
874
989
|
}
|
|
875
|
-
get(context, key, alwaysCreateNewBuffer = false,
|
|
990
|
+
get(context, key, alwaysCreateNewBuffer = false, options) {
|
|
876
991
|
const keyParam = getKeyParam(this.encodeKey(key));
|
|
877
992
|
let flags = 0;
|
|
878
993
|
if (alwaysCreateNewBuffer) flags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;
|
|
879
|
-
if (
|
|
880
|
-
const
|
|
994
|
+
if (options?.populateVersion) flags |= POPULATE_VERSION_FLAG;
|
|
995
|
+
const txnId = this.getTxnId(options);
|
|
996
|
+
const expectedVersion = options?.expectedVersion;
|
|
997
|
+
const result = context.getSync(keyParam, flags | ONLY_IF_IN_MEMORY_CACHE_FLAG, txnId, expectedVersion);
|
|
881
998
|
if (typeof result === "number") {
|
|
882
999
|
if (result === NOT_IN_MEMORY_CACHE_FLAG) return new Promise((resolve, reject) => {
|
|
883
|
-
context.get(keyParam, resolve, reject, txnId);
|
|
1000
|
+
context.get(keyParam, resolve, reject, txnId, expectedVersion);
|
|
884
1001
|
});
|
|
1002
|
+
if (result === FRESH_VERSION_FLAG) return result;
|
|
885
1003
|
VALUE_BUFFER.end = result;
|
|
886
1004
|
return VALUE_BUFFER;
|
|
887
1005
|
}
|
|
@@ -948,14 +1066,16 @@ var Store = class {
|
|
|
948
1066
|
if (includeValues && !this.decoderCopies) flags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;
|
|
949
1067
|
if (context !== this.db) flags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;
|
|
950
1068
|
const advancedOptions = options !== void 0 && (options.adaptiveReadahead !== void 0 || options.asyncIO !== void 0 || options.autoReadaheadSize !== void 0 || options.backgroundPurgeOnIteratorCleanup !== void 0 || options.fillCache !== void 0 || options.readaheadSize !== void 0 || options.tailing !== void 0) ? options : void 0;
|
|
951
|
-
return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues));
|
|
1069
|
+
return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues, options?.limit));
|
|
952
1070
|
}
|
|
953
1071
|
getSync(context, key, alwaysCreateNewBuffer = false, options) {
|
|
954
1072
|
const keyParam = getKeyParam(this.encodeKey(key));
|
|
955
1073
|
let flags = 0;
|
|
956
1074
|
if (alwaysCreateNewBuffer) flags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;
|
|
957
|
-
|
|
1075
|
+
if (options?.populateVersion) flags |= POPULATE_VERSION_FLAG;
|
|
1076
|
+
const result = context.getSync(keyParam, flags, this.getTxnId(options), options?.expectedVersion);
|
|
958
1077
|
if (typeof result === "number") {
|
|
1078
|
+
if (result === FRESH_VERSION_FLAG) return result;
|
|
959
1079
|
VALUE_BUFFER.end = result;
|
|
960
1080
|
return VALUE_BUFFER;
|
|
961
1081
|
}
|
|
@@ -1044,6 +1164,7 @@ var Store = class {
|
|
|
1044
1164
|
transactionLogMaxSize: this.transactionLogMaxSize,
|
|
1045
1165
|
transactionLogRetentionMs: this.transactionLogRetention ? parseDuration(this.transactionLogRetention) : void 0,
|
|
1046
1166
|
transactionLogsPath: this.transactionLogsPath,
|
|
1167
|
+
verificationTable: this.verificationTable,
|
|
1047
1168
|
writeBufferSize: this.writeBufferSize
|
|
1048
1169
|
});
|
|
1049
1170
|
return false;
|
|
@@ -1093,6 +1214,25 @@ var Store = class {
|
|
|
1093
1214
|
return context.useLog(String(name));
|
|
1094
1215
|
}
|
|
1095
1216
|
/**
|
|
1217
|
+
* Checks the process-global verification table for a fresh version match
|
|
1218
|
+
* on `key`. Returns `true` when the table currently records `version` for
|
|
1219
|
+
* this database+column-family. Provides a fast cache-freshness check
|
|
1220
|
+
* before falling back to a full read.
|
|
1221
|
+
*/
|
|
1222
|
+
verifyVersion(key, version) {
|
|
1223
|
+
const keyParam = getKeyParam(this.encodeKey(key));
|
|
1224
|
+
return this.db.verifyVersion(keyParam, version);
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Seeds the verification-table slot for `key` with `version`. Has no
|
|
1228
|
+
* effect if the slot is currently lock-tagged or the table is disabled.
|
|
1229
|
+
* Useful after a full read where the caller already knows the version.
|
|
1230
|
+
*/
|
|
1231
|
+
populateVersion(key, version) {
|
|
1232
|
+
const keyParam = getKeyParam(this.encodeKey(key));
|
|
1233
|
+
this.db.populateVersion(keyParam, version);
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1096
1236
|
* Acquires a lock on the given key and calls the callback.
|
|
1097
1237
|
*
|
|
1098
1238
|
* @param key - The key to lock.
|
|
@@ -1120,6 +1260,13 @@ function getKeyParam(keyBuffer) {
|
|
|
1120
1260
|
|
|
1121
1261
|
//#endregion
|
|
1122
1262
|
//#region src/transaction.ts
|
|
1263
|
+
/**
|
|
1264
|
+
* Sentinel value returned by `commit()` when `coordinatedRetry: true` and the
|
|
1265
|
+
* transaction encountered an IsBusy conflict. The native layer parks on VT
|
|
1266
|
+
* slots and resolves only after the conflicting transaction releases its write
|
|
1267
|
+
* intent, so callers should retry immediately without any backoff delay.
|
|
1268
|
+
*/
|
|
1269
|
+
const RETRY_NOW = constants.RETRY_NOW_VALUE;
|
|
1123
1270
|
var TransactionAlreadyAbortedError = class extends Error {
|
|
1124
1271
|
code = "ERR_ALREADY_ABORTED";
|
|
1125
1272
|
};
|
|
@@ -1180,13 +1327,16 @@ var Transaction = class extends DBI {
|
|
|
1180
1327
|
}
|
|
1181
1328
|
/**
|
|
1182
1329
|
* Commit the transaction.
|
|
1330
|
+
*
|
|
1331
|
+
* Returns `RETRY_NOW` when `coordinatedRetry: true` and an IsBusy conflict
|
|
1332
|
+
* was detected. The caller should retry the transaction body immediately.
|
|
1183
1333
|
*/
|
|
1184
1334
|
async commit() {
|
|
1185
1335
|
try {
|
|
1186
|
-
await new Promise((resolve, reject) => {
|
|
1336
|
+
if (await new Promise((resolve, reject) => {
|
|
1187
1337
|
this.notify("beforecommit");
|
|
1188
1338
|
this.#txn.commit(resolve, reject);
|
|
1189
|
-
});
|
|
1339
|
+
}) === RETRY_NOW) return RETRY_NOW;
|
|
1190
1340
|
} catch (err) {
|
|
1191
1341
|
throw this.#handleCommitError(err);
|
|
1192
1342
|
} finally {
|
|
@@ -1332,6 +1482,60 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1332
1482
|
return this.store.compact(options);
|
|
1333
1483
|
}
|
|
1334
1484
|
/**
|
|
1485
|
+
* Creates a backup of the entire database (all column families) into the
|
|
1486
|
+
* given directory, creating parent directories as needed, and resolves with
|
|
1487
|
+
* the new backup id. Use the `backups` namespace to restore, list, delete,
|
|
1488
|
+
* purge, or verify backups.
|
|
1489
|
+
*
|
|
1490
|
+
* When the database was opened with `disableWAL`, the memtable is flushed
|
|
1491
|
+
* before the backup by default so unflushed data is not lost.
|
|
1492
|
+
*
|
|
1493
|
+
* @example
|
|
1494
|
+
* ```typescript
|
|
1495
|
+
* import { backups } from '@harperfast/rocksdb-js';
|
|
1496
|
+
*
|
|
1497
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1498
|
+
* const id = await db.backup('/path/to/backups');
|
|
1499
|
+
* ```
|
|
1500
|
+
*/
|
|
1501
|
+
backup(backupDir, options) {
|
|
1502
|
+
return this.store.backup(backupDir, options);
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Creates a hardlinked, point-in-time, fully independent copy of the entire
|
|
1506
|
+
* database (all column families) at `targetPath` and resolves once written.
|
|
1507
|
+
*
|
|
1508
|
+
* Unlike a backup, a checkpoint is a normal, writable sibling database: open
|
|
1509
|
+
* it with {@link RocksDatabase.open} and it diverges independently from the
|
|
1510
|
+
* source. SST and blob files are hardlinked when `targetPath` is on the same
|
|
1511
|
+
* filesystem as the database and copied otherwise (other files such as the
|
|
1512
|
+
* MANIFEST are always copied), so the operation is near-instant on the same
|
|
1513
|
+
* filesystem. The memtable is flushed so the checkpoint includes the latest
|
|
1514
|
+
* writes even when the WAL is disabled.
|
|
1515
|
+
*
|
|
1516
|
+
* Parent directories are created as needed. `targetPath` itself must not
|
|
1517
|
+
* already exist (RocksDB creates the checkpoint directory) and rejects with
|
|
1518
|
+
* `Create checkpoint failed: target path exists` if it does. The caller is
|
|
1519
|
+
* responsible for eventual cleanup of the directory.
|
|
1520
|
+
*
|
|
1521
|
+
* @example
|
|
1522
|
+
* ```typescript
|
|
1523
|
+
* const db = RocksDatabase.open('/path/to/database');
|
|
1524
|
+
* await db.createCheckpoint('/path/to/checkpoint');
|
|
1525
|
+
* const branch = RocksDatabase.open('/path/to/checkpoint');
|
|
1526
|
+
* ```
|
|
1527
|
+
*/
|
|
1528
|
+
createCheckpoint(targetPath) {
|
|
1529
|
+
return new Promise((resolve, reject) => {
|
|
1530
|
+
if (existsSync(targetPath)) {
|
|
1531
|
+
reject(/* @__PURE__ */ new Error("Create checkpoint failed: target path exists"));
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
1535
|
+
this.store.db.createCheckpoint(resolve, reject, targetPath);
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1335
1539
|
* Compacts the entire key range of the database synchronously.
|
|
1336
1540
|
* This triggers manual compaction which removes tombstones and reclaims space.
|
|
1337
1541
|
*
|
|
@@ -1563,6 +1767,30 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1563
1767
|
}
|
|
1564
1768
|
async ifNoExists(_key) {}
|
|
1565
1769
|
/**
|
|
1770
|
+
* Checks the process-global verification table for a fresh version match
|
|
1771
|
+
* on `key`. Returns `true` when the table currently records `version`. Use
|
|
1772
|
+
* this as a fast cache-freshness check before falling back to a full read:
|
|
1773
|
+
*
|
|
1774
|
+
* ```typescript
|
|
1775
|
+
* if (db.verifyVersion(key, cachedEntry.version)) {
|
|
1776
|
+
* return cachedEntry.value;
|
|
1777
|
+
* }
|
|
1778
|
+
* const value = db.getSync(key);
|
|
1779
|
+
* db.populateVersion(key, extractVersion(value));
|
|
1780
|
+
* ```
|
|
1781
|
+
*/
|
|
1782
|
+
verifyVersion(key, version) {
|
|
1783
|
+
return this.store.verifyVersion(key, version);
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Seeds the verification-table slot for `key` with `version`. Has no
|
|
1787
|
+
* effect if the slot is currently lock-tagged or if the verification
|
|
1788
|
+
* table is disabled.
|
|
1789
|
+
*/
|
|
1790
|
+
populateVersion(key, version) {
|
|
1791
|
+
this.store.populateVersion(key, version);
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1566
1794
|
* Returns whether the database is open.
|
|
1567
1795
|
*
|
|
1568
1796
|
* @returns `true` if the database is open, `false` otherwise.
|
|
@@ -1702,9 +1930,6 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1702
1930
|
get path() {
|
|
1703
1931
|
return this.store.path;
|
|
1704
1932
|
}
|
|
1705
|
-
/**
|
|
1706
|
-
* Purges transaction logs.
|
|
1707
|
-
*/
|
|
1708
1933
|
purgeLogs(options) {
|
|
1709
1934
|
return this.store.db.purgeLogs(options);
|
|
1710
1935
|
}
|
|
@@ -1740,13 +1965,19 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1740
1965
|
} catch (callbackErr) {
|
|
1741
1966
|
return this.#abortTransaction(txn, callbackErr);
|
|
1742
1967
|
}
|
|
1968
|
+
let commitResult;
|
|
1743
1969
|
try {
|
|
1744
|
-
await txn.commit();
|
|
1745
|
-
return result;
|
|
1970
|
+
commitResult = await txn.commit();
|
|
1746
1971
|
} catch (commitErr) {
|
|
1747
1972
|
if (commitErr instanceof TransactionAlreadyAbortedError) return;
|
|
1748
|
-
if (commitErr instanceof TransactionIsBusyError && (options?.retryOnBusy ?? commitErr.hasLog) && attempt
|
|
1973
|
+
if (commitErr instanceof TransactionIsBusyError && (options?.retryOnBusy ?? commitErr.hasLog) && attempt < maxRetries) continue;
|
|
1749
1974
|
this.#abandonTransaction(txn, commitErr);
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
if (commitResult !== RETRY_NOW) return result;
|
|
1978
|
+
if (attempt >= maxRetries) {
|
|
1979
|
+
this.#abandonTransaction(txn, /* @__PURE__ */ new Error(`Transaction did not commit after ${maxRetries} coordinated retries`));
|
|
1980
|
+
return;
|
|
1750
1981
|
}
|
|
1751
1982
|
}
|
|
1752
1983
|
}
|
|
@@ -2059,7 +2290,7 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
|
|
|
2059
2290
|
done: true,
|
|
2060
2291
|
value: void 0
|
|
2061
2292
|
};
|
|
2062
|
-
const limit = readUncommitted ? logBuffer.length : size;
|
|
2293
|
+
const limit = readUncommitted ? logBuffer.length : Math.min(size, logBuffer.length);
|
|
2063
2294
|
if (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE > limit) throw new RangeError(`Corrupt transaction log: truncated entry header at position ${position.toString(16)} of log ${logBuffer.logId} (available=${limit - position})`);
|
|
2064
2295
|
const length = dataView.getUint32(position + 8);
|
|
2065
2296
|
if (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE + length > limit) throw new RangeError(`Corrupt transaction log entry at position ${position.toString(16)} of log ${logBuffer.logId}: declared length ${length} overruns the log (limit=${limit})`);
|
|
@@ -2153,9 +2384,9 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
2153
2384
|
//#region src/index.ts
|
|
2154
2385
|
const versions = {
|
|
2155
2386
|
rocksdb: version,
|
|
2156
|
-
"rocksdb-js": "2.
|
|
2387
|
+
"rocksdb-js": "2.3.0"
|
|
2157
2388
|
};
|
|
2158
2389
|
|
|
2159
2390
|
//#endregion
|
|
2160
|
-
export { DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, constants, currentThreadId, parseTransactionLog, registryStatus, shutdown, stats, versions };
|
|
2391
|
+
export { DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, backups, constants, coolTransactionLogs, currentThreadId, parseTransactionLog, registryStatus, shutdown, stats, versions };
|
|
2161
2392
|
//# sourceMappingURL=index.mjs.map
|