serializable-bptree 5.1.6 → 5.2.1

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.
@@ -62,232 +62,132 @@ var StringComparator = class extends ValueComparator {
62
62
  };
63
63
 
64
64
  // node_modules/cache-entanglement/dist/esm/index.mjs
65
- var __create = Object.create;
66
- var __defProp2 = Object.defineProperty;
67
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
68
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
69
- var __getProtoOf = Object.getPrototypeOf;
70
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
71
- var __commonJS = (cb, mod) => function __require() {
72
- return mod || (0, cb[__getOwnPropNames2(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
73
- };
74
- var __copyProps2 = (to, from, except, desc) => {
75
- if (from && typeof from === "object" || typeof from === "function") {
76
- for (let key of __getOwnPropNames2(from))
77
- if (!__hasOwnProp2.call(to, key) && key !== except)
78
- __defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
65
+ var LRUMap = class {
66
+ capacity;
67
+ map;
68
+ head = null;
69
+ tail = null;
70
+ /**
71
+ * Creates an instance of LRUMap.
72
+ * @param capacity The maximum number of items the cache can hold.
73
+ */
74
+ constructor(capacity) {
75
+ this.capacity = capacity;
76
+ this.map = /* @__PURE__ */ new Map();
79
77
  }
80
- return to;
81
- };
82
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps2(
83
- // If the importer is in node compatibility mode or this is not an ESM
84
- // file that has been converted to a CommonJS file using a Babel-
85
- // compatible transform (i.e. "__esModule" has not been set), then set
86
- // "default" to the CommonJS "module.exports" for node compatibility.
87
- isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", { value: mod, enumerable: true }) : target,
88
- mod
89
- ));
90
- var require_ms = __commonJS({
91
- "node_modules/ms/index.js"(exports, module2) {
92
- var s = 1e3;
93
- var m = s * 60;
94
- var h = m * 60;
95
- var d = h * 24;
96
- var w = d * 7;
97
- var y = d * 365.25;
98
- module2.exports = function(val, options) {
99
- options = options || {};
100
- var type = typeof val;
101
- if (type === "string" && val.length > 0) {
102
- return parse(val);
103
- } else if (type === "number" && isFinite(val)) {
104
- return options.long ? fmtLong(val) : fmtShort(val);
105
- }
106
- throw new Error(
107
- "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
108
- );
109
- };
110
- function parse(str) {
111
- str = String(str);
112
- if (str.length > 100) {
113
- return;
114
- }
115
- var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
116
- str
117
- );
118
- if (!match) {
119
- return;
120
- }
121
- var n = parseFloat(match[1]);
122
- var type = (match[2] || "ms").toLowerCase();
123
- switch (type) {
124
- case "years":
125
- case "year":
126
- case "yrs":
127
- case "yr":
128
- case "y":
129
- return n * y;
130
- case "weeks":
131
- case "week":
132
- case "w":
133
- return n * w;
134
- case "days":
135
- case "day":
136
- case "d":
137
- return n * d;
138
- case "hours":
139
- case "hour":
140
- case "hrs":
141
- case "hr":
142
- case "h":
143
- return n * h;
144
- case "minutes":
145
- case "minute":
146
- case "mins":
147
- case "min":
148
- case "m":
149
- return n * m;
150
- case "seconds":
151
- case "second":
152
- case "secs":
153
- case "sec":
154
- case "s":
155
- return n * s;
156
- case "milliseconds":
157
- case "millisecond":
158
- case "msecs":
159
- case "msec":
160
- case "ms":
161
- return n;
162
- default:
163
- return void 0;
164
- }
165
- }
166
- function fmtShort(ms2) {
167
- var msAbs = Math.abs(ms2);
168
- if (msAbs >= d) {
169
- return Math.round(ms2 / d) + "d";
170
- }
171
- if (msAbs >= h) {
172
- return Math.round(ms2 / h) + "h";
173
- }
174
- if (msAbs >= m) {
175
- return Math.round(ms2 / m) + "m";
176
- }
177
- if (msAbs >= s) {
178
- return Math.round(ms2 / s) + "s";
179
- }
180
- return ms2 + "ms";
181
- }
182
- function fmtLong(ms2) {
183
- var msAbs = Math.abs(ms2);
184
- if (msAbs >= d) {
185
- return plural(ms2, msAbs, d, "day");
186
- }
187
- if (msAbs >= h) {
188
- return plural(ms2, msAbs, h, "hour");
189
- }
190
- if (msAbs >= m) {
191
- return plural(ms2, msAbs, m, "minute");
192
- }
193
- if (msAbs >= s) {
194
- return plural(ms2, msAbs, s, "second");
195
- }
196
- return ms2 + " ms";
197
- }
198
- function plural(ms2, msAbs, n, name) {
199
- var isPlural = msAbs >= n * 1.5;
200
- return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
201
- }
78
+ /**
79
+ * Promotes a node to the head of the linked list (marks as most recently used).
80
+ * @param node The node to promote.
81
+ */
82
+ promote(node) {
83
+ this.extract(node);
84
+ this.prepend(node);
202
85
  }
203
- });
204
- var import_ms = __toESM(require_ms());
205
- var InvertedWeakMap = class {
206
- _map;
207
- _keepAlive;
208
- _timeouts;
209
- _registry;
210
- _lifespan;
211
- constructor(option) {
212
- const { lifespan } = option;
213
- this._lifespan = lifespan;
214
- this._map = /* @__PURE__ */ new Map();
215
- this._keepAlive = /* @__PURE__ */ new Map();
216
- this._timeouts = /* @__PURE__ */ new Map();
217
- this._registry = new FinalizationRegistry((key) => {
218
- this._stopExpire(key, true);
219
- this._map.delete(key);
220
- });
86
+ /**
87
+ * Disconnects a node from the doubly linked list.
88
+ * @param node The node to extract.
89
+ */
90
+ extract(node) {
91
+ if (node.prev) node.prev.next = node.next;
92
+ else this.head = node.next;
93
+ if (node.next) node.next.prev = node.prev;
94
+ else this.tail = node.prev;
95
+ node.prev = null;
96
+ node.next = null;
221
97
  }
222
- clear() {
223
- this._keepAlive.clear();
224
- this._map.clear();
98
+ /**
99
+ * Inserts a node at the head of the doubly linked list.
100
+ * @param node The node to prepend.
101
+ */
102
+ prepend(node) {
103
+ node.next = this.head;
104
+ if (this.head) this.head.prev = node;
105
+ this.head = node;
106
+ if (!this.tail) this.tail = node;
225
107
  }
226
- delete(key) {
227
- const ref = this._map.get(key);
228
- if (ref) {
229
- const raw = ref.deref();
230
- if (raw !== void 0) {
231
- this._registry.unregister(raw);
232
- }
108
+ /**
109
+ * Stores or updates a value by key.
110
+ * If the capacity is exceeded, the least recently used item (tail) is removed.
111
+ * @param key The key to store.
112
+ * @param value The value to store.
113
+ */
114
+ set(key, value) {
115
+ const existing = this.map.get(key);
116
+ if (existing) {
117
+ existing.value = value;
118
+ this.promote(existing);
119
+ return;
120
+ }
121
+ const newNode = { key, value, prev: null, next: null };
122
+ this.map.set(key, newNode);
123
+ this.prepend(newNode);
124
+ if (this.map.size > this.capacity && this.tail) {
125
+ this.map.delete(this.tail.key);
126
+ this.extract(this.tail);
233
127
  }
234
- this._stopExpire(key, true);
235
- this._keepAlive.delete(key);
236
- return this._map.delete(key);
237
128
  }
129
+ /**
130
+ * Retrieves a value by key.
131
+ * Accessing the item moves it to the "most recently used" position.
132
+ * @param key The key to look for.
133
+ * @returns The value associated with the key, or undefined if not found.
134
+ */
238
135
  get(key) {
239
- return this._map.get(key)?.deref();
136
+ const node = this.map.get(key);
137
+ if (!node) return void 0;
138
+ this.promote(node);
139
+ return node.value;
240
140
  }
141
+ /**
142
+ * Checks if a key exists in the cache without changing its access order.
143
+ * @param key The key to check.
144
+ * @returns True if the key exists, false otherwise.
145
+ */
241
146
  has(key) {
242
- return this._map.has(key) && this.get(key) !== void 0;
243
- }
244
- set(key, value) {
245
- this._map.set(key, new WeakRef(value));
246
- this._registry.register(value, key);
247
- if (this._lifespan > 0) {
248
- this._stopExpire(key, true);
249
- this._startExpire(key, value);
250
- }
251
- return this;
252
- }
253
- extendExpire(key) {
254
- if (!(this._lifespan > 0)) {
255
- return;
256
- }
257
- if (!this._keepAlive.has(key)) {
258
- return;
259
- }
260
- this._stopExpire(key, false);
261
- this._startExpire(key, this._keepAlive.get(key));
147
+ return this.map.has(key);
262
148
  }
263
- _startExpire(key, value) {
264
- this._keepAlive.set(key, value);
265
- this._timeouts.set(key, setTimeout(() => {
266
- this._keepAlive.delete(key);
267
- }, this._lifespan));
149
+ /**
150
+ * Removes a key and its associated value from the cache.
151
+ * @param key The key to remove.
152
+ * @returns True if the key was found and removed, false otherwise.
153
+ */
154
+ delete(key) {
155
+ const node = this.map.get(key);
156
+ if (!node) return false;
157
+ this.extract(node);
158
+ this.map.delete(key);
159
+ return true;
268
160
  }
269
- _stopExpire(key, removeKeepAlive) {
270
- if (!this._timeouts.has(key)) {
271
- return;
272
- }
273
- const timeout = this._timeouts.get(key);
274
- this._timeouts.delete(key);
275
- clearTimeout(timeout);
276
- if (removeKeepAlive) {
277
- this._keepAlive.delete(key);
161
+ /**
162
+ * Returns an iterator of keys in the order of most recently used to least recently used.
163
+ * @returns An iterable iterator of keys.
164
+ */
165
+ *keys() {
166
+ let current = this.head;
167
+ while (current) {
168
+ yield current.key;
169
+ current = current.next;
278
170
  }
279
171
  }
172
+ /**
173
+ * Returns the current number of items in the cache.
174
+ */
280
175
  get size() {
281
- return this._map.size;
176
+ return this.map.size;
282
177
  }
283
- keys() {
284
- return this._map.keys();
178
+ /**
179
+ * Clears all items from the cache.
180
+ */
181
+ clear() {
182
+ this.map.clear();
183
+ this.head = null;
184
+ this.tail = null;
285
185
  }
286
186
  };
287
187
  var CacheEntanglement = class {
288
188
  creation;
289
189
  beforeUpdateHook;
290
- lifespan;
190
+ capacity;
291
191
  dependencies;
292
192
  caches;
293
193
  parameters;
@@ -298,15 +198,15 @@ var CacheEntanglement = class {
298
198
  option = option ?? {};
299
199
  const {
300
200
  dependencies,
301
- lifespan,
201
+ capacity,
302
202
  beforeUpdateHook
303
203
  } = option;
304
204
  this.creation = creation;
305
205
  this.beforeUpdateHook = beforeUpdateHook ?? (() => {
306
206
  });
307
- this.lifespan = this._normalizeMs(lifespan ?? 0);
207
+ this.capacity = capacity ?? 100;
308
208
  this.assignments = [];
309
- this.caches = new InvertedWeakMap({ lifespan: this.lifespan });
209
+ this.caches = new LRUMap(this.capacity);
310
210
  this.parameters = /* @__PURE__ */ new Map();
311
211
  this.dependencies = dependencies ?? {};
312
212
  this.dependencyProperties = Object.keys(this.dependencies);
@@ -318,12 +218,6 @@ var CacheEntanglement = class {
318
218
  }
319
219
  }
320
220
  }
321
- _normalizeMs(time) {
322
- if (typeof time === "string") {
323
- return (0, import_ms.default)(time);
324
- }
325
- return time;
326
- }
327
221
  bubbleUpdateSignal(key) {
328
222
  this.updateRequirements.add(key);
329
223
  for (let i = 0, len = this.assignments.length; i < len; i++) {
@@ -480,8 +374,6 @@ var CacheEntanglementSync = class extends CacheEntanglement {
480
374
  cache(key, ...parameter) {
481
375
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
482
376
  this.resolve(key, ...parameter);
483
- } else {
484
- this.caches.extendExpire(key);
485
377
  }
486
378
  return this.caches.get(key);
487
379
  }
@@ -536,8 +428,6 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
536
428
  async cache(key, ...parameter) {
537
429
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
538
430
  await this.update(key, ...parameter);
539
- } else {
540
- this.caches.extendExpire(key);
541
431
  }
542
432
  return this.caches.get(key);
543
433
  }
@@ -625,7 +515,7 @@ var BPTree = class {
625
515
  const regexp = new RegExp(`^${pattern}$`, "i");
626
516
  return regexp;
627
517
  }, {
628
- lifespan: this.option.lifespan ?? "3m"
518
+ capacity: this.option.capacity ?? 1e3
629
519
  });
630
520
  }
631
521
  ensureValues(v) {
@@ -718,7 +608,7 @@ var BPTreeSync = class extends BPTree {
718
608
  return new CacheEntanglementSync((key) => {
719
609
  return this.strategy.read(key);
720
610
  }, {
721
- lifespan: this.option.lifespan ?? "3m"
611
+ capacity: this.option.capacity ?? 1e3
722
612
  });
723
613
  }
724
614
  getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -1300,17 +1190,295 @@ var BPTreeSync = class extends BPTree {
1300
1190
  }
1301
1191
  };
1302
1192
 
1193
+ // node_modules/ryoiki/dist/esm/index.mjs
1194
+ var Ryoiki = class _Ryoiki {
1195
+ readings;
1196
+ writings;
1197
+ readQueue;
1198
+ writeQueue;
1199
+ static async CatchError(promise) {
1200
+ return await promise.then((v) => [void 0, v]).catch((err) => [err]);
1201
+ }
1202
+ static IsRangeOverlap(a, b) {
1203
+ const [start1, end1] = a;
1204
+ const [start2, end2] = b;
1205
+ if (end1 <= start2 || end2 <= start1) {
1206
+ return false;
1207
+ }
1208
+ return true;
1209
+ }
1210
+ static ERR_ALREADY_EXISTS(lockId) {
1211
+ return new Error(`The '${lockId}' task already existing in queue or running.`);
1212
+ }
1213
+ static ERR_NOT_EXISTS(lockId) {
1214
+ return new Error(`The '${lockId}' task not existing in task queue.`);
1215
+ }
1216
+ static ERR_TIMEOUT(lockId, timeout) {
1217
+ return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
1218
+ }
1219
+ /**
1220
+ * Constructs a new instance of the Ryoiki class.
1221
+ */
1222
+ constructor() {
1223
+ this.readings = /* @__PURE__ */ new Map();
1224
+ this.writings = /* @__PURE__ */ new Map();
1225
+ this.readQueue = /* @__PURE__ */ new Map();
1226
+ this.writeQueue = /* @__PURE__ */ new Map();
1227
+ }
1228
+ /**
1229
+ * Creates a range based on a start value and length.
1230
+ * @param start - The starting value of the range.
1231
+ * @param length - The length of the range.
1232
+ * @returns A range tuple [start, start + length].
1233
+ */
1234
+ range(start, length) {
1235
+ return [start, start + length];
1236
+ }
1237
+ rangeOverlapping(tasks, range) {
1238
+ return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range));
1239
+ }
1240
+ isSameRange(a, b) {
1241
+ const [a1, a2] = a;
1242
+ const [b1, b2] = b;
1243
+ return a1 === b1 && a2 === b2;
1244
+ }
1245
+ fetchUnitAndRun(queue, workspaces) {
1246
+ for (const [id, unit] of queue) {
1247
+ if (!unit.condition()) {
1248
+ continue;
1249
+ }
1250
+ this._alloc(queue, workspaces, id);
1251
+ }
1252
+ }
1253
+ _handleOverload(args, handlers, argPatterns) {
1254
+ for (const [key, pattern] of Object.entries(argPatterns)) {
1255
+ if (this._matchArgs(args, pattern)) {
1256
+ return handlers[key](...args);
1257
+ }
1258
+ }
1259
+ throw new Error("Invalid arguments");
1260
+ }
1261
+ _matchArgs(args, pattern) {
1262
+ return args.every((arg, index) => {
1263
+ const expectedType = pattern[index];
1264
+ if (expectedType === void 0) return typeof arg === "undefined";
1265
+ if (expectedType === Function) return typeof arg === "function";
1266
+ if (expectedType === Number) return typeof arg === "number";
1267
+ if (expectedType === Array) return Array.isArray(arg);
1268
+ return false;
1269
+ });
1270
+ }
1271
+ _createRandomId() {
1272
+ const timestamp = Date.now().toString(36);
1273
+ const random = Math.random().toString(36).substring(2);
1274
+ return `${timestamp}${random}`;
1275
+ }
1276
+ _alloc(queue, workspaces, lockId) {
1277
+ const unit = queue.get(lockId);
1278
+ if (!unit) {
1279
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1280
+ }
1281
+ workspaces.set(lockId, unit);
1282
+ queue.delete(lockId);
1283
+ unit.alloc();
1284
+ }
1285
+ _free(workspaces, lockId) {
1286
+ const unit = workspaces.get(lockId);
1287
+ if (!unit) {
1288
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1289
+ }
1290
+ workspaces.delete(lockId);
1291
+ unit.free();
1292
+ }
1293
+ _lock(queue, range, timeout, task, condition) {
1294
+ return new Promise((resolve, reject) => {
1295
+ let timeoutId = null;
1296
+ if (timeout >= 0) {
1297
+ timeoutId = setTimeout(() => {
1298
+ reject(_Ryoiki.ERR_TIMEOUT(id, timeout));
1299
+ }, timeout);
1300
+ }
1301
+ const id = this._createRandomId();
1302
+ const alloc = async () => {
1303
+ if (timeoutId !== null) {
1304
+ clearTimeout(timeoutId);
1305
+ }
1306
+ const [err, v] = await _Ryoiki.CatchError(task(id));
1307
+ if (err) reject(err);
1308
+ else resolve(v);
1309
+ };
1310
+ const fetch = () => {
1311
+ this.fetchUnitAndRun(this.readQueue, this.readings);
1312
+ this.fetchUnitAndRun(this.writeQueue, this.writings);
1313
+ };
1314
+ queue.set(id, { id, range, condition, alloc, free: fetch });
1315
+ fetch();
1316
+ });
1317
+ }
1318
+ _checkWorking(range, workspaces) {
1319
+ let isLocked = false;
1320
+ for (const lock of workspaces.values()) {
1321
+ if (_Ryoiki.IsRangeOverlap(range, lock.range)) {
1322
+ isLocked = true;
1323
+ break;
1324
+ }
1325
+ }
1326
+ return isLocked;
1327
+ }
1328
+ /**
1329
+ * Checks if there is any active read lock within the specified range.
1330
+ * @param range The range to check for active read locks.
1331
+ * @returns `true` if there is an active read lock within the range, `false` otherwise.
1332
+ */
1333
+ isReading(range) {
1334
+ return this._checkWorking(range, this.readings);
1335
+ }
1336
+ /**
1337
+ * Checks if there is any active write lock within the specified range.
1338
+ * @param range The range to check for active write locks.
1339
+ * @returns `true` if there is an active write lock within the range, `false` otherwise.
1340
+ */
1341
+ isWriting(range) {
1342
+ return this._checkWorking(range, this.writings);
1343
+ }
1344
+ /**
1345
+ * Checks if a read lock can be acquired within the specified range.
1346
+ * @param range The range to check for read lock availability.
1347
+ * @returns `true` if a read lock can be acquired, `false` otherwise.
1348
+ */
1349
+ canRead(range) {
1350
+ const writing = this.isWriting(range);
1351
+ return !writing;
1352
+ }
1353
+ /**
1354
+ * Checks if a write lock can be acquired within the specified range.
1355
+ * @param range The range to check for write lock availability.
1356
+ * @returns `true` if a write lock can be acquired, `false` otherwise.
1357
+ */
1358
+ canWrite(range) {
1359
+ const reading = this.isReading(range);
1360
+ const writing = this.isWriting(range);
1361
+ return !reading && !writing;
1362
+ }
1363
+ /**
1364
+ * Internal implementation of the read lock. Handles both overloads.
1365
+ * @template T - The return type of the task.
1366
+ * @param arg0 - Either a range or a task callback.
1367
+ * If a range is provided, the task is the second argument.
1368
+ * @param arg1 - The task to execute, required if a range is provided.
1369
+ * @param arg2 - The timeout for acquiring the lock.
1370
+ * If the lock cannot be acquired within this period, an error will be thrown.
1371
+ * If this value is not provided, no timeout will be set.
1372
+ * @returns A promise resolving to the result of the task execution.
1373
+ */
1374
+ readLock(arg0, arg1, arg2) {
1375
+ const [range, task, timeout] = this._handleOverload(
1376
+ [arg0, arg1, arg2],
1377
+ {
1378
+ rangeTask: (range2, task2) => [range2, task2, -1],
1379
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1380
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
1381
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1382
+ },
1383
+ {
1384
+ task: [Function],
1385
+ taskTimeout: [Function, Number],
1386
+ rangeTask: [Array, Function],
1387
+ rangeTaskTimeout: [Array, Function, Number]
1388
+ }
1389
+ );
1390
+ return this._lock(
1391
+ this.readQueue,
1392
+ range,
1393
+ timeout,
1394
+ task,
1395
+ () => !this.rangeOverlapping(this.writings, range)
1396
+ );
1397
+ }
1398
+ /**
1399
+ * Internal implementation of the write lock. Handles both overloads.
1400
+ * @template T - The return type of the task.
1401
+ * @param arg0 - Either a range or a task callback.
1402
+ * If a range is provided, the task is the second argument.
1403
+ * @param arg1 - The task to execute, required if a range is provided.
1404
+ * @param arg2 - The timeout for acquiring the lock.
1405
+ * If the lock cannot be acquired within this period, an error will be thrown.
1406
+ * If this value is not provided, no timeout will be set.
1407
+ * @returns A promise resolving to the result of the task execution.
1408
+ */
1409
+ writeLock(arg0, arg1, arg2) {
1410
+ const [range, task, timeout] = this._handleOverload(
1411
+ [arg0, arg1, arg2],
1412
+ {
1413
+ rangeTask: (range2, task2) => [range2, task2, -1],
1414
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1415
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
1416
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1417
+ },
1418
+ {
1419
+ task: [Function],
1420
+ taskTimeout: [Function, Number],
1421
+ rangeTask: [Array, Function],
1422
+ rangeTaskTimeout: [Array, Function, Number]
1423
+ }
1424
+ );
1425
+ return this._lock(
1426
+ this.writeQueue,
1427
+ range,
1428
+ timeout,
1429
+ task,
1430
+ () => {
1431
+ return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
1432
+ }
1433
+ );
1434
+ }
1435
+ /**
1436
+ * Releases a read lock by its lock ID.
1437
+ * @param lockId - The unique identifier for the lock to release.
1438
+ */
1439
+ readUnlock(lockId) {
1440
+ this._free(this.readings, lockId);
1441
+ }
1442
+ /**
1443
+ * Releases a write lock by its lock ID.
1444
+ * @param lockId - The unique identifier for the lock to release.
1445
+ */
1446
+ writeUnlock(lockId) {
1447
+ this._free(this.writings, lockId);
1448
+ }
1449
+ };
1450
+
1303
1451
  // src/BPTreeAsync.ts
1304
1452
  var BPTreeAsync = class extends BPTree {
1453
+ lock;
1305
1454
  constructor(strategy, comparator, option) {
1306
1455
  super(strategy, comparator, option);
1307
1456
  this.nodes = this._createCachedNode();
1457
+ this.lock = new Ryoiki();
1308
1458
  }
1309
1459
  _createCachedNode() {
1310
1460
  return new CacheEntanglementAsync(async (key) => {
1311
1461
  return await this.strategy.read(key);
1312
1462
  }, {
1313
- lifespan: this.option.lifespan ?? "3m"
1463
+ capacity: this.option.capacity ?? 1e3
1464
+ });
1465
+ }
1466
+ async readLock(callback) {
1467
+ let lockId;
1468
+ return await this.lock.readLock(async (_lockId) => {
1469
+ lockId = _lockId;
1470
+ return await callback();
1471
+ }).finally(() => {
1472
+ this.lock.readUnlock(lockId);
1473
+ });
1474
+ }
1475
+ async writeLock(callback) {
1476
+ let lockId;
1477
+ return await this.lock.writeLock(async (_lockId) => {
1478
+ lockId = _lockId;
1479
+ return await callback();
1480
+ }).finally(() => {
1481
+ this.lock.writeUnlock(lockId);
1314
1482
  });
1315
1483
  }
1316
1484
  async getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -1756,139 +1924,153 @@ var BPTreeAsync = class extends BPTree {
1756
1924
  this._nodeDeleteBuffer.clear();
1757
1925
  }
1758
1926
  async keys(condition, filterValues) {
1759
- for (const k in condition) {
1760
- const key = k;
1761
- const value = condition[key];
1762
- const startNode = await this.verifierStartNode[key](value);
1763
- const endNode = await this.verifierEndNode[key](value);
1764
- const direction = this.verifierDirection[key];
1765
- const comparator = this.verifierMap[key];
1766
- const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1767
- if (!filterValues) {
1768
- filterValues = new Set(pairs.keys());
1769
- } else {
1770
- const intersections = /* @__PURE__ */ new Set();
1771
- for (const key2 of filterValues) {
1772
- const has = pairs.has(key2);
1773
- if (has) {
1774
- intersections.add(key2);
1927
+ return this.readLock(async () => {
1928
+ for (const k in condition) {
1929
+ const key = k;
1930
+ const value = condition[key];
1931
+ const startNode = await this.verifierStartNode[key](value);
1932
+ const endNode = await this.verifierEndNode[key](value);
1933
+ const direction = this.verifierDirection[key];
1934
+ const comparator = this.verifierMap[key];
1935
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1936
+ if (!filterValues) {
1937
+ filterValues = new Set(pairs.keys());
1938
+ } else {
1939
+ const intersections = /* @__PURE__ */ new Set();
1940
+ for (const key2 of filterValues) {
1941
+ const has = pairs.has(key2);
1942
+ if (has) {
1943
+ intersections.add(key2);
1944
+ }
1775
1945
  }
1946
+ filterValues = intersections;
1776
1947
  }
1777
- filterValues = intersections;
1778
1948
  }
1779
- }
1780
- return filterValues ?? /* @__PURE__ */ new Set([]);
1949
+ return filterValues ?? /* @__PURE__ */ new Set([]);
1950
+ });
1781
1951
  }
1782
1952
  async where(condition) {
1783
- let result = null;
1784
- for (const k in condition) {
1785
- const key = k;
1786
- const value = condition[key];
1787
- const startNode = await this.verifierStartNode[key](value);
1788
- const endNode = await this.verifierEndNode[key](value);
1789
- const direction = this.verifierDirection[key];
1790
- const comparator = this.verifierMap[key];
1791
- const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1792
- if (result === null) {
1793
- result = pairs;
1794
- } else {
1795
- const intersection = /* @__PURE__ */ new Map();
1796
- for (const [k2, v] of pairs) {
1797
- if (result.has(k2)) {
1798
- intersection.set(k2, v);
1953
+ return this.readLock(async () => {
1954
+ let result = null;
1955
+ for (const k in condition) {
1956
+ const key = k;
1957
+ const value = condition[key];
1958
+ const startNode = await this.verifierStartNode[key](value);
1959
+ const endNode = await this.verifierEndNode[key](value);
1960
+ const direction = this.verifierDirection[key];
1961
+ const comparator = this.verifierMap[key];
1962
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1963
+ if (result === null) {
1964
+ result = pairs;
1965
+ } else {
1966
+ const intersection = /* @__PURE__ */ new Map();
1967
+ for (const [k2, v] of pairs) {
1968
+ if (result.has(k2)) {
1969
+ intersection.set(k2, v);
1970
+ }
1799
1971
  }
1972
+ result = intersection;
1800
1973
  }
1801
- result = intersection;
1802
1974
  }
1803
- }
1804
- return result ?? /* @__PURE__ */ new Map();
1975
+ return result ?? /* @__PURE__ */ new Map();
1976
+ });
1805
1977
  }
1806
1978
  async insert(key, value) {
1807
- const before = await this.insertableNode(value);
1808
- this._insertAtLeaf(before, key, value);
1809
- if (before.values.length === this.order) {
1810
- const after = await this._createNode(
1811
- true,
1812
- [],
1813
- [],
1814
- true,
1815
- before.parent,
1816
- before.next,
1817
- before.id
1818
- );
1819
- const mid = Math.ceil(this.order / 2) - 1;
1820
- const beforeNext = before.next;
1821
- after.values = before.values.slice(mid + 1);
1822
- after.keys = before.keys.slice(mid + 1);
1823
- before.values = before.values.slice(0, mid + 1);
1824
- before.keys = before.keys.slice(0, mid + 1);
1825
- before.next = after.id;
1826
- if (beforeNext) {
1827
- const node = await this.getNode(beforeNext);
1828
- node.prev = after.id;
1829
- this.bufferForNodeUpdate(node);
1979
+ return this.writeLock(async () => {
1980
+ const before = await this.insertableNode(value);
1981
+ this._insertAtLeaf(before, key, value);
1982
+ if (before.values.length === this.order) {
1983
+ const after = await this._createNode(
1984
+ true,
1985
+ [],
1986
+ [],
1987
+ true,
1988
+ before.parent,
1989
+ before.next,
1990
+ before.id
1991
+ );
1992
+ const mid = Math.ceil(this.order / 2) - 1;
1993
+ const beforeNext = before.next;
1994
+ after.values = before.values.slice(mid + 1);
1995
+ after.keys = before.keys.slice(mid + 1);
1996
+ before.values = before.values.slice(0, mid + 1);
1997
+ before.keys = before.keys.slice(0, mid + 1);
1998
+ before.next = after.id;
1999
+ if (beforeNext) {
2000
+ const node = await this.getNode(beforeNext);
2001
+ node.prev = after.id;
2002
+ this.bufferForNodeUpdate(node);
2003
+ }
2004
+ await this._insertInParent(before, after.values[0], after);
2005
+ this.bufferForNodeUpdate(before);
1830
2006
  }
1831
- await this._insertInParent(before, after.values[0], after);
1832
- this.bufferForNodeUpdate(before);
1833
- }
1834
- await this.commitHeadBuffer();
1835
- await this.commitNodeCreateBuffer();
1836
- await this.commitNodeUpdateBuffer();
2007
+ await this.commitHeadBuffer();
2008
+ await this.commitNodeCreateBuffer();
2009
+ await this.commitNodeUpdateBuffer();
2010
+ });
1837
2011
  }
1838
2012
  async delete(key, value) {
1839
- const node = await this.insertableNode(value);
1840
- let i = node.values.length;
1841
- while (i--) {
1842
- const nValue = node.values[i];
1843
- if (this.comparator.isSame(value, nValue)) {
1844
- const keys = node.keys[i];
1845
- if (keys.includes(key)) {
1846
- if (keys.length > 1) {
1847
- keys.splice(keys.indexOf(key), 1);
1848
- this.bufferForNodeUpdate(node);
1849
- } else if (node.id === this.root.id) {
1850
- node.values.splice(i, 1);
1851
- node.keys.splice(i, 1);
1852
- this.bufferForNodeUpdate(node);
1853
- } else {
1854
- keys.splice(keys.indexOf(key), 1);
1855
- node.keys.splice(i, 1);
1856
- node.values.splice(node.values.indexOf(value), 1);
1857
- await this._deleteEntry(node, key, value);
1858
- this.bufferForNodeUpdate(node);
2013
+ return this.writeLock(async () => {
2014
+ const node = await this.insertableNode(value);
2015
+ let i = node.values.length;
2016
+ while (i--) {
2017
+ const nValue = node.values[i];
2018
+ if (this.comparator.isSame(value, nValue)) {
2019
+ const keys = node.keys[i];
2020
+ if (keys.includes(key)) {
2021
+ if (keys.length > 1) {
2022
+ keys.splice(keys.indexOf(key), 1);
2023
+ this.bufferForNodeUpdate(node);
2024
+ } else if (node.id === this.root.id) {
2025
+ node.values.splice(i, 1);
2026
+ node.keys.splice(i, 1);
2027
+ this.bufferForNodeUpdate(node);
2028
+ } else {
2029
+ keys.splice(keys.indexOf(key), 1);
2030
+ node.keys.splice(i, 1);
2031
+ node.values.splice(node.values.indexOf(value), 1);
2032
+ await this._deleteEntry(node, key, value);
2033
+ this.bufferForNodeUpdate(node);
2034
+ }
1859
2035
  }
1860
2036
  }
1861
2037
  }
1862
- }
1863
- await this.commitHeadBuffer();
1864
- await this.commitNodeCreateBuffer();
1865
- await this.commitNodeUpdateBuffer();
1866
- await this.commitNodeDeleteBuffer();
2038
+ await this.commitHeadBuffer();
2039
+ await this.commitNodeCreateBuffer();
2040
+ await this.commitNodeUpdateBuffer();
2041
+ await this.commitNodeDeleteBuffer();
2042
+ });
1867
2043
  }
1868
2044
  async exists(key, value) {
1869
- const node = await this.insertableNode(value);
1870
- for (let i = 0, len = node.values.length; i < len; i++) {
1871
- const nValue = node.values[i];
1872
- if (this.comparator.isSame(value, nValue)) {
1873
- const keys = node.keys[i];
1874
- return keys.includes(key);
2045
+ return this.readLock(async () => {
2046
+ const node = await this.insertableNode(value);
2047
+ for (let i = 0, len = node.values.length; i < len; i++) {
2048
+ const nValue = node.values[i];
2049
+ if (this.comparator.isSame(value, nValue)) {
2050
+ const keys = node.keys[i];
2051
+ return keys.includes(key);
2052
+ }
1875
2053
  }
1876
- }
1877
- return false;
2054
+ return false;
2055
+ });
1878
2056
  }
1879
2057
  async setHeadData(data) {
1880
- this.strategy.head.data = data;
1881
- this._strategyDirty = true;
1882
- await this.commitHeadBuffer();
2058
+ return this.writeLock(async () => {
2059
+ this.strategy.head.data = data;
2060
+ this._strategyDirty = true;
2061
+ await this.commitHeadBuffer();
2062
+ });
1883
2063
  }
1884
2064
  async forceUpdate() {
1885
- const keys = [...this.nodes.keys()];
1886
- this.nodes.clear();
1887
- await this.init();
1888
- for (const key of keys) {
1889
- await this.getNode(key);
1890
- }
1891
- return keys.length;
2065
+ return this.readLock(async () => {
2066
+ const keys = [...this.nodes.keys()];
2067
+ this.nodes.clear();
2068
+ await this.init();
2069
+ for (const key of keys) {
2070
+ await this.getNode(key);
2071
+ }
2072
+ return keys.length;
2073
+ });
1892
2074
  }
1893
2075
  };
1894
2076