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.
@@ -28,232 +28,132 @@ var StringComparator = class extends ValueComparator {
28
28
  };
29
29
 
30
30
  // node_modules/cache-entanglement/dist/esm/index.mjs
31
- var __create = Object.create;
32
- var __defProp = Object.defineProperty;
33
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
34
- var __getOwnPropNames = Object.getOwnPropertyNames;
35
- var __getProtoOf = Object.getPrototypeOf;
36
- var __hasOwnProp = Object.prototype.hasOwnProperty;
37
- var __commonJS = (cb, mod) => function __require() {
38
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
39
- };
40
- var __copyProps = (to, from, except, desc) => {
41
- if (from && typeof from === "object" || typeof from === "function") {
42
- for (let key of __getOwnPropNames(from))
43
- if (!__hasOwnProp.call(to, key) && key !== except)
44
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
45
- }
46
- return to;
47
- };
48
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
49
- // If the importer is in node compatibility mode or this is not an ESM
50
- // file that has been converted to a CommonJS file using a Babel-
51
- // compatible transform (i.e. "__esModule" has not been set), then set
52
- // "default" to the CommonJS "module.exports" for node compatibility.
53
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
54
- mod
55
- ));
56
- var require_ms = __commonJS({
57
- "node_modules/ms/index.js"(exports, module) {
58
- var s = 1e3;
59
- var m = s * 60;
60
- var h = m * 60;
61
- var d = h * 24;
62
- var w = d * 7;
63
- var y = d * 365.25;
64
- module.exports = function(val, options) {
65
- options = options || {};
66
- var type = typeof val;
67
- if (type === "string" && val.length > 0) {
68
- return parse(val);
69
- } else if (type === "number" && isFinite(val)) {
70
- return options.long ? fmtLong(val) : fmtShort(val);
71
- }
72
- throw new Error(
73
- "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
74
- );
75
- };
76
- function parse(str) {
77
- str = String(str);
78
- if (str.length > 100) {
79
- return;
80
- }
81
- 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(
82
- str
83
- );
84
- if (!match) {
85
- return;
86
- }
87
- var n = parseFloat(match[1]);
88
- var type = (match[2] || "ms").toLowerCase();
89
- switch (type) {
90
- case "years":
91
- case "year":
92
- case "yrs":
93
- case "yr":
94
- case "y":
95
- return n * y;
96
- case "weeks":
97
- case "week":
98
- case "w":
99
- return n * w;
100
- case "days":
101
- case "day":
102
- case "d":
103
- return n * d;
104
- case "hours":
105
- case "hour":
106
- case "hrs":
107
- case "hr":
108
- case "h":
109
- return n * h;
110
- case "minutes":
111
- case "minute":
112
- case "mins":
113
- case "min":
114
- case "m":
115
- return n * m;
116
- case "seconds":
117
- case "second":
118
- case "secs":
119
- case "sec":
120
- case "s":
121
- return n * s;
122
- case "milliseconds":
123
- case "millisecond":
124
- case "msecs":
125
- case "msec":
126
- case "ms":
127
- return n;
128
- default:
129
- return void 0;
130
- }
131
- }
132
- function fmtShort(ms2) {
133
- var msAbs = Math.abs(ms2);
134
- if (msAbs >= d) {
135
- return Math.round(ms2 / d) + "d";
136
- }
137
- if (msAbs >= h) {
138
- return Math.round(ms2 / h) + "h";
139
- }
140
- if (msAbs >= m) {
141
- return Math.round(ms2 / m) + "m";
142
- }
143
- if (msAbs >= s) {
144
- return Math.round(ms2 / s) + "s";
145
- }
146
- return ms2 + "ms";
147
- }
148
- function fmtLong(ms2) {
149
- var msAbs = Math.abs(ms2);
150
- if (msAbs >= d) {
151
- return plural(ms2, msAbs, d, "day");
152
- }
153
- if (msAbs >= h) {
154
- return plural(ms2, msAbs, h, "hour");
155
- }
156
- if (msAbs >= m) {
157
- return plural(ms2, msAbs, m, "minute");
158
- }
159
- if (msAbs >= s) {
160
- return plural(ms2, msAbs, s, "second");
161
- }
162
- return ms2 + " ms";
163
- }
164
- function plural(ms2, msAbs, n, name) {
165
- var isPlural = msAbs >= n * 1.5;
166
- return Math.round(ms2 / n) + " " + name + (isPlural ? "s" : "");
167
- }
168
- }
169
- });
170
- var import_ms = __toESM(require_ms());
171
- var InvertedWeakMap = class {
172
- _map;
173
- _keepAlive;
174
- _timeouts;
175
- _registry;
176
- _lifespan;
177
- constructor(option) {
178
- const { lifespan } = option;
179
- this._lifespan = lifespan;
180
- this._map = /* @__PURE__ */ new Map();
181
- this._keepAlive = /* @__PURE__ */ new Map();
182
- this._timeouts = /* @__PURE__ */ new Map();
183
- this._registry = new FinalizationRegistry((key) => {
184
- this._stopExpire(key, true);
185
- this._map.delete(key);
186
- });
187
- }
188
- clear() {
189
- this._keepAlive.clear();
190
- this._map.clear();
31
+ var LRUMap = class {
32
+ capacity;
33
+ map;
34
+ head = null;
35
+ tail = null;
36
+ /**
37
+ * Creates an instance of LRUMap.
38
+ * @param capacity The maximum number of items the cache can hold.
39
+ */
40
+ constructor(capacity) {
41
+ this.capacity = capacity;
42
+ this.map = /* @__PURE__ */ new Map();
191
43
  }
192
- delete(key) {
193
- const ref = this._map.get(key);
194
- if (ref) {
195
- const raw = ref.deref();
196
- if (raw !== void 0) {
197
- this._registry.unregister(raw);
198
- }
199
- }
200
- this._stopExpire(key, true);
201
- this._keepAlive.delete(key);
202
- return this._map.delete(key);
44
+ /**
45
+ * Promotes a node to the head of the linked list (marks as most recently used).
46
+ * @param node The node to promote.
47
+ */
48
+ promote(node) {
49
+ this.extract(node);
50
+ this.prepend(node);
203
51
  }
204
- get(key) {
205
- return this._map.get(key)?.deref();
52
+ /**
53
+ * Disconnects a node from the doubly linked list.
54
+ * @param node The node to extract.
55
+ */
56
+ extract(node) {
57
+ if (node.prev) node.prev.next = node.next;
58
+ else this.head = node.next;
59
+ if (node.next) node.next.prev = node.prev;
60
+ else this.tail = node.prev;
61
+ node.prev = null;
62
+ node.next = null;
206
63
  }
207
- has(key) {
208
- return this._map.has(key) && this.get(key) !== void 0;
64
+ /**
65
+ * Inserts a node at the head of the doubly linked list.
66
+ * @param node The node to prepend.
67
+ */
68
+ prepend(node) {
69
+ node.next = this.head;
70
+ if (this.head) this.head.prev = node;
71
+ this.head = node;
72
+ if (!this.tail) this.tail = node;
209
73
  }
74
+ /**
75
+ * Stores or updates a value by key.
76
+ * If the capacity is exceeded, the least recently used item (tail) is removed.
77
+ * @param key The key to store.
78
+ * @param value The value to store.
79
+ */
210
80
  set(key, value) {
211
- this._map.set(key, new WeakRef(value));
212
- this._registry.register(value, key);
213
- if (this._lifespan > 0) {
214
- this._stopExpire(key, true);
215
- this._startExpire(key, value);
216
- }
217
- return this;
218
- }
219
- extendExpire(key) {
220
- if (!(this._lifespan > 0)) {
81
+ const existing = this.map.get(key);
82
+ if (existing) {
83
+ existing.value = value;
84
+ this.promote(existing);
221
85
  return;
222
86
  }
223
- if (!this._keepAlive.has(key)) {
224
- return;
87
+ const newNode = { key, value, prev: null, next: null };
88
+ this.map.set(key, newNode);
89
+ this.prepend(newNode);
90
+ if (this.map.size > this.capacity && this.tail) {
91
+ this.map.delete(this.tail.key);
92
+ this.extract(this.tail);
225
93
  }
226
- this._stopExpire(key, false);
227
- this._startExpire(key, this._keepAlive.get(key));
228
94
  }
229
- _startExpire(key, value) {
230
- this._keepAlive.set(key, value);
231
- this._timeouts.set(key, setTimeout(() => {
232
- this._keepAlive.delete(key);
233
- }, this._lifespan));
95
+ /**
96
+ * Retrieves a value by key.
97
+ * Accessing the item moves it to the "most recently used" position.
98
+ * @param key The key to look for.
99
+ * @returns The value associated with the key, or undefined if not found.
100
+ */
101
+ get(key) {
102
+ const node = this.map.get(key);
103
+ if (!node) return void 0;
104
+ this.promote(node);
105
+ return node.value;
234
106
  }
235
- _stopExpire(key, removeKeepAlive) {
236
- if (!this._timeouts.has(key)) {
237
- return;
238
- }
239
- const timeout = this._timeouts.get(key);
240
- this._timeouts.delete(key);
241
- clearTimeout(timeout);
242
- if (removeKeepAlive) {
243
- this._keepAlive.delete(key);
107
+ /**
108
+ * Checks if a key exists in the cache without changing its access order.
109
+ * @param key The key to check.
110
+ * @returns True if the key exists, false otherwise.
111
+ */
112
+ has(key) {
113
+ return this.map.has(key);
114
+ }
115
+ /**
116
+ * Removes a key and its associated value from the cache.
117
+ * @param key The key to remove.
118
+ * @returns True if the key was found and removed, false otherwise.
119
+ */
120
+ delete(key) {
121
+ const node = this.map.get(key);
122
+ if (!node) return false;
123
+ this.extract(node);
124
+ this.map.delete(key);
125
+ return true;
126
+ }
127
+ /**
128
+ * Returns an iterator of keys in the order of most recently used to least recently used.
129
+ * @returns An iterable iterator of keys.
130
+ */
131
+ *keys() {
132
+ let current = this.head;
133
+ while (current) {
134
+ yield current.key;
135
+ current = current.next;
244
136
  }
245
137
  }
138
+ /**
139
+ * Returns the current number of items in the cache.
140
+ */
246
141
  get size() {
247
- return this._map.size;
142
+ return this.map.size;
248
143
  }
249
- keys() {
250
- return this._map.keys();
144
+ /**
145
+ * Clears all items from the cache.
146
+ */
147
+ clear() {
148
+ this.map.clear();
149
+ this.head = null;
150
+ this.tail = null;
251
151
  }
252
152
  };
253
153
  var CacheEntanglement = class {
254
154
  creation;
255
155
  beforeUpdateHook;
256
- lifespan;
156
+ capacity;
257
157
  dependencies;
258
158
  caches;
259
159
  parameters;
@@ -264,15 +164,15 @@ var CacheEntanglement = class {
264
164
  option = option ?? {};
265
165
  const {
266
166
  dependencies,
267
- lifespan,
167
+ capacity,
268
168
  beforeUpdateHook
269
169
  } = option;
270
170
  this.creation = creation;
271
171
  this.beforeUpdateHook = beforeUpdateHook ?? (() => {
272
172
  });
273
- this.lifespan = this._normalizeMs(lifespan ?? 0);
173
+ this.capacity = capacity ?? 100;
274
174
  this.assignments = [];
275
- this.caches = new InvertedWeakMap({ lifespan: this.lifespan });
175
+ this.caches = new LRUMap(this.capacity);
276
176
  this.parameters = /* @__PURE__ */ new Map();
277
177
  this.dependencies = dependencies ?? {};
278
178
  this.dependencyProperties = Object.keys(this.dependencies);
@@ -284,12 +184,6 @@ var CacheEntanglement = class {
284
184
  }
285
185
  }
286
186
  }
287
- _normalizeMs(time) {
288
- if (typeof time === "string") {
289
- return (0, import_ms.default)(time);
290
- }
291
- return time;
292
- }
293
187
  bubbleUpdateSignal(key) {
294
188
  this.updateRequirements.add(key);
295
189
  for (let i = 0, len = this.assignments.length; i < len; i++) {
@@ -446,8 +340,6 @@ var CacheEntanglementSync = class extends CacheEntanglement {
446
340
  cache(key, ...parameter) {
447
341
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
448
342
  this.resolve(key, ...parameter);
449
- } else {
450
- this.caches.extendExpire(key);
451
343
  }
452
344
  return this.caches.get(key);
453
345
  }
@@ -502,8 +394,6 @@ var CacheEntanglementAsync = class extends CacheEntanglement {
502
394
  async cache(key, ...parameter) {
503
395
  if (!this.caches.has(key) || this.updateRequirements.has(key)) {
504
396
  await this.update(key, ...parameter);
505
- } else {
506
- this.caches.extendExpire(key);
507
397
  }
508
398
  return this.caches.get(key);
509
399
  }
@@ -591,7 +481,7 @@ var BPTree = class {
591
481
  const regexp = new RegExp(`^${pattern}$`, "i");
592
482
  return regexp;
593
483
  }, {
594
- lifespan: this.option.lifespan ?? "3m"
484
+ capacity: this.option.capacity ?? 1e3
595
485
  });
596
486
  }
597
487
  ensureValues(v) {
@@ -684,7 +574,7 @@ var BPTreeSync = class extends BPTree {
684
574
  return new CacheEntanglementSync((key) => {
685
575
  return this.strategy.read(key);
686
576
  }, {
687
- lifespan: this.option.lifespan ?? "3m"
577
+ capacity: this.option.capacity ?? 1e3
688
578
  });
689
579
  }
690
580
  getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -1266,17 +1156,295 @@ var BPTreeSync = class extends BPTree {
1266
1156
  }
1267
1157
  };
1268
1158
 
1159
+ // node_modules/ryoiki/dist/esm/index.mjs
1160
+ var Ryoiki = class _Ryoiki {
1161
+ readings;
1162
+ writings;
1163
+ readQueue;
1164
+ writeQueue;
1165
+ static async CatchError(promise) {
1166
+ return await promise.then((v) => [void 0, v]).catch((err) => [err]);
1167
+ }
1168
+ static IsRangeOverlap(a, b) {
1169
+ const [start1, end1] = a;
1170
+ const [start2, end2] = b;
1171
+ if (end1 <= start2 || end2 <= start1) {
1172
+ return false;
1173
+ }
1174
+ return true;
1175
+ }
1176
+ static ERR_ALREADY_EXISTS(lockId) {
1177
+ return new Error(`The '${lockId}' task already existing in queue or running.`);
1178
+ }
1179
+ static ERR_NOT_EXISTS(lockId) {
1180
+ return new Error(`The '${lockId}' task not existing in task queue.`);
1181
+ }
1182
+ static ERR_TIMEOUT(lockId, timeout) {
1183
+ return new Error(`The task with ID '${lockId}' failed to acquire the lock within the timeout(${timeout}ms).`);
1184
+ }
1185
+ /**
1186
+ * Constructs a new instance of the Ryoiki class.
1187
+ */
1188
+ constructor() {
1189
+ this.readings = /* @__PURE__ */ new Map();
1190
+ this.writings = /* @__PURE__ */ new Map();
1191
+ this.readQueue = /* @__PURE__ */ new Map();
1192
+ this.writeQueue = /* @__PURE__ */ new Map();
1193
+ }
1194
+ /**
1195
+ * Creates a range based on a start value and length.
1196
+ * @param start - The starting value of the range.
1197
+ * @param length - The length of the range.
1198
+ * @returns A range tuple [start, start + length].
1199
+ */
1200
+ range(start, length) {
1201
+ return [start, start + length];
1202
+ }
1203
+ rangeOverlapping(tasks, range) {
1204
+ return Array.from(tasks.values()).some((t) => _Ryoiki.IsRangeOverlap(t.range, range));
1205
+ }
1206
+ isSameRange(a, b) {
1207
+ const [a1, a2] = a;
1208
+ const [b1, b2] = b;
1209
+ return a1 === b1 && a2 === b2;
1210
+ }
1211
+ fetchUnitAndRun(queue, workspaces) {
1212
+ for (const [id, unit] of queue) {
1213
+ if (!unit.condition()) {
1214
+ continue;
1215
+ }
1216
+ this._alloc(queue, workspaces, id);
1217
+ }
1218
+ }
1219
+ _handleOverload(args, handlers, argPatterns) {
1220
+ for (const [key, pattern] of Object.entries(argPatterns)) {
1221
+ if (this._matchArgs(args, pattern)) {
1222
+ return handlers[key](...args);
1223
+ }
1224
+ }
1225
+ throw new Error("Invalid arguments");
1226
+ }
1227
+ _matchArgs(args, pattern) {
1228
+ return args.every((arg, index) => {
1229
+ const expectedType = pattern[index];
1230
+ if (expectedType === void 0) return typeof arg === "undefined";
1231
+ if (expectedType === Function) return typeof arg === "function";
1232
+ if (expectedType === Number) return typeof arg === "number";
1233
+ if (expectedType === Array) return Array.isArray(arg);
1234
+ return false;
1235
+ });
1236
+ }
1237
+ _createRandomId() {
1238
+ const timestamp = Date.now().toString(36);
1239
+ const random = Math.random().toString(36).substring(2);
1240
+ return `${timestamp}${random}`;
1241
+ }
1242
+ _alloc(queue, workspaces, lockId) {
1243
+ const unit = queue.get(lockId);
1244
+ if (!unit) {
1245
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1246
+ }
1247
+ workspaces.set(lockId, unit);
1248
+ queue.delete(lockId);
1249
+ unit.alloc();
1250
+ }
1251
+ _free(workspaces, lockId) {
1252
+ const unit = workspaces.get(lockId);
1253
+ if (!unit) {
1254
+ throw _Ryoiki.ERR_NOT_EXISTS(lockId);
1255
+ }
1256
+ workspaces.delete(lockId);
1257
+ unit.free();
1258
+ }
1259
+ _lock(queue, range, timeout, task, condition) {
1260
+ return new Promise((resolve, reject) => {
1261
+ let timeoutId = null;
1262
+ if (timeout >= 0) {
1263
+ timeoutId = setTimeout(() => {
1264
+ reject(_Ryoiki.ERR_TIMEOUT(id, timeout));
1265
+ }, timeout);
1266
+ }
1267
+ const id = this._createRandomId();
1268
+ const alloc = async () => {
1269
+ if (timeoutId !== null) {
1270
+ clearTimeout(timeoutId);
1271
+ }
1272
+ const [err, v] = await _Ryoiki.CatchError(task(id));
1273
+ if (err) reject(err);
1274
+ else resolve(v);
1275
+ };
1276
+ const fetch = () => {
1277
+ this.fetchUnitAndRun(this.readQueue, this.readings);
1278
+ this.fetchUnitAndRun(this.writeQueue, this.writings);
1279
+ };
1280
+ queue.set(id, { id, range, condition, alloc, free: fetch });
1281
+ fetch();
1282
+ });
1283
+ }
1284
+ _checkWorking(range, workspaces) {
1285
+ let isLocked = false;
1286
+ for (const lock of workspaces.values()) {
1287
+ if (_Ryoiki.IsRangeOverlap(range, lock.range)) {
1288
+ isLocked = true;
1289
+ break;
1290
+ }
1291
+ }
1292
+ return isLocked;
1293
+ }
1294
+ /**
1295
+ * Checks if there is any active read lock within the specified range.
1296
+ * @param range The range to check for active read locks.
1297
+ * @returns `true` if there is an active read lock within the range, `false` otherwise.
1298
+ */
1299
+ isReading(range) {
1300
+ return this._checkWorking(range, this.readings);
1301
+ }
1302
+ /**
1303
+ * Checks if there is any active write lock within the specified range.
1304
+ * @param range The range to check for active write locks.
1305
+ * @returns `true` if there is an active write lock within the range, `false` otherwise.
1306
+ */
1307
+ isWriting(range) {
1308
+ return this._checkWorking(range, this.writings);
1309
+ }
1310
+ /**
1311
+ * Checks if a read lock can be acquired within the specified range.
1312
+ * @param range The range to check for read lock availability.
1313
+ * @returns `true` if a read lock can be acquired, `false` otherwise.
1314
+ */
1315
+ canRead(range) {
1316
+ const writing = this.isWriting(range);
1317
+ return !writing;
1318
+ }
1319
+ /**
1320
+ * Checks if a write lock can be acquired within the specified range.
1321
+ * @param range The range to check for write lock availability.
1322
+ * @returns `true` if a write lock can be acquired, `false` otherwise.
1323
+ */
1324
+ canWrite(range) {
1325
+ const reading = this.isReading(range);
1326
+ const writing = this.isWriting(range);
1327
+ return !reading && !writing;
1328
+ }
1329
+ /**
1330
+ * Internal implementation of the read lock. Handles both overloads.
1331
+ * @template T - The return type of the task.
1332
+ * @param arg0 - Either a range or a task callback.
1333
+ * If a range is provided, the task is the second argument.
1334
+ * @param arg1 - The task to execute, required if a range is provided.
1335
+ * @param arg2 - The timeout for acquiring the lock.
1336
+ * If the lock cannot be acquired within this period, an error will be thrown.
1337
+ * If this value is not provided, no timeout will be set.
1338
+ * @returns A promise resolving to the result of the task execution.
1339
+ */
1340
+ readLock(arg0, arg1, arg2) {
1341
+ const [range, task, timeout] = this._handleOverload(
1342
+ [arg0, arg1, arg2],
1343
+ {
1344
+ rangeTask: (range2, task2) => [range2, task2, -1],
1345
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1346
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
1347
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1348
+ },
1349
+ {
1350
+ task: [Function],
1351
+ taskTimeout: [Function, Number],
1352
+ rangeTask: [Array, Function],
1353
+ rangeTaskTimeout: [Array, Function, Number]
1354
+ }
1355
+ );
1356
+ return this._lock(
1357
+ this.readQueue,
1358
+ range,
1359
+ timeout,
1360
+ task,
1361
+ () => !this.rangeOverlapping(this.writings, range)
1362
+ );
1363
+ }
1364
+ /**
1365
+ * Internal implementation of the write lock. Handles both overloads.
1366
+ * @template T - The return type of the task.
1367
+ * @param arg0 - Either a range or a task callback.
1368
+ * If a range is provided, the task is the second argument.
1369
+ * @param arg1 - The task to execute, required if a range is provided.
1370
+ * @param arg2 - The timeout for acquiring the lock.
1371
+ * If the lock cannot be acquired within this period, an error will be thrown.
1372
+ * If this value is not provided, no timeout will be set.
1373
+ * @returns A promise resolving to the result of the task execution.
1374
+ */
1375
+ writeLock(arg0, arg1, arg2) {
1376
+ const [range, task, timeout] = this._handleOverload(
1377
+ [arg0, arg1, arg2],
1378
+ {
1379
+ rangeTask: (range2, task2) => [range2, task2, -1],
1380
+ rangeTaskTimeout: (range2, task2, timeout2) => [range2, task2, timeout2],
1381
+ task: (task2) => [[-Infinity, Infinity], task2, -1],
1382
+ taskTimeout: (task2, timeout2) => [[-Infinity, Infinity], task2, timeout2]
1383
+ },
1384
+ {
1385
+ task: [Function],
1386
+ taskTimeout: [Function, Number],
1387
+ rangeTask: [Array, Function],
1388
+ rangeTaskTimeout: [Array, Function, Number]
1389
+ }
1390
+ );
1391
+ return this._lock(
1392
+ this.writeQueue,
1393
+ range,
1394
+ timeout,
1395
+ task,
1396
+ () => {
1397
+ return !this.rangeOverlapping(this.writings, range) && !this.rangeOverlapping(this.readings, range);
1398
+ }
1399
+ );
1400
+ }
1401
+ /**
1402
+ * Releases a read lock by its lock ID.
1403
+ * @param lockId - The unique identifier for the lock to release.
1404
+ */
1405
+ readUnlock(lockId) {
1406
+ this._free(this.readings, lockId);
1407
+ }
1408
+ /**
1409
+ * Releases a write lock by its lock ID.
1410
+ * @param lockId - The unique identifier for the lock to release.
1411
+ */
1412
+ writeUnlock(lockId) {
1413
+ this._free(this.writings, lockId);
1414
+ }
1415
+ };
1416
+
1269
1417
  // src/BPTreeAsync.ts
1270
1418
  var BPTreeAsync = class extends BPTree {
1419
+ lock;
1271
1420
  constructor(strategy, comparator, option) {
1272
1421
  super(strategy, comparator, option);
1273
1422
  this.nodes = this._createCachedNode();
1423
+ this.lock = new Ryoiki();
1274
1424
  }
1275
1425
  _createCachedNode() {
1276
1426
  return new CacheEntanglementAsync(async (key) => {
1277
1427
  return await this.strategy.read(key);
1278
1428
  }, {
1279
- lifespan: this.option.lifespan ?? "3m"
1429
+ capacity: this.option.capacity ?? 1e3
1430
+ });
1431
+ }
1432
+ async readLock(callback) {
1433
+ let lockId;
1434
+ return await this.lock.readLock(async (_lockId) => {
1435
+ lockId = _lockId;
1436
+ return await callback();
1437
+ }).finally(() => {
1438
+ this.lock.readUnlock(lockId);
1439
+ });
1440
+ }
1441
+ async writeLock(callback) {
1442
+ let lockId;
1443
+ return await this.lock.writeLock(async (_lockId) => {
1444
+ lockId = _lockId;
1445
+ return await callback();
1446
+ }).finally(() => {
1447
+ this.lock.writeUnlock(lockId);
1280
1448
  });
1281
1449
  }
1282
1450
  async getPairsRightToLeft(value, startNode, endNode, comparator) {
@@ -1722,139 +1890,153 @@ var BPTreeAsync = class extends BPTree {
1722
1890
  this._nodeDeleteBuffer.clear();
1723
1891
  }
1724
1892
  async keys(condition, filterValues) {
1725
- for (const k in condition) {
1726
- const key = k;
1727
- const value = condition[key];
1728
- const startNode = await this.verifierStartNode[key](value);
1729
- const endNode = await this.verifierEndNode[key](value);
1730
- const direction = this.verifierDirection[key];
1731
- const comparator = this.verifierMap[key];
1732
- const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1733
- if (!filterValues) {
1734
- filterValues = new Set(pairs.keys());
1735
- } else {
1736
- const intersections = /* @__PURE__ */ new Set();
1737
- for (const key2 of filterValues) {
1738
- const has = pairs.has(key2);
1739
- if (has) {
1740
- intersections.add(key2);
1893
+ return this.readLock(async () => {
1894
+ for (const k in condition) {
1895
+ const key = k;
1896
+ const value = condition[key];
1897
+ const startNode = await this.verifierStartNode[key](value);
1898
+ const endNode = await this.verifierEndNode[key](value);
1899
+ const direction = this.verifierDirection[key];
1900
+ const comparator = this.verifierMap[key];
1901
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1902
+ if (!filterValues) {
1903
+ filterValues = new Set(pairs.keys());
1904
+ } else {
1905
+ const intersections = /* @__PURE__ */ new Set();
1906
+ for (const key2 of filterValues) {
1907
+ const has = pairs.has(key2);
1908
+ if (has) {
1909
+ intersections.add(key2);
1910
+ }
1741
1911
  }
1912
+ filterValues = intersections;
1742
1913
  }
1743
- filterValues = intersections;
1744
1914
  }
1745
- }
1746
- return filterValues ?? /* @__PURE__ */ new Set([]);
1915
+ return filterValues ?? /* @__PURE__ */ new Set([]);
1916
+ });
1747
1917
  }
1748
1918
  async where(condition) {
1749
- let result = null;
1750
- for (const k in condition) {
1751
- const key = k;
1752
- const value = condition[key];
1753
- const startNode = await this.verifierStartNode[key](value);
1754
- const endNode = await this.verifierEndNode[key](value);
1755
- const direction = this.verifierDirection[key];
1756
- const comparator = this.verifierMap[key];
1757
- const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1758
- if (result === null) {
1759
- result = pairs;
1760
- } else {
1761
- const intersection = /* @__PURE__ */ new Map();
1762
- for (const [k2, v] of pairs) {
1763
- if (result.has(k2)) {
1764
- intersection.set(k2, v);
1919
+ return this.readLock(async () => {
1920
+ let result = null;
1921
+ for (const k in condition) {
1922
+ const key = k;
1923
+ const value = condition[key];
1924
+ const startNode = await this.verifierStartNode[key](value);
1925
+ const endNode = await this.verifierEndNode[key](value);
1926
+ const direction = this.verifierDirection[key];
1927
+ const comparator = this.verifierMap[key];
1928
+ const pairs = await this.getPairs(value, startNode, endNode, comparator, direction);
1929
+ if (result === null) {
1930
+ result = pairs;
1931
+ } else {
1932
+ const intersection = /* @__PURE__ */ new Map();
1933
+ for (const [k2, v] of pairs) {
1934
+ if (result.has(k2)) {
1935
+ intersection.set(k2, v);
1936
+ }
1765
1937
  }
1938
+ result = intersection;
1766
1939
  }
1767
- result = intersection;
1768
1940
  }
1769
- }
1770
- return result ?? /* @__PURE__ */ new Map();
1941
+ return result ?? /* @__PURE__ */ new Map();
1942
+ });
1771
1943
  }
1772
1944
  async insert(key, value) {
1773
- const before = await this.insertableNode(value);
1774
- this._insertAtLeaf(before, key, value);
1775
- if (before.values.length === this.order) {
1776
- const after = await this._createNode(
1777
- true,
1778
- [],
1779
- [],
1780
- true,
1781
- before.parent,
1782
- before.next,
1783
- before.id
1784
- );
1785
- const mid = Math.ceil(this.order / 2) - 1;
1786
- const beforeNext = before.next;
1787
- after.values = before.values.slice(mid + 1);
1788
- after.keys = before.keys.slice(mid + 1);
1789
- before.values = before.values.slice(0, mid + 1);
1790
- before.keys = before.keys.slice(0, mid + 1);
1791
- before.next = after.id;
1792
- if (beforeNext) {
1793
- const node = await this.getNode(beforeNext);
1794
- node.prev = after.id;
1795
- this.bufferForNodeUpdate(node);
1945
+ return this.writeLock(async () => {
1946
+ const before = await this.insertableNode(value);
1947
+ this._insertAtLeaf(before, key, value);
1948
+ if (before.values.length === this.order) {
1949
+ const after = await this._createNode(
1950
+ true,
1951
+ [],
1952
+ [],
1953
+ true,
1954
+ before.parent,
1955
+ before.next,
1956
+ before.id
1957
+ );
1958
+ const mid = Math.ceil(this.order / 2) - 1;
1959
+ const beforeNext = before.next;
1960
+ after.values = before.values.slice(mid + 1);
1961
+ after.keys = before.keys.slice(mid + 1);
1962
+ before.values = before.values.slice(0, mid + 1);
1963
+ before.keys = before.keys.slice(0, mid + 1);
1964
+ before.next = after.id;
1965
+ if (beforeNext) {
1966
+ const node = await this.getNode(beforeNext);
1967
+ node.prev = after.id;
1968
+ this.bufferForNodeUpdate(node);
1969
+ }
1970
+ await this._insertInParent(before, after.values[0], after);
1971
+ this.bufferForNodeUpdate(before);
1796
1972
  }
1797
- await this._insertInParent(before, after.values[0], after);
1798
- this.bufferForNodeUpdate(before);
1799
- }
1800
- await this.commitHeadBuffer();
1801
- await this.commitNodeCreateBuffer();
1802
- await this.commitNodeUpdateBuffer();
1973
+ await this.commitHeadBuffer();
1974
+ await this.commitNodeCreateBuffer();
1975
+ await this.commitNodeUpdateBuffer();
1976
+ });
1803
1977
  }
1804
1978
  async delete(key, value) {
1805
- const node = await this.insertableNode(value);
1806
- let i = node.values.length;
1807
- while (i--) {
1808
- const nValue = node.values[i];
1809
- if (this.comparator.isSame(value, nValue)) {
1810
- const keys = node.keys[i];
1811
- if (keys.includes(key)) {
1812
- if (keys.length > 1) {
1813
- keys.splice(keys.indexOf(key), 1);
1814
- this.bufferForNodeUpdate(node);
1815
- } else if (node.id === this.root.id) {
1816
- node.values.splice(i, 1);
1817
- node.keys.splice(i, 1);
1818
- this.bufferForNodeUpdate(node);
1819
- } else {
1820
- keys.splice(keys.indexOf(key), 1);
1821
- node.keys.splice(i, 1);
1822
- node.values.splice(node.values.indexOf(value), 1);
1823
- await this._deleteEntry(node, key, value);
1824
- this.bufferForNodeUpdate(node);
1979
+ return this.writeLock(async () => {
1980
+ const node = await this.insertableNode(value);
1981
+ let i = node.values.length;
1982
+ while (i--) {
1983
+ const nValue = node.values[i];
1984
+ if (this.comparator.isSame(value, nValue)) {
1985
+ const keys = node.keys[i];
1986
+ if (keys.includes(key)) {
1987
+ if (keys.length > 1) {
1988
+ keys.splice(keys.indexOf(key), 1);
1989
+ this.bufferForNodeUpdate(node);
1990
+ } else if (node.id === this.root.id) {
1991
+ node.values.splice(i, 1);
1992
+ node.keys.splice(i, 1);
1993
+ this.bufferForNodeUpdate(node);
1994
+ } else {
1995
+ keys.splice(keys.indexOf(key), 1);
1996
+ node.keys.splice(i, 1);
1997
+ node.values.splice(node.values.indexOf(value), 1);
1998
+ await this._deleteEntry(node, key, value);
1999
+ this.bufferForNodeUpdate(node);
2000
+ }
1825
2001
  }
1826
2002
  }
1827
2003
  }
1828
- }
1829
- await this.commitHeadBuffer();
1830
- await this.commitNodeCreateBuffer();
1831
- await this.commitNodeUpdateBuffer();
1832
- await this.commitNodeDeleteBuffer();
2004
+ await this.commitHeadBuffer();
2005
+ await this.commitNodeCreateBuffer();
2006
+ await this.commitNodeUpdateBuffer();
2007
+ await this.commitNodeDeleteBuffer();
2008
+ });
1833
2009
  }
1834
2010
  async exists(key, value) {
1835
- const node = await this.insertableNode(value);
1836
- for (let i = 0, len = node.values.length; i < len; i++) {
1837
- const nValue = node.values[i];
1838
- if (this.comparator.isSame(value, nValue)) {
1839
- const keys = node.keys[i];
1840
- return keys.includes(key);
2011
+ return this.readLock(async () => {
2012
+ const node = await this.insertableNode(value);
2013
+ for (let i = 0, len = node.values.length; i < len; i++) {
2014
+ const nValue = node.values[i];
2015
+ if (this.comparator.isSame(value, nValue)) {
2016
+ const keys = node.keys[i];
2017
+ return keys.includes(key);
2018
+ }
1841
2019
  }
1842
- }
1843
- return false;
2020
+ return false;
2021
+ });
1844
2022
  }
1845
2023
  async setHeadData(data) {
1846
- this.strategy.head.data = data;
1847
- this._strategyDirty = true;
1848
- await this.commitHeadBuffer();
2024
+ return this.writeLock(async () => {
2025
+ this.strategy.head.data = data;
2026
+ this._strategyDirty = true;
2027
+ await this.commitHeadBuffer();
2028
+ });
1849
2029
  }
1850
2030
  async forceUpdate() {
1851
- const keys = [...this.nodes.keys()];
1852
- this.nodes.clear();
1853
- await this.init();
1854
- for (const key of keys) {
1855
- await this.getNode(key);
1856
- }
1857
- return keys.length;
2031
+ return this.readLock(async () => {
2032
+ const keys = [...this.nodes.keys()];
2033
+ this.nodes.clear();
2034
+ await this.init();
2035
+ for (const key of keys) {
2036
+ await this.getNode(key);
2037
+ }
2038
+ return keys.length;
2039
+ });
1858
2040
  }
1859
2041
  };
1860
2042