Skip to content

Commit

Permalink
feat(mergeUp): for SBFNode + getFillStatus + fix for root
Browse files Browse the repository at this point in the history
Now root correctly hold data at starts in an identifiers array. Will make our test fails
  • Loading branch information
Alex-Werner committed Oct 3, 2019
1 parent d34784d commit 6072fa5
Show file tree
Hide file tree
Showing 26 changed files with 377 additions and 102 deletions.
14 changes: 2 additions & 12 deletions src/adapters/MemoryAdapter/methods/removeDocument.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
async function removeDocument(identifier){
console.log(identifier)
console.log(identifier)
console.log(identifier)
console.log(identifier)
console.log(identifier)
if(!this.documents[identifier]){
console.log(this.documents[identifier])
console.log(this.documents[identifier])
console.log(this.documents[identifier])
console.log(this.documents[identifier])
console.log(this.documents[identifier])
console.log(this.documents[identifier])
if(this.documents[identifier]){
delete this.documents[identifier]
}
}
module.exports = removeDocument
7 changes: 4 additions & 3 deletions src/adapters/MemoryAdapter/methods/removeInLeaf.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
async function removeInLeaf(leafName, identifier) {
const identifiers = [];
if (this.leafs[leafName]) {
if (!this.leafs[leafName]) {
throw new Error('Trying to remove in unknown leaf id')
}
const index = this.leafs[leafName].meta.identifiers.indexOf(identifier);
if (index >= 0) {
this.leafs[leafName].meta.size -= 1;
this.leafs[leafName].meta.identifiers.splice(index, 1);
this.leafs[leafName].data.keys.splice(index, 1);
identifiers.push(identifier);
identifiers.push({identifier, index});
}
}
return identifiers;
}

Expand Down
1 change: 1 addition & 0 deletions src/types/SBFLeaf/methods/isFillFactorFilled.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ async function isFillFactorFilled(){
}
try {
const leaf = await adapter.openLeaf(this.id);

return leaf.meta.size>=(order*fillFactor);

}catch (e) {
Expand Down
28 changes: 26 additions & 2 deletions src/types/SBFLeaf/methods/mergeWithSiblings.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ async function mergeWithSiblings(){
if(siblings.left) siblings.leftStatus = await siblings.left.getFillStatus();
if(siblings.right) siblings.rightStatus = await siblings.right.getFillStatus();

if(selfPos===0 && siblings.right){

if(siblings.right && (selfPos===0 || !siblings.left )){
const rightSib = siblings.right;

const rightSibPos = selfPos+1;
Expand All @@ -36,9 +37,20 @@ async function mergeWithSiblings(){


// Repair parent keys TODO FIXME
const parentKeys = parent.keys;

// We remove the children reference in keys
parent.keys.splice(parseInt(selfPos/2),1);
if(parent.keys.length===0){
// We have no keys, let's merge up.
await parent.mergeUp();
}
console.log('merge')

hasMerged=true;

}else if(siblings.left){
}
else if(siblings.left){
const leftSib = siblings.left;
const leftSibPos = selfPos-1;
const {identifiers, keys} = await leftSib.getAll();
Expand All @@ -57,6 +69,18 @@ async function mergeWithSiblings(){
parent.childrens.splice(leftSibPos,1);

// Repair parent keys TODO FIXME
const parentKeys = parent.keys;

// We remove the children reference in keys
parent.keys.splice(parseInt(selfPos/2),1);
if(parent.keys.length===0){

// throw new Error('Not implemented. Looking for case.')
// We have no keys, let's merge up.
await parent.mergeUp();
// }

}
hasMerged=true;
}

Expand Down
5 changes: 3 additions & 2 deletions src/types/SBFLeaf/methods/redistribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ async function redistribute(){

const borrowFromRight = async ()=>{
const rightStatus = await siblings.right.getFillStatus();

if(rightStatus.fillFactorFilled && (rightStatus.leafSize>Number.parseInt(rightStatus.order/2))){
redistributed+=1;
throw new Error('Missing implementation of actually redistribute');
}
}else return false;
}
const borrowFromLeft = async ()=>{
const leftStatus = await siblings.left.getFillStatus();

if(leftStatus.fillFactorFilled && (leftStatus.leafSize>Number.parseInt(leftStatus.order/2))){
redistributed+=1;
throw new Error('Missing implementation of actually redistribute');
}else {
return false;
}
}

Expand Down
30 changes: 27 additions & 3 deletions src/types/SBFLeaf/methods/remove.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,39 @@
async function remove(identifier){
async function remove(remCmd){
const parent = this.getParent();
const adapter = parent.getAdapter();
await adapter.removeInLeaf(this.id, identifier);

// const value = remCmd.query[this.fieldName];
const identifier = remCmd._id;
const selfPos = parent.childrens.findIndex((el)=> el.id === this.id);

const removed = await adapter.removeInLeaf(this.id, identifier);
if(removed.length>1) throw new Error(`Unexpected amount of removed entities in same leaf`);

if(removed[0].index===0){
const newLeft = await adapter.getLeftInLeaf(this.id);

if(newLeft.key){
parent.keys.splice(selfPos-1, 1, newLeft.key)
}else{
parent.keys.splice(selfPos-1, 1)
}
}

const fillFactorFilled = await this.isFillFactorFilled();
if(fillFactorFilled){
return true;
}else{
try{
await this.redistribute();
}catch (e) {
await this.mergeWithSiblings();
try{
await this.mergeWithSiblings();
}catch (e) {
// This is done to be valid with https://www.cs.csubak.edu/~msarr/visualizations/BPlusTree.html
// but BPlusTree.js line 1289 has a discrepenties (comment says inverse of code).
// So FIXME with real research on what is advised perf-wise TODO
return true;
}
}
}
};
Expand Down
6 changes: 6 additions & 0 deletions src/types/SBFLeaf/methods/split.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ async function split(){
const adapter = parent.getAdapter();

const newLeaf = new SBFLeaf({parent});
// console.log(parent)
// console.log(parent)
// console.log(parent)
// console.log(parent)
// console.log(parent.getParent())
await adapter.createLeaf(newLeaf.id);
const midKey = await adapter.splitLeaf(this, newLeaf);

const index = await parent.insertReferenceKey(midKey);

await parent.attachLeaf(index+1,newLeaf);

};
module.exports = split;
2 changes: 2 additions & 0 deletions src/types/SBFNode/SBFNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ SBFNode.prototype.findLowerThan = require('./methods/findLowerThan')
SBFNode.prototype.findGreaterThan = require('./methods/findGreaterThan')
SBFNode.prototype.getAdapter = require('./methods/getAdapter')
SBFNode.prototype.getAll = require('./methods/getAll')
SBFNode.prototype.getFillStatus = require('./methods/getFillStatus')
SBFNode.prototype.getTreeOptions = require('./methods/getTreeOptions')
SBFNode.prototype.insert = require('./methods/insert')
SBFNode.prototype.insertReferenceKey = require('./methods/insertReferenceKey')
SBFNode.prototype.isFull = require('./methods/isFull')
SBFNode.prototype.mergeUp = require('./methods/mergeUp')
SBFNode.prototype.remove = require('./methods/remove')
SBFNode.prototype.split = require('./methods/split')
module.exports = SBFNode;
2 changes: 2 additions & 0 deletions src/types/SBFNode/methods/attachLeaf.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
module.exports = async function attachLeaf(index, leaf){
this.childrens.splice(index,0,leaf);

leaf.setParent(this);

}
20 changes: 20 additions & 0 deletions src/types/SBFNode/methods/getFillStatus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const getFillStatus = async function(){
const parent = this.getParent();
const adapter = parent.getAdapter();
const {fillFactor,order} = parent.getTreeOptions();
if(fillFactor<0.5){
throw new Error(`FillFactor cannot be less than 0.5. Received ${fillFactor}`)
}
try {
const leaf = await adapter.openLeaf(this.id);

return {fillFactor, order, leafSize:leaf.meta.size, fillFactorFilled: leaf.meta.size>=(order*fillFactor)};
}catch (e) {
if(e.message === 'Leaf do not exist'){
await adapter.createLeaf(this.id);
return this.getFillStatus()
}
else throw e
};
};
module.exports = getFillStatus;
36 changes: 36 additions & 0 deletions src/types/SBFNode/methods/mergeUp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Merge the node with it's parent (thus : up).
* Used mostly from the results of a merge from leafs when it result in emptying parent node keys.
* Parent node is then called for some mergeUp.
*
* @returns {Promise<void>}
*/
const mergeUp = async function(){
const parent = this.getParent();
const {childrens, keys, id}= this;
// const
const selfPos = parent.childrens.findIndex((el)=> el.id === id);
if(childrens.length!==1){
throw new Error('We did not tought about resolving this case. ');//todo
}
if(parent.childrens.length===2 && !await parent.getFillStatus().fillFactorFilled){
// We actually bring both leaf
let siblingPos = (selfPos===1) ? 0 : 1;
const sibling = parent.childrens[siblingPos];

parent.keys.splice(siblingPos, 0, ...sibling.keys);
parent.childrens = [...sibling.childrens, ...childrens]
}else{
// parent.childrens.splice(selfPos, 1, childrens[0]);
// console.log(selfPos);
// console.log(parent.keys);
// console.log(parent)

// console.log(this)
// console.log(await parent.getFillStatus())
throw new Error('Not implemented : MergingUp');
}


};
module.exports = mergeUp;
8 changes: 5 additions & 3 deletions src/types/SBFNode/methods/remove.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
async function remove(value){
async function remove(remCmd){
const value = remCmd.query[this.fieldName];

let leafIndex = 0;
this.keys.forEach((_key)=>{
if(value<=_key) return;
if(value<_key) return;
leafIndex++;
});

const leaf = this.childrens[leafIndex];
await leaf.remove(value);
await leaf.remove(remCmd);
};
module.exports = remove;

6 changes: 6 additions & 0 deletions src/types/SBFRoot/SBFRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ class SBFRoot {
this.fieldName = (props.tree.fieldName) ? props.tree.fieldName : null;

this.keys = (props.keys) ? props.keys : [];
// Used when SBFRoot holds value (when size = 0)
this.identifiers = (props.identifiers) ? props.identifiers : [];

this.childrens = (props.childrens) ? props.childrens : [];

this.type = 'root';
}

getTree() {
Expand All @@ -32,6 +37,7 @@ SBFRoot.prototype.find = require('./methods/find')
SBFRoot.prototype.getAll = require('./methods/getAll')
SBFRoot.prototype.get = require('./methods/get')
SBFRoot.prototype.getAdapter = require('./methods/getAdapter')
SBFRoot.prototype.getFillStatus = require('./methods/getFillStatus')
SBFRoot.prototype.getTreeOptions = require('./methods/getTreeOptions')
SBFRoot.prototype.remove = require('./methods/remove')
SBFRoot.prototype.insert = require('./methods/insert')
Expand Down
10 changes: 10 additions & 0 deletions src/types/SBFRoot/methods/getFillStatus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const getFillStatus = async function(){
const adapter = this.getAdapter();
const {fillFactor,order} = this.getTreeOptions();
if(fillFactor<0.5){
throw new Error(`FillFactor cannot be less than 0.5. Received ${fillFactor}`)
}
return {fillFactor, order, leafSize:this.keys.length, fillFactorFilled: this.keys.length>=(order*fillFactor)};

};
module.exports = getFillStatus;
15 changes: 10 additions & 5 deletions src/types/SBFRoot/methods/insert.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ const SBFLeaf = require('../../SBFLeaf/SBFLeaf');

async function insert(identifier, value = null){

if(!this.childrens.length){
const leaf = new SBFLeaf({parent:this});
this.childrens.push(leaf);

await leaf.insert(identifier, value);
if(this.childrens.length===0){
// if(this.keys.length===0){
const idx = await this.insertReferenceKey(value)
this.identifiers.splice(idx, 0, identifier);
// }else{
// const leaf = new SBFLeaf({parent:this});
// this.childrens.push(leaf);

// await leaf.insert(identifier, value);
// }
}else{
let leafIndex = 0;
this.keys.forEach((_key)=>{
Expand All @@ -22,5 +26,6 @@ async function insert(identifier, value = null){
await this.split();
}


};
module.exports = insert;
32 changes: 32 additions & 0 deletions src/types/SBFRoot/methods/mergeDown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Merge the node with it's parent (thus : up).
* Used mostly from the results of a merge from leafs when it result in emptying parent node keys.
* Parent node is then called for some mergeUp.
*
* @returns {Promise<void>}
*/
const mergeDown = async function(){
const parent = this.getParent();
const {childrens, keys, id}= this;

if(childrens.leng)



// parent.childrens.splice(selfPos, 1, childrens[0]);
// console.log(selfPos);
// console.log(parent.keys);
// console.log(parent)

// console.log(this)
// console.log(await parent.getFillStatus())
console.log('Mergeup')
console.log('Mergeup')
console.log('Mergeup')
console.log('Mergeup')
console.log('Mergeup')
console.log('Mergeup')
console.log('Mergeup')
throw new Error()
};
module.exports = mergeDown;
1 change: 0 additions & 1 deletion src/types/SBFRoot/methods/ops/findEquals.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module.exports = async function findEquals(value){
let leafIndex = 0;
console.log(this.keys)
this.keys.forEach((_key)=>{
if(value<=_key) return;
leafIndex++;
Expand Down
7 changes: 4 additions & 3 deletions src/types/SBFRoot/methods/remove.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
async function remove(remCmd){
const value = remCmd.query[this.fieldName];

async function remove(value){
let leafIndex = 0;
this.keys.forEach((_key)=>{
if(value<=_key) return;
if(value<_key) return;
leafIndex++;
});

const leaf = this.childrens[leafIndex];
await leaf.remove(value);
await leaf.remove(remCmd);
};
module.exports = remove;
Loading

0 comments on commit 6072fa5

Please sign in to comment.