From 1f612b7576738dda0b808253579c07bd7af442a1 Mon Sep 17 00:00:00 2001 From: Ewout Stortenbeker Date: Sat, 19 Aug 2023 09:29:45 +0200 Subject: [PATCH 1/2] Trigger single-leaf tree growth rebuilds on time Fixes #242 --- src/btree/binary-tree.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/btree/binary-tree.ts b/src/btree/binary-tree.ts index 8439368..67a9888 100644 --- a/src/btree/binary-tree.ts +++ b/src/btree/binary-tree.ts @@ -2359,6 +2359,11 @@ export class BinaryBPlusTree { throw new Error('specify options.cancelCallback to undo any changes when a rollback needs to be performed'); } + if (!leaf.parentNode) { + // This is a single-leaf tree, cannot split without rebuilding + throw new DetailedError('single-leaf-tree-split', 'Cannot split leaf because it is a single-leaf tree. Tree needs to be rebuilt'); + } + if (leaf.parentNode.entries.length >= this.info.entriesPerNode) { // TODO: TEST splitting node // throw new DetailedError('parent-node-full', `Cannot split leaf because parent node is full`); @@ -2883,10 +2888,10 @@ export class BinaryBPlusTree { // Should this entry be added to this leaf? const applyToThisLeaf = (() => { - if (leaf.entries.length > this.info.entriesPerNode) { + if (type === 'add' && leaf.entries.length >= this.info.entriesPerNode) { return false; } - // Check if the "roadsigns" in parent nodes will point to this leaf for the new key + // Check if the "roadsigns" in parent nodes point to this leaf for current key const pointsThisDirection = (node: BinaryBPlusTreeLeaf | BinaryBPlusTreeNode): boolean => { if (node.parentEntry) { // Parent node's entry has a less than connection to this node/leaf From 444c1ffd7fee6ee3538b1b7a804c85fd2ffc4ffc Mon Sep 17 00:00:00 2001 From: Ewout Stortenbeker Date: Sat, 19 Aug 2023 09:30:11 +0200 Subject: [PATCH 2/2] improved unit test --- src/storage/binary/test.spec.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/storage/binary/test.spec.ts b/src/storage/binary/test.spec.ts index 8c7166e..dce2c15 100644 --- a/src/storage/binary/test.spec.ts +++ b/src/storage/binary/test.spec.ts @@ -13,7 +13,7 @@ describe('issue', () => { await removeDB(); }); - it('#239', async () => { + it('#239 and #242', async () => { // Created for issue #239 ("TypeError when trying to add new records after removing old ones") const ref = db.ref('table'); @@ -27,12 +27,22 @@ describe('issue', () => { // remove all the added records with the query await ref.query().filter('playlistId', '==', 'playlist1').remove(); - // add new "small" dataset to the database -> error - const songIds2 = Array(10).fill(0).map((_value, index) => `id-${index}`); + // add new "large" dataset to the database -> error + const songIds2 = Array(110).fill(0).map((_value, index) => `id-${index}`); await ref.update(songIds2.reduce((obj, songId) => { obj[songId] = { playlistId: 'playlist1' }; return obj; }, {} as any)); - }); + // remove all the added records with the query + await ref.query().filter('playlistId', '==', 'playlist1').remove(); + + // add new "large" dataset to the database -> error + const songIds3 = Array(500).fill(0).map((_value, index) => `id-${index}`); + await ref.update(songIds3.reduce((obj, songId) => { + obj[songId] = { playlistId: 'playlist1' }; + return obj; + }, {} as any)); + + }, 30e6); });