
src.org.neodatis.btree.impl.AbstractBTreeNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neodatis-odb Show documentation
Show all versions of neodatis-odb Show documentation
The NeoDatis Object Database
/*
NeoDatis ODB : Native Object Database ([email protected])
Copyright (C) 2007 NeoDatis Inc. http://www.neodatis.org
"This file is part of the NeoDatis ODB open source object database".
NeoDatis ODB is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
NeoDatis ODB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.neodatis.btree.impl;
import org.neodatis.btree.IBTree;
import org.neodatis.btree.IBTreeNode;
import org.neodatis.btree.IKeyAndValue;
import org.neodatis.btree.exception.BTreeException;
import org.neodatis.btree.exception.BTreeNodeValidationException;
import org.neodatis.btree.tool.BTreeValidator;
public abstract class AbstractBTreeNode implements IBTreeNode {
protected int degree;
protected Comparable[] keys;
protected Object[] values;
protected int nbKeys;
protected int nbChildren;
protected int maxNbKeys;
protected int maxNbChildren;
/** The BTree owner of this node */
transient protected IBTree btree;
public AbstractBTreeNode() {
this.btree = null;
this.degree = -1;
this.maxNbKeys = -1;
this.maxNbChildren = -1;
keys = null;
values = null;
nbKeys = 0;
nbChildren = 0;
}
public AbstractBTreeNode(IBTree btree) {
basicInit(btree);
}
private void basicInit(IBTree btree) {
this.btree = btree;
this.degree = btree.getDegree();
this.maxNbKeys = 2 * degree - 1;
this.maxNbChildren = 2 * degree;
keys = new Comparable[maxNbKeys];
values = new Object[maxNbKeys];
nbKeys = 0;
nbChildren = 0;
init();
}
public abstract void insertKeyAndValue(Comparable key, Object value);
protected abstract void init();
public abstract IBTreeNode getChildAt(int index, boolean throwExceptionIfNotExist);
public abstract IBTreeNode getParent();
public abstract Object getParentId();
public abstract void setParent(IBTreeNode node);
public abstract boolean hasParent();
public abstract void moveChildFromTo(int sourceIndex, int destinationIndex, boolean throwExceptionIfDoesNotExist);
/**
* Creates a new node with the right part of this node. This should only be
* called on a full node
*/
public IBTreeNode extractRightPart() {
if (!isFull()) {
throw new BTreeException("extract right part called on non full node");
}
// Creates an empty new node
IBTreeNode rightPart = btree.buildNode();
int j = 0;
for (int i = degree; i < maxNbKeys; i++) {
rightPart.setKeyAndValueAt(keys[i], values[i], j, false, false);
keys[i] = null;
values[i] = null;
rightPart.setChildAt(this, i, j, false);
// TODO must we load all nodes to set new parent
IBTreeNode c = rightPart.getChildAt(j, false);
if (c != null) {
c.setParent(rightPart);
}
// rightPart.setChildAt(getChildAt(i,false), j);
setNullChildAt(i);
j++;
}
// rightPart.setChildAt(getLastPositionChild(), j);
rightPart.setChildAt(this, getMaxNbChildren() - 1, j, false);
// correct father id
IBTreeNode c1 = rightPart.getChildAt(j, false);
if (c1 != null) {
c1.setParent(rightPart);
}
setNullChildAt(maxNbChildren - 1); // resets last child
keys[degree - 1] = null;// resets median element
values[degree - 1] = null;
// set numbers
nbKeys = degree - 1;
int originalNbChildren = nbChildren;
nbChildren = Math.min(nbChildren, degree);
rightPart.setNbKeys(degree - 1);
rightPart.setNbChildren(originalNbChildren - nbChildren);
BTreeValidator.validateNode(this);
BTreeValidator.validateNode(rightPart);
BTreeValidator.checkDuplicateChildren(this, rightPart);
return rightPart;
}
public IKeyAndValue getKeyAndValueAt(int index) {
if (keys[index] == null && values[index] == null) {
return null;
}
return new KeyAndValue(keys[index], values[index]);
}
public IKeyAndValue getLastKeyAndValue() {
return getKeyAndValueAt(nbKeys - 1);
}
public Comparable getKeyAt(int index) {
return keys[index];
}
public IKeyAndValue getMedian() {
int medianPosition = degree - 1;
return getKeyAndValueAt(medianPosition);
}
/**
* Returns the position of the key. If the key does not exist in node,
* returns the position where this key should be,multiplied by -1
*
*
* for example for node of degree 3 : [1 89 452 789 - ],
* calling getPositionOfKey(89) returns 2 (starts with 1)
* calling getPositionOfKey(99) returns -2 (starts with 1),because the position should be done, but it does not exist so multiply by -1
* this is used to know the child we should descend to!in this case the getChild(2).
*
*
*
* @param key
* @return The position of the key,as a negative number if key does not
* exist, warning, the position starts with 1and not 0!
*/
public int getPositionOfKey(Comparable key) {
int i = 0;
while (i < nbKeys) {
int result = keys[i].compareTo(key);
if (result == 0) {
return i + 1;
}
if (result > 0) {
return -(i + 1);
}
i++;
}
return -(i + 1);
}
public void incrementNbChildren() {
nbChildren++;
}
public void incrementNbKeys() {
nbKeys++;
}
protected void rightShiftFrom(int position, boolean shiftChildren) {
if (isFull()) {
throw new BTreeException("Node is full, can't right shift!");
}
// Shift keys
for (int i = nbKeys; i > position; i--) {
keys[i] = keys[i - 1];
values[i] = values[i - 1];
}
keys[position] = null;
values[position] = null;
// Shift children
if (shiftChildren) {
for (int i = nbChildren; i > position; i--) {
moveChildFromTo(i - 1, i, true);
// setChildAt(getChildAt(i-1,true),i);
}
setNullChildAt(position);
}
}
protected void leftShiftFrom(int position, boolean shiftChildren) {
for (int i = position; i < nbKeys - 1; i++) {
keys[i] = keys[i + 1];
values[i] = values[i + 1];
if (shiftChildren) {
moveChildFromTo(i + 1, i, false);
// setChildAt(getChildAt(i+1,false), i);
}
}
keys[nbKeys - 1] = null;
values[nbKeys - 1] = null;
if (shiftChildren) {
moveChildFromTo(nbKeys, nbKeys - 1, false);
// setChildAt(getChildAt(nbKeys,false), nbKeys-1);
setNullChildAt(nbKeys);
}
}
public void setKeyAndValueAt(Comparable key, Object value, int index) {
keys[index] = key;
values[index] = value;
}
public void setKeyAndValueAt(IKeyAndValue keyAndValue, int index) {
setKeyAndValueAt(keyAndValue.getKey(), keyAndValue.getValue(), index);
}
public void setKeyAndValueAt(Comparable key, Object value, int index, boolean shiftIfAlreadyExist, boolean incrementNbKeys) {
if (shiftIfAlreadyExist && index < nbKeys) {
rightShiftFrom(index, true);
}
keys[index] = key;
values[index] = value;
if (incrementNbKeys) {
nbKeys++;
}
}
public void setKeyAndValueAt(IKeyAndValue keyAndValue, int index, boolean shiftIfAlreadyExist, boolean incrementNbKeys) {
setKeyAndValueAt(keyAndValue.getKey(), keyAndValue.getValue(), index, shiftIfAlreadyExist, incrementNbKeys);
}
public boolean isFull() {
return nbKeys == maxNbKeys;
}
public boolean isLeaf() {
return nbChildren == 0;
}
/**
* Can only merge node without intersection => the greater key of this must
* be smaller than the smallest key of the node
*
*/
public void mergeWith(IBTreeNode node) {
BTreeValidator.validateNode(this);
BTreeValidator.validateNode(node);
checkIfCanMergeWith(node);
int j = nbKeys;
for (int i = 0; i < node.getNbKeys(); i++) {
setKeyAndValueAt(node.getKeyAt(i), node.getValueAsObjectAt(i), j, false, false);
setChildAt(node, i, j, false);
j++;
}
// in this, we have to take the last child
if (node.getNbChildren() > node.getNbKeys()) {
setChildAt(node, node.getNbChildren() - 1, j, true);
}
nbKeys += node.getNbKeys();
nbChildren += node.getNbChildren();
BTreeValidator.validateNode(this);
}
private void checkIfCanMergeWith(IBTreeNode node) {
if (nbKeys + node.getNbKeys() > maxNbKeys) {
throw new BTreeException("Trying to merge two nodes with too many keys " + nbKeys + " + " + node.getNbKeys() + " > "
+ maxNbKeys);
}
if (nbKeys > 0) {
Comparable greatestOfThis = keys[nbKeys - 1];
Comparable smallestOfOther = node.getKeyAt(0);
if (greatestOfThis.compareTo(smallestOfOther) >= 0) {
throw new BTreeNodeValidationException("Trying to merge two nodes that have intersections : " + toString() + " / " + node);
}
}
if (nbKeys < nbChildren) {
throw new BTreeNodeValidationException("Trying to merge two nodes where the first one has more children than keys");
}
}
public void removeKeyAndValueAt(int index) {
throw new BTreeException("Not implemented");
}
public IBTreeNode getLastChild() {
return getChildAt(nbChildren - 1, true);
}
public IBTreeNode getLastPositionChild() {
return getChildAt(maxNbChildren - 1, false);
}
public int getNbKeys() {
return nbKeys;
}
public void setNbChildren(int nbChildren) {
this.nbChildren = nbChildren;
}
public void setNbKeys(int nbKeys) {
this.nbKeys = nbKeys;
}
public int getDegree() {
return degree;
}
public int getNbChildren() {
return nbChildren;
}
public Object deleteKeyForLeafNode(IKeyAndValue keyAndValue) {
int position = getPositionOfKey(keyAndValue.getKey());
if (position < 0) {
return null;
}
int realPosition = position - 1;
Object value = values[realPosition];
leftShiftFrom(realPosition, false);
nbKeys--;
BTreeValidator.validateNode(this);
return value;
}
public Object deleteKeyAndValueAt(int keyIndex, boolean shiftChildren) {
Object currentValue = values[keyIndex];
leftShiftFrom(keyIndex, shiftChildren);
nbKeys--;
// only decrease child number if child are involved in shifting
if (shiftChildren && nbChildren > keyIndex) {
nbChildren--;
}
// BTreeValidator.validateNode(this);
return currentValue;
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("id=").append(getId()).append(" {keys(").append(nbKeys).append(")=(");
for (int i = 0; i < nbKeys; i++) {
if (i > 0) {
buffer.append(",");
}
buffer.append(keys[i]).append("/").append(values[i]);
}
buffer.append("), child(").append(nbChildren).append(")}");
return buffer.toString();
}
public int getMaxNbChildren() {
return maxNbChildren;
}
public void setBTree(IBTree btree) {
this.btree = btree;
}
public IBTree getBTree() {
return btree;
}
public void clear() {
basicInit(btree);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy