serializable-bptree 5.2.0 → 6.0.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 +27 -18
- package/dist/cjs/index.cjs +508 -185
- package/dist/esm/index.mjs +508 -185
- package/dist/types/BPTreeAsync.d.ts +3 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
|
|
16
16
|
class FileStoreStrategySync extends SerializeStrategySync<K, V> {
|
|
17
17
|
id(): string {
|
|
18
|
-
return
|
|
18
|
+
return crypto.randomUUID()
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
read(id: string): BPTreeNode<K, V> {
|
|
@@ -105,10 +105,19 @@ import {
|
|
|
105
105
|
ValueComparator,
|
|
106
106
|
NumericComparator,
|
|
107
107
|
StringComparator
|
|
108
|
-
} from 'https://cdn.jsdelivr.
|
|
108
|
+
} from 'https://cdn.jsdelivr.com/npm/serializable-bptree@6/+esm'
|
|
109
109
|
</script>
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
+
## Migration from v5.x.x to v6.0.0
|
|
113
|
+
|
|
114
|
+
Version 6.0.0 includes a critical fix for how internal nodes are sorted.
|
|
115
|
+
|
|
116
|
+
> [!IMPORTANT]
|
|
117
|
+
> **Breaking Changes & Incompatibility**
|
|
118
|
+
> In previous versions, internal nodes were not strictly sorted by value magnitude, which could lead to incorrect traversals and failed queries (especially for the last nodes in a branch).
|
|
119
|
+
> v6.0.0 enforces strict value sorting. **Data structures created with v5.x.x or earlier may be incompatible** with v6.0.0 if they contain unsorted internal nodes. It is highly recommended to rebuild your tree from scratch when upgrading.
|
|
120
|
+
|
|
112
121
|
## Conceptualization
|
|
113
122
|
|
|
114
123
|
### Value comparator
|
|
@@ -199,21 +208,11 @@ What does this method mean? And why do we need to construct such a method?
|
|
|
199
208
|
|
|
200
209
|
When a node is created in the B+tree, the node needs a unique value to represent itself. This is the **node.id** attribute, and you can specify this attribute yourself.
|
|
201
210
|
|
|
202
|
-
Typically, such an **id** value
|
|
211
|
+
Typically, such an **id** value can be a unique string like a UUID. Below is an example of usage:
|
|
203
212
|
|
|
204
213
|
```typescript
|
|
205
214
|
id(isLeaf: boolean): string {
|
|
206
|
-
|
|
207
|
-
this.setHeadData('index', current+1)
|
|
208
|
-
return current.toString()
|
|
209
|
-
}
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
Additionally, there is a more dev-friendly usage of this code.
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
id(isLeaf: boolean): string {
|
|
216
|
-
return this.autoIncrement('index', 1).toString()
|
|
215
|
+
return crypto.randomUUID()
|
|
217
216
|
}
|
|
218
217
|
```
|
|
219
218
|
|
|
@@ -415,7 +414,7 @@ import {
|
|
|
415
414
|
|
|
416
415
|
class FileStoreStrategyAsync extends SerializeStrategyAsync<K, V> {
|
|
417
416
|
async id(isLeaf: boolean): Promise<string> {
|
|
418
|
-
return
|
|
417
|
+
return crypto.randomUUID()
|
|
419
418
|
}
|
|
420
419
|
|
|
421
420
|
async read(id: string): Promise<BPTreeNode<K, V>> {
|
|
@@ -473,13 +472,23 @@ The implementation method for asynchronous operations is not significantly diffe
|
|
|
473
472
|
|
|
474
473
|
### Synchronization Issue
|
|
475
474
|
|
|
476
|
-
The serializable-bptree minimizes file I/O by storing loaded nodes in-memory. This approach works
|
|
475
|
+
The serializable-bptree minimizes file I/O by storing loaded nodes in-memory (caching). This approach works perfectly when a single tree instance is used for a given storage.
|
|
476
|
+
|
|
477
|
+
However, if **multiple BPTree instances** (e.g., across different processes or servers) read from and write to a **single shared storage**, data inconsistency can occur. This is because each instance maintains its own independent in-memory cache, and changes made by one instance are not automatically reflected in the others.
|
|
477
478
|
|
|
478
|
-
To solve this problem,
|
|
479
|
+
To solve this problem, you must synchronize the cached nodes across all instances. The `forceUpdate` method can be used to refresh the nodes cached in a tree instance. When one instance saves data to the shared storage, you should implement a signaling mechanism (e.g., via Pub/Sub or WebSockets) to notify other instances that a node has been updated. Upon receiving this signal, the other instances should call the `forceUpdate` method to ensure they are working with the latest data.
|
|
479
480
|
|
|
480
481
|
### Concurrency Issue in Asynchronous Trees
|
|
481
482
|
|
|
482
|
-
This issue occurs only in asynchronous trees and can also occur in a 1:1 relationship between remote storage and client.
|
|
483
|
+
This issue occurs only in asynchronous trees and can also occur in a 1:1 relationship between remote storage and client.
|
|
484
|
+
|
|
485
|
+
Since version 5.x.x, **serializable-bptree** provides a built-in read/write lock for the `BPTreeAsync` class to prevent data inconsistency during concurrent operations. Calling public methods like `insert`, `delete`, `where`, `exists`, `keys`, `setHeadData`, and `forceUpdate` will automatically acquire the appropriate lock.
|
|
486
|
+
|
|
487
|
+
However, please be aware of the following technical limitations:
|
|
488
|
+
- **Locking is only applied to public methods**: The internal `protected` methods (e.g., `_insertInParent`, `_deleteEntry`, etc.) do not automatically acquire locks.
|
|
489
|
+
- **Inheritance Caution**: If you extend the `BPTreeAsync` class and call `protected` methods directly, you must manually manage the locks using `readLock` or `writeLock` to ensure data integrity.
|
|
490
|
+
|
|
491
|
+
Despite these safeguards, it is still recommended to avoid unnecessary concurrent operations whenever possible to maintain optimal performance and predictability.
|
|
483
492
|
|
|
484
493
|
## LICENSE
|
|
485
494
|
|