@Override public OMVRBTreeEntry<K, V> setParent(final OMVRBTreeEntry<K, V> iParent) { if (iParent != parent) { OMVRBTreeEntryPersistent<K, V> newParent = (OMVRBTreeEntryPersistent<K, V>) iParent; ORID newParentId = iParent == null ? ORecordId.EMPTY_RECORD_ID : newParent.dataProvider.getIdentity(); parent = newParent; if (dataProvider.setParent(newParentId)) markDirty(); if (parent != null) { ORID thisRid = dataProvider.getIdentity(); if (parent.left == this && !parent.dataProvider.getLeft().equals(thisRid)) if (parent.dataProvider.setLeft(thisRid)) parent.markDirty(); if (parent.left != this && parent.dataProvider.getLeft().isValid() && parent.dataProvider.getLeft().equals(thisRid)) parent.left = this; if (parent.right == this && !parent.dataProvider.getRight().equals(thisRid)) if (parent.dataProvider.setRight(thisRid)) parent.markDirty(); if (parent.right != this && parent.dataProvider.getRight().isValid() && parent.dataProvider.getRight().equals(thisRid)) parent.right = this; } } return iParent; }
@Override public OMVRBTreeEntry<K, V> getParent() { if (dataProvider == null) return null; if (parent == null && dataProvider.getParent().isValid()) { // LAZY LOADING OF THE PARENT NODE parent = pTree.loadEntry(null, dataProvider.getParent()); checkEntryStructure(); if (parent != null) { // TRY TO ASSIGN IT FOLLOWING THE RID if (parent.dataProvider.getLeft().isValid() && parent.dataProvider.getLeft().equals(dataProvider.getIdentity())) parent.left = this; else if (parent.dataProvider.getRight().isValid() && parent.dataProvider.getRight().equals(dataProvider.getIdentity())) parent.right = this; else { OLogManager.instance() .error( this, "getParent: Cannot assign node %s to parent. Nodes parent-left=%s, parent-right=%s", dataProvider.getParent(), parent.dataProvider.getLeft(), parent.dataProvider.getRight()); } } } return parent; }
@Override protected void insert(final int iIndex, final K iKey, final V iValue) { K oldKey = iIndex == 0 ? dataProvider.getKeyAt(0) : null; if (dataProvider.insertAt(iIndex, iKey, iValue)) markDirty(); if (iIndex == 0) pTree.updateEntryPoint(oldKey, this); }
protected void clear() { // SPEED UP MEMORY CLAIM BY RESETTING INTERNAL FIELDS pTree = null; tree = null; dataProvider.removeIdentityChangedListener(this); dataProvider.clear(); dataProvider = null; }
@Override public OMVRBTreeEntry<K, V> getLeft() { if (dataProvider == null) return null; if (left == null && dataProvider.getLeft().isValid()) { // LAZY LOADING OF THE LEFT LEAF left = pTree.loadEntry(this, dataProvider.getLeft()); checkEntryStructure(); } return left; }
@Override public OMVRBTreeEntry<K, V> getRight() { if (dataProvider == null) return null; if (right == null && dataProvider.getRight().isValid()) { // LAZY LOADING OF THE RIGHT LEAF right = pTree.loadEntry(this, dataProvider.getRight()); checkEntryStructure(); } return right; }
/** * Called on event of splitting an entry. Copy values from the parent node. * * @param iParent Parent node * @param iPosition Current position */ public OMVRBTreeEntryPersistent(final OMVRBTreeEntry<K, V> iParent, final int iPosition) { super(((OMVRBTreeEntryPersistent<K, V>) iParent).getTree()); pTree = (OMVRBTreePersistent<K, V>) tree; OMVRBTreeEntryPersistent<K, V> pParent = (OMVRBTreeEntryPersistent<K, V>) iParent; dataProvider = pTree.dataProvider.createEntry(); dataProvider.setIdentityChangedListener(this); dataProvider.copyDataFrom(pParent.dataProvider, iPosition); if (pParent.dataProvider.truncate(iPosition)) pParent.markDirty(); init(); setParent(pParent); pTree.addNodeInMemory(this); // created entry : force dispatch dirty node. markDirty(); }
/** * Make a new cell with given key, value, and parent, and with <tt>null</tt> child links, and * BLACK color. */ public OMVRBTreeEntryPersistent( final OMVRBTreePersistent<K, V> iTree, final K iKey, final V iValue, final OMVRBTreeEntryPersistent<K, V> iParent) { super(iTree); pTree = iTree; dataProvider = pTree.dataProvider.createEntry(); dataProvider.setIdentityChangedListener(this); dataProvider.insertAt(0, iKey, iValue); init(); setParent(iParent); pTree.addNodeInMemory(this); // created entry : force dispatch dirty node. markDirty(); }
/** * Invalidate serialized Value associated in order to be re-marshalled on the next node storing. */ public V setValue(final V iValue) { V oldValue = getValue(); int index = tree.getPageIndex(); if (dataProvider.setValueAt(index, iValue)) markDirty(); return oldValue; }
/** Assures that all the links versus parent, left and right are consistent. */ public OMVRBTreeEntryPersistent<K, V> save() throws OSerializationException { if (!dataProvider.isEntryDirty()) return this; final boolean isNew = dataProvider.getIdentity().isNew(); // FOR EACH NEW LINK, SAVE BEFORE if (left != null && left.dataProvider.getIdentity().isNew()) { if (isNew) { // TEMPORARY INCORRECT SAVE FOR GETTING AN ID. WILL BE SET DIRTY AGAIN JUST AFTER left.dataProvider.save(); } else left.save(); } if (right != null && right.dataProvider.getIdentity().isNew()) { if (isNew) { // TEMPORARY INCORRECT SAVE FOR GETTING AN ID. WILL BE SET DIRTY AGAIN JUST AFTER right.dataProvider.save(); } else right.save(); } if (parent != null && parent.dataProvider.getIdentity().isNew()) { if (isNew) { // TEMPORARY INCORRECT SAVE FOR GETTING AN ID. WILL BE SET DIRTY AGAIN JUST AFTER parent.dataProvider.save(); } else parent.save(); } dataProvider.save(); // if (parent != null) // if (!parent.record.getIdentity().equals(parentRid)) // OLogManager.instance().error(this, // "[save]: Tree node %s has parentRid '%s' different by the rid of the assigned parent node: // %s", record.getIdentity(), // parentRid, parent.record.getIdentity()); checkEntryStructure(); if (pTree.searchNodeInCache(dataProvider.getIdentity()) != this) { // UPDATE THE CACHE pTree.addNodeInMemory(this); } return this; }
/** * Delete all the nodes recursively. IF they are not loaded in memory, load all the tree. * * @throws IOException */ public OMVRBTreeEntryPersistent<K, V> delete() throws IOException { if (dataProvider != null) { pTree.removeNodeFromMemory(this); pTree.removeEntry(dataProvider.getIdentity()); // EARLY LOAD LEFT AND DELETE IT RECURSIVELY if (getLeft() != null) ((OMVRBTreeEntryPersistent<K, V>) getLeft()).delete(); // EARLY LOAD RIGHT AND DELETE IT RECURSIVELY if (getRight() != null) ((OMVRBTreeEntryPersistent<K, V>) getRight()).delete(); // DELETE MYSELF dataProvider.removeIdentityChangedListener(this); dataProvider.delete(); clear(); } return this; }
@Override protected void remove() { final int index = tree.getPageIndex(); final K oldKey = index == 0 ? getKeyAt(0) : null; if (dataProvider.removeAt(index)) markDirty(); tree.setPageIndex(index - 1); if (index == 0) pTree.updateEntryPoint(oldKey, this); }
/** * Called upon unmarshalling. * * @param iTree Tree which belong * @param iParent Parent node if any * @param iRecordId Record to unmarshall */ public OMVRBTreeEntryPersistent( final OMVRBTreePersistent<K, V> iTree, final OMVRBTreeEntryPersistent<K, V> iParent, final ORID iRecordId) { super(iTree); pTree = iTree; dataProvider = pTree.dataProvider.getEntry(iRecordId); dataProvider.setIdentityChangedListener(this); init(); parent = iParent; // setParent(iParent); pTree.addNodeInMemory(this); }
@Override public void setLeft(final OMVRBTreeEntry<K, V> iLeft) { if (iLeft != left) { OMVRBTreeEntryPersistent<K, V> newLeft = (OMVRBTreeEntryPersistent<K, V>) iLeft; ORID newLeftId = iLeft == null ? ORecordId.EMPTY_RECORD_ID : newLeft.dataProvider.getIdentity(); left = newLeft; if (dataProvider.setLeft(newLeftId)) markDirty(); if (left != null && left.parent != this) left.setParent(this); checkEntryStructure(); } }
@Override public void setRight(final OMVRBTreeEntry<K, V> iRight) { if (iRight != right) { OMVRBTreeEntryPersistent<K, V> newRight = (OMVRBTreeEntryPersistent<K, V>) iRight; ORID newRightId = iRight == null ? ORecordId.EMPTY_RECORD_ID : newRight.dataProvider.getIdentity(); right = newRight; if (dataProvider.setRight(newRightId)) markDirty(); if (right != null && right.parent != this) right.setParent(this); checkEntryStructure(); } }
private boolean canDisconnectFrom(OMVRBTreeEntryPersistent<K, V> entry) { return dataProvider == null || !dataProvider.getIdentity().isNew() && !entry.dataProvider.getIdentity().isNew(); }
@Override protected V getValueAt(final int iIndex) { return dataProvider.getValueAt(iIndex); }
@Override protected void copyFrom(final OMVRBTreeEntry<K, V> iSource) { if (dataProvider.copyFrom(((OMVRBTreeEntryPersistent<K, V>) iSource).dataProvider)) markDirty(); }
/** * Disconnect the current node from others. * * @param iForceDirty Force disconnection also if the record it's dirty * @param iLevel * @return count of nodes that has been disconnected */ protected int disconnect(final boolean iForceDirty, final int iLevel) { if (dataProvider == null) // DIRTY NODE, JUST REMOVE IT return 1; int totalDisconnected = 0; final ORID rid = dataProvider.getIdentity(); boolean disconnectedFromParent = false; if (parent != null) { // DISCONNECT RECURSIVELY THE PARENT NODE if (canDisconnectFrom(parent) || iForceDirty) { if (parent.left == this) { parent.left = null; } else if (parent.right == this) { parent.right = null; } else OLogManager.instance() .warn( this, "Node " + rid + " has the parent (" + parent + ") unlinked to itself. It links to " + parent); totalDisconnected += parent.disconnect(iForceDirty, iLevel + 1); parent = null; disconnectedFromParent = true; } } else { disconnectedFromParent = true; } boolean disconnectedFromLeft = false; if (left != null) { // DISCONNECT RECURSIVELY THE LEFT NODE if (canDisconnectFrom(left) || iForceDirty) { if (left.parent == this) left.parent = null; else OLogManager.instance() .warn( this, "Node " + rid + " has the left (" + left + ") unlinked to itself. It links to " + left.parent); totalDisconnected += left.disconnect(iForceDirty, iLevel + 1); left = null; disconnectedFromLeft = true; } } else { disconnectedFromLeft = true; } boolean disconnectedFromRight = false; if (right != null) { // DISCONNECT RECURSIVELY THE RIGHT NODE if (canDisconnectFrom(right) || iForceDirty) { if (right.parent == this) right.parent = null; else OLogManager.instance() .warn( this, "Node " + rid + " has the right (" + right + ") unlinked to itself. It links to " + right.parent); totalDisconnected += right.disconnect(iForceDirty, iLevel + 1); right = null; disconnectedFromRight = true; } } else { disconnectedFromLeft = true; } if (disconnectedFromParent && disconnectedFromLeft && disconnectedFromRight) if ((!dataProvider.isEntryDirty() && !dataProvider.getIdentity().isTemporary() || iForceDirty) && !pTree.isNodeEntryPoint(this)) { totalDisconnected++; pTree.removeNodeFromMemory(this); clear(); } return totalDisconnected; }
@Override protected void setColor(final boolean iColor) { if (dataProvider.setColor(iColor)) markDirty(); }
@Override public boolean getColor() { return dataProvider.getColor(); }
public int getPageSize() { return dataProvider.getPageSize(); }
public int getSize() { return dataProvider != null ? dataProvider.getSize() : 0; }
@Override public K getKeyAt(final int iIndex) { return dataProvider.getKeyAt(iIndex); }
public void checkEntryStructure() { if (!tree.isRuntimeCheckEnabled()) return; if (dataProvider.getParent() == null) OLogManager.instance() .error(this, "checkEntryStructure: Node %s has parentRid null!\n", this); if (dataProvider.getLeft() == null) OLogManager.instance().error(this, "checkEntryStructure: Node %s has leftRid null!\n", this); if (dataProvider.getRight() == null) OLogManager.instance().error(this, "checkEntryStructure: Node %s has rightRid null!\n", this); if (this == left || dataProvider.getIdentity().isValid() && dataProvider.getIdentity().equals(dataProvider.getLeft())) OLogManager.instance() .error(this, "checkEntryStructure: Node %s has left that points to itself!\n", this); if (this == right || dataProvider.getIdentity().isValid() && dataProvider.getIdentity().equals(dataProvider.getRight())) OLogManager.instance() .error(this, "checkEntryStructure: Node %s has right that points to itself!\n", this); if (left != null && left == right) OLogManager.instance() .error(this, "checkEntryStructure: Node %s has left and right equals!\n", this); if (left != null) { if (!left.dataProvider.getIdentity().equals(dataProvider.getLeft())) OLogManager.instance() .error(this, "checkEntryStructure: Wrong left node loaded: " + dataProvider.getLeft()); if (left.parent != this) OLogManager.instance() .error( this, "checkEntryStructure: Left node is not correctly connected to the parent" + dataProvider.getLeft()); } if (right != null) { if (!right.dataProvider.getIdentity().equals(dataProvider.getRight())) OLogManager.instance() .error( this, "checkEntryStructure: Wrong right node loaded: " + dataProvider.getRight()); if (right.parent != this) OLogManager.instance() .error( this, "checkEntryStructure: Right node is not correctly connected to the parent" + dataProvider.getRight()); } }