Skip to content

Commit 21cd0c8

Browse files
committed
feat: Replace rbtree with btree
1 parent 343c3ab commit 21cd0c8

File tree

3 files changed

+3719
-3720
lines changed

3 files changed

+3719
-3720
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
"@collectable/core": "^5.0.1",
2626
"@collectable/red-black-tree": "^5.0.1",
2727
"lodash": "^4.17.21",
28-
"regexp-i18n": "^1.3.2"
28+
"regexp-i18n": "^1.3.2",
29+
"sorted-btree": "^1.5.0"
2930
},
3031
"sideEffects": [
3132
"./src/Promise.ts"

src/InMemoryProvider.ts

+45-52
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,9 @@ import {
5151
TransactionToken,
5252
TransactionLockHelper,
5353
} from "./TransactionLockHelper";
54-
import {
55-
empty,
56-
RedBlackTreeStructure,
57-
set,
58-
iterateFromIndex,
59-
iterateKeysFromFirst,
60-
get,
61-
iterateKeysFromLast,
62-
has,
63-
remove,
64-
iterateFromFirst,
65-
} from "@collectable/red-black-tree";
54+
55+
import BTree from "sorted-btree";
56+
6657
export interface StoreData {
6758
data: Map<string, ItemType>;
6859
indices: Map<string, InMemoryIndex>;
@@ -448,18 +439,15 @@ class InMemoryStore implements DbStore {
448439

449440
// Note: Currently maintains nothing interesting -- rebuilds the results every time from scratch. Scales like crap.
450441
class InMemoryIndex extends DbIndexFTSFromRangeQueries {
451-
private _rbIndex: RedBlackTreeStructure<string, ItemType[]>;
442+
private _bTreeIndex: BTree<string, ItemType[]>;
452443
private _trans?: InMemoryTransaction;
453444
constructor(
454445
_mergedData: Map<string, ItemType>,
455446
indexSchema: IndexSchema,
456447
primaryKeyPath: KeyPathType
457448
) {
458449
super(indexSchema, primaryKeyPath);
459-
this._rbIndex = empty<string, ItemType[]>(
460-
(a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0),
461-
true
462-
);
450+
this._bTreeIndex = new BTree();
463451
this.put(values(_mergedData), true);
464452
}
465453

@@ -504,12 +492,12 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
504492

505493
each(keys, (key) => {
506494
// For non-unique indexes we want to overwrite
507-
if (!this.isUniqueIndex() && has(key, this._rbIndex)) {
508-
const existingItems = get(key, this._rbIndex)!!! as ItemType[];
495+
if (!this.isUniqueIndex() && this._bTreeIndex.has(key)) {
496+
const existingItems = this._bTreeIndex.get(key)!!! as ItemType[];
509497
existingItems.push(item);
510-
set<string, ItemType[]>(key, existingItems, this._rbIndex);
498+
this._bTreeIndex.set(key, existingItems);
511499
} else {
512-
set(key, [item], this._rbIndex);
500+
this._bTreeIndex.set(key, [item]);
513501
}
514502
});
515503
});
@@ -534,7 +522,7 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
534522

535523
let values = [] as ItemType[];
536524
for (const key of joinedKeys) {
537-
values.push(get(key, this._rbIndex) as ItemType[]);
525+
values.push(this._bTreeIndex.get(key) as ItemType[]);
538526
}
539527
return Promise.resolve(compact(flatten(values)));
540528
}
@@ -548,9 +536,9 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
548536
}
549537

550538
if (typeof key === "string") {
551-
remove(key, this._rbIndex);
539+
this._bTreeIndex.delete(key);
552540
} else {
553-
const idxItems = get(key.idxKey, this._rbIndex);
541+
const idxItems = this._bTreeIndex.get(key.idxKey);
554542
if (!idxItems) {
555543
return;
556544
}
@@ -567,9 +555,9 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
567555
// otherwise, update the index value with the new array
568556
// sans the primary key item
569557
if (idxItemsWithoutItem?.length === 0) {
570-
remove(key.idxKey, this._rbIndex);
558+
this._bTreeIndex.delete(key.idxKey);
571559
} else {
572-
set<string, ItemType[]>(key.idxKey, idxItemsWithoutItem, this._rbIndex);
560+
this._bTreeIndex.set(key.idxKey, idxItemsWithoutItem);
573561
}
574562
}
575563
}
@@ -582,24 +570,27 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
582570
const definedLimit = limit
583571
? limit
584572
: this.isUniqueIndex()
585-
? this._rbIndex._size
573+
? this._bTreeIndex._size
586574
: MAX_COUNT;
587575
let definedOffset = offset ? offset : 0;
588576
const data = new Array<ItemType>(definedLimit);
589577
const reverse =
590578
reverseOrSortOrder === true ||
591579
reverseOrSortOrder === QuerySortOrder.Reverse;
592580
// when index is not unique, we cannot use offset as a starting index
593-
const iterator = iterateFromIndex(
594-
reverse,
595-
this.isUniqueIndex() ? definedOffset : 0,
596-
this._rbIndex
597-
);
581+
let skip = this.isUniqueIndex() ? definedOffset : 0;
582+
const iterator = reverse
583+
? this._bTreeIndex.entriesReversed()
584+
: this._bTreeIndex.entries();
598585
let i = 0;
599586
for (const item of iterator) {
587+
if (skip > 0) {
588+
skip--;
589+
continue;
590+
}
600591
// when index is not unique, each node may contain multiple items
601592
if (!this.isUniqueIndex()) {
602-
let count = item.value.length;
593+
let count = item[1].length;
603594
const minOffsetCount = Math.min(count, definedOffset);
604595
count -= minOffsetCount;
605596
definedOffset -= minOffsetCount;
@@ -609,9 +600,9 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
609600
}
610601

611602
const values = this._getKeyValues(
612-
item.key,
603+
item[0],
613604
definedLimit - i,
614-
item.value.length - count,
605+
item[1].length - count,
615606
reverse
616607
);
617608

@@ -621,7 +612,7 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
621612

622613
i += values.length;
623614
} else {
624-
data[i] = item.value[0];
615+
data[i] = item[1][0];
625616
i++;
626617
}
627618

@@ -671,16 +662,17 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
671662
limit = limit
672663
? limit
673664
: this.isUniqueIndex()
674-
? this._rbIndex._size
665+
? this._bTreeIndex._size
675666
: MAX_COUNT;
676667
offset = offset ? offset : 0;
677668
const keyLow = serializeKeyToString(keyLowRange, this._keyPath);
678669
const keyHigh = serializeKeyToString(keyHighRange, this._keyPath);
679670
const iterator = reverse
680-
? iterateKeysFromLast(this._rbIndex)
681-
: iterateKeysFromFirst(this._rbIndex);
671+
? this._bTreeIndex.entriesReversed()
672+
: this._bTreeIndex.entries();
682673
let values = [] as ItemType[];
683-
for (const key of iterator) {
674+
for (const entry of iterator) {
675+
const key = entry[0];
684676
if (
685677
(key > keyLow || (key === keyLow && !lowRangeExclusive)) &&
686678
(key < keyHigh || (key === keyHigh && !highRangeExclusive))
@@ -690,7 +682,7 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
690682
offset--;
691683
continue;
692684
} else {
693-
const idxValues = get(key, this._rbIndex) as ItemType[];
685+
const idxValues = this._bTreeIndex.get(key) as ItemType[];
694686
offset -= idxValues.length;
695687
// if offset >= 0, we skipped just enough, or we still need to skip more
696688
// if offset < 0, we need to get some of the values from the index
@@ -704,7 +696,7 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
704696
}
705697

706698
if (this.isUniqueIndex()) {
707-
values = values.concat(get(key, this._rbIndex) as ItemType[]);
699+
values = values.concat(this._bTreeIndex.get(key) as ItemType[]);
708700
} else {
709701
values = values.concat(
710702
this._getKeyValues(
@@ -767,7 +759,7 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
767759
if (limit <= 0) {
768760
return [];
769761
}
770-
const idxValues = get(key, this._rbIndex) as ItemType[];
762+
const idxValues = this._bTreeIndex.get(key) as ItemType[];
771763

772764
// get may return undefined, if the key is not found
773765
if (!idxValues) {
@@ -801,9 +793,10 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
801793
): string[] {
802794
const keyLow = serializeKeyToString(keyLowRange, this._keyPath);
803795
const keyHigh = serializeKeyToString(keyHighRange, this._keyPath);
804-
const iterator = iterateKeysFromFirst(this._rbIndex);
796+
const iterator = this._bTreeIndex.entries();
805797
const keys = [];
806-
for (const key of iterator) {
798+
for (const entry of iterator) {
799+
const key = entry[0];
807800
if (
808801
(key > keyLow || (key === keyLow && !lowRangeExclusive)) &&
809802
(key < keyHigh || (key === keyHigh && !highRangeExclusive))
@@ -823,17 +816,17 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
823816
): number {
824817
const keyLow = serializeKeyToString(keyLowRange, this._keyPath);
825818
const keyHigh = serializeKeyToString(keyHighRange, this._keyPath);
826-
const iterator = iterateFromFirst(this._rbIndex);
819+
const iterator = this._bTreeIndex.entries();
827820
let keyCount = 0;
828821
for (const item of iterator) {
829822
if (
830-
(item.key > keyLow || (item.key === keyLow && !lowRangeExclusive)) &&
831-
(item.key < keyHigh || (item.key === keyHigh && !highRangeExclusive))
823+
(item[0] > keyLow || (item[0] === keyLow && !lowRangeExclusive)) &&
824+
(item[0] < keyHigh || (item[0] === keyHigh && !highRangeExclusive))
832825
) {
833826
if (this.isUniqueIndex()) {
834827
keyCount++;
835828
} else {
836-
keyCount += item.value.length;
829+
keyCount += item[1].length;
837830
}
838831
}
839832
}
@@ -842,13 +835,13 @@ class InMemoryIndex extends DbIndexFTSFromRangeQueries {
842835

843836
countAll(): Promise<number> {
844837
if (this.isUniqueIndex()) {
845-
return Promise.resolve(this._rbIndex._size);
838+
return Promise.resolve(this._bTreeIndex._size);
846839
} else {
847840
const keyCount = attempt(() => {
848-
const iterator = iterateFromFirst(this._rbIndex);
841+
const iterator = this._bTreeIndex.entries();
849842
let keyCount = 0;
850843
for (const item of iterator) {
851-
keyCount += item.value.length;
844+
keyCount += item[1].length;
852845
}
853846
return keyCount;
854847
});

0 commit comments

Comments
 (0)