All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.treetank.access.NodeWriteTrx Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2011, University of Konstanz, Distributed Systems Group
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * * Neither the name of the University of Konstanz nor the
 * names of its contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.treetank.access;

import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.treetank.data.IConstants.NULL_NODE;
import static org.treetank.data.IConstants.ROOT_NODE;

import java.util.ArrayList;

import javax.xml.namespace.QName;

import org.treetank.api.IBucketWriteTrx;
import org.treetank.api.INodeWriteTrx;
import org.treetank.api.ISession;
import org.treetank.data.AttributeNode;
import org.treetank.data.DocumentRootNode;
import org.treetank.data.ElementNode;
import org.treetank.data.IConstants;
import org.treetank.data.NamespaceNode;
import org.treetank.data.NodeMetaPageFactory;
import org.treetank.data.TextNode;
import org.treetank.data.delegates.NameNodeDelegate;
import org.treetank.data.delegates.NodeDelegate;
import org.treetank.data.delegates.StructNodeDelegate;
import org.treetank.data.delegates.ValNodeDelegate;
import org.treetank.data.interfaces.ITreeData;
import org.treetank.data.interfaces.ITreeNameData;
import org.treetank.data.interfaces.ITreeStructData;
import org.treetank.data.interfaces.ITreeValData;
import org.treetank.exception.TTException;
import org.treetank.exception.TTIOException;
import org.treetank.utils.NamePageHash;
import org.treetank.utils.TypedValue;

/**
 * 

NodeWriteTrx

* *

* Single-threaded instance of only write transaction per session. *

* *

* All methods throw {@link NullPointerException}s in case of null values for reference parameters. *

* * @author Sebastian Graf, University of Konstanz */ public class NodeWriteTrx implements INodeWriteTrx { /** Session for abort/commit. */ private final ISession mSession; /** * How is the Hash for this storage computed? */ public enum HashKind { /** Rolling hash, only nodes on ancestor axis are touched. */ Rolling, /** * Postorder hash, all nodes on ancestor plus postorder are at least * read. */ Postorder, /** No hash structure after all. */ None; } /** Prime for computing the hash. */ private static final int PRIME = 77081; /** Hash kind of Structure. */ private final HashKind mHashKind; /** Delegate for the read access. */ private NodeReadTrx mDelegate; /** * Constructor. * * @param pSession * state of the session * @param pPageWriteTrx * state of this transaction * * @throws TTIOException * if the reading of the props is failing * @throws TTUsageException * if paramMaxNodeCount < 0 or paramMaxTime < 0 */ public NodeWriteTrx(final ISession pSession, final IBucketWriteTrx pPageWriteTrx, final HashKind kind) throws TTException { mHashKind = kind; mDelegate = new NodeReadTrx(pPageWriteTrx); mSession = pSession; } /** * {@inheritDoc} */ @Override public long insertElementAsFirstChild(final QName pQName) throws TTException, NullPointerException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkNotNull(pQName); checkState(mDelegate.getCurrentNode() instanceof ElementNode || mDelegate.getCurrentNode() instanceof DocumentRootNode, "Insert is not allowed if current node is not an ElementNode, but was %s", mDelegate .getCurrentNode()); final long parentKey = mDelegate.getCurrentNode().getDataKey(); final long leftSibKey = NULL_NODE; final long rightSibKey = ((ITreeStructData)mDelegate.getCurrentNode()).getFirstChildKey(); final ElementNode node = createElementNode(parentKey, leftSibKey, rightSibKey, 0, pQName); mDelegate.setCurrentNode(node); adaptForInsert(node, true); adaptHashesWithAdd(); return node.getDataKey(); } /** * {@inheritDoc} */ @Override public long insertElementAsRightSibling(final QName pQName) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkNotNull(pQName); checkState( mDelegate.getCurrentNode() instanceof ITreeStructData, "Insert is not allowed if current node is not an StructuralNode (either Text or Element), but was %s", mDelegate.getCurrentNode()); final long parentKey = mDelegate.getCurrentNode().getParentKey(); final long leftSibKey = mDelegate.getCurrentNode().getDataKey(); final long rightSibKey = ((ITreeStructData)mDelegate.getCurrentNode()).getRightSiblingKey(); final ElementNode node = createElementNode(parentKey, leftSibKey, rightSibKey, 0, pQName); mDelegate.setCurrentNode(node); adaptForInsert(node, false); adaptHashesWithAdd(); return node.getDataKey(); } /** * {@inheritDoc} */ @Override public long insertTextAsFirstChild(final String pValue) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkNotNull(pValue); checkState(mDelegate.getCurrentNode() instanceof ElementNode || mDelegate.getCurrentNode() instanceof DocumentRootNode, "Insert is not allowed if current node is not an ElementNode, but was %s", mDelegate .getCurrentNode()); final byte[] value = TypedValue.getBytes(pValue); final long parentKey = mDelegate.getCurrentNode().getDataKey(); final long leftSibKey = NULL_NODE; final long rightSibKey = ((ITreeStructData)mDelegate.getCurrentNode()).getFirstChildKey(); final TextNode node = createTextNode(parentKey, leftSibKey, rightSibKey, value); mDelegate.setCurrentNode(node); adaptForInsert(node, true); adaptHashesWithAdd(); return node.getDataKey(); } /** * {@inheritDoc} */ @Override public long insertTextAsRightSibling(final String pValue) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkNotNull(pValue); checkState(mDelegate.getCurrentNode() instanceof ElementNode, "Insert is not allowed if current node is not an ElementNode, but was %s", mDelegate .getCurrentNode()); final byte[] value = TypedValue.getBytes(pValue); final long parentKey = mDelegate.getCurrentNode().getParentKey(); final long leftSibKey = mDelegate.getCurrentNode().getDataKey(); final long rightSibKey = ((ITreeStructData)mDelegate.getCurrentNode()).getRightSiblingKey(); final TextNode node = createTextNode(parentKey, leftSibKey, rightSibKey, value); mDelegate.setCurrentNode(node); adaptForInsert(node, false); adaptHashesWithAdd(); return node.getDataKey(); } /** * {@inheritDoc} */ @Override public long insertAttribute(final QName pQName, final String pValue) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkState(mDelegate.getCurrentNode() instanceof ElementNode, "Insert is not allowed if current node is not an ElementNode, but was %s", mDelegate .getCurrentNode()); final byte[] value = TypedValue.getBytes(pValue); final long elementKey = mDelegate.getCurrentNode().getDataKey(); final int nameKey = insertName(buildName(pQName)); final int namespaceKey = insertName(pQName.getNamespaceURI()); final NodeDelegate nodeDel = new NodeDelegate(getPtx().incrementDataKey(), elementKey, 0); final NameNodeDelegate nameDel = new NameNodeDelegate(nodeDel, nameKey, namespaceKey); final ValNodeDelegate valDel = new ValNodeDelegate(nodeDel, value); final AttributeNode node = new AttributeNode(nodeDel, nameDel, valDel); getPtx().setData(node); final ITreeData parentNode = (org.treetank.data.interfaces.ITreeData)getPtx().getData(node.getParentKey()); ((ElementNode)parentNode).insertAttribute(node.getDataKey()); getPtx().setData(parentNode); mDelegate.setCurrentNode(node); adaptForInsert(node, false); adaptHashesWithAdd(); return node.getDataKey(); } /** * {@inheritDoc} */ @Override public long insertNamespace(final QName pQName) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkNotNull(pQName); checkState(mDelegate.getCurrentNode() instanceof ElementNode, "Insert is not allowed if current node is not an ElementNode, but was %s", mDelegate .getCurrentNode()); final int uriKey = insertName(pQName.getNamespaceURI()); final int prefixKey = insertName(pQName.getPrefix()); final long elementKey = mDelegate.getCurrentNode().getDataKey(); final NodeDelegate nodeDel = new NodeDelegate(getPtx().incrementDataKey(), elementKey, 0); final NameNodeDelegate nameDel = new NameNodeDelegate(nodeDel, prefixKey, uriKey); final NamespaceNode node = new NamespaceNode(nodeDel, nameDel); getPtx().setData(node); final ITreeData parentNode = (org.treetank.data.interfaces.ITreeData)getPtx().getData(node.getParentKey()); ((ElementNode)parentNode).insertNamespace(node.getDataKey()); getPtx().setData(parentNode); mDelegate.setCurrentNode(node); adaptForInsert(node, false); adaptHashesWithAdd(); return node.getDataKey(); } private ElementNode createElementNode(final long parentKey, final long mLeftSibKey, final long rightSibKey, final long hash, final QName mName) throws TTException { final int nameKey = insertName(buildName(mName)); final int namespaceKey = insertName(mName.getNamespaceURI()); final NodeDelegate nodeDel = new NodeDelegate(getPtx().incrementDataKey(), parentKey, 0); final StructNodeDelegate structDel = new StructNodeDelegate(nodeDel, NULL_NODE, rightSibKey, mLeftSibKey, 0); final NameNodeDelegate nameDel = new NameNodeDelegate(nodeDel, nameKey, namespaceKey); final ElementNode node = new ElementNode(nodeDel, structDel, nameDel, new ArrayList(), new ArrayList()); getPtx().setData(node); return node; } private TextNode createTextNode(final long mParentKey, final long mLeftSibKey, final long rightSibKey, final byte[] mValue) throws TTException { final NodeDelegate nodeDel = new NodeDelegate(getPtx().incrementDataKey(), mParentKey, 0); final ValNodeDelegate valDel = new ValNodeDelegate(nodeDel, mValue); final StructNodeDelegate structDel = new StructNodeDelegate(nodeDel, NULL_NODE, rightSibKey, mLeftSibKey, 0); final TextNode node = new TextNode(nodeDel, structDel, valDel); getPtx().setData(node); return node; } /** * {@inheritDoc} */ @Override public void remove() throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkState(mDelegate.getCurrentNode().getKind() != IConstants.ROOT, "Document root can not be removed."); if (mDelegate.getCurrentNode() instanceof ITreeStructData) { final ITreeStructData node = (ITreeStructData)mDelegate.getCurrentNode(); if (node.getKind() == IConstants.ELEMENT) { long currentKey = node.getDataKey(); ElementNode element = (ElementNode)node; for (int i = 0; i < element.getAttributeCount(); i++) { moveTo(element.getAttributeKey(i)); getPtx().removeData(mDelegate.getCurrentNode()); } for (int i = 0; i < element.getNamespaceCount(); i++) { moveTo(element.getNamespaceKey(i)); getPtx().removeData(mDelegate.getCurrentNode()); } moveTo(currentKey); } moveTo(node.getDataKey()); adaptForRemove(node); adaptHashesWithRemove(); // Set current node. if (node.hasRightSibling()) { moveTo(node.getRightSiblingKey()); } else if (node.hasLeftSibling()) { moveTo(node.getLeftSiblingKey()); } else { moveTo(node.getParentKey()); } } else if (mDelegate.getCurrentNode().getKind() == IConstants.ATTRIBUTE) { final ITreeData treeData = mDelegate.getCurrentNode(); final ElementNode parentNode = (ElementNode)getPtx().getData(treeData.getParentKey()); parentNode.removeAttribute(treeData.getDataKey()); getPtx().setData(parentNode); adaptHashesWithRemove(); moveTo(mDelegate.getCurrentNode().getParentKey()); } else if (mDelegate.getCurrentNode().getKind() == IConstants.NAMESPACE) { final ITreeData treeData = mDelegate.getCurrentNode(); final ElementNode parentNode = (ElementNode)getPtx().getData(treeData.getParentKey()); parentNode.removeNamespace(treeData.getDataKey()); getPtx().setData(parentNode); adaptHashesWithRemove(); moveTo(mDelegate.getCurrentNode().getParentKey()); } } /** * {@inheritDoc} */ @Override public void setQName(final QName paramName) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkState(mDelegate.getCurrentNode() instanceof ITreeNameData, "setQName is not allowed if current node is not an ITreeNameData implementation, but was %s", mDelegate.getCurrentNode()); final long oldHash = mDelegate.getCurrentNode().hashCode(); final ITreeNameData node = (ITreeNameData)getPtx().getData(mDelegate.getCurrentNode().getDataKey()); node.setNameKey(insertName(buildName(paramName))); getPtx().setData(node); mDelegate.setCurrentNode((ITreeData)node); adaptHashedWithUpdate(oldHash); } /** * {@inheritDoc} */ @Override public void setURI(final String paramUri) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkState(mDelegate.getCurrentNode() instanceof ITreeNameData, "setURI is not allowed if current node is not an ITreeNameData implementation, but was %s", mDelegate .getCurrentNode()); final long oldHash = mDelegate.getCurrentNode().hashCode(); final ITreeNameData node = (ITreeNameData)getPtx().getData(mDelegate.getCurrentNode().getDataKey()); node.setURIKey(insertName(paramUri)); getPtx().setData(node); mDelegate.setCurrentNode((ITreeData)node); adaptHashedWithUpdate(oldHash); } /** * {@inheritDoc} */ @Override public void setValue(final String pValue) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkState(mDelegate.getCurrentNode() instanceof ITreeValData, "setValue is not allowed if current node is not an ITreeValData implementation, but was %s", mDelegate.getCurrentNode()); final long oldHash = mDelegate.getCurrentNode().hashCode(); final ITreeValData node = (ITreeValData)getPtx().getData(mDelegate.getCurrentNode().getDataKey()); node.setValue(TypedValue.getBytes(pValue)); getPtx().setData(node); mDelegate.setCurrentNode((ITreeData)node); adaptHashedWithUpdate(oldHash); } /** * {@inheritDoc} * * @throws TTUsageException * if paramRevision < 0 or paramRevision > maxCommitedRev * @throws TTIOException * if an I/O operation fails */ @Override public void revertTo(final long pRevision) throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); checkArgument(pRevision >= 0, "Parameter must be >= 0, but was %s", pRevision); getPtx().close(); // Reset internal transaction state to new uber page. mDelegate.setPageTransaction(mSession.beginBucketWtx(pRevision)); moveTo(ROOT_NODE); } /** * {@inheritDoc} */ @Override public void commit() throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); // ICommitStrategy uber page. getPtx().commit(); } /** * {@inheritDoc} */ @Override public void abort() throws TTException { checkState(!mDelegate.isClosed(), "Transaction is already closed."); long revisionToSet = 0; revisionToSet = mDelegate.mPageReadTrx.getRevision() - 1; getPtx().close(); // Reset internal transaction state to last committed uber page. mDelegate.setPageTransaction(mSession.beginBucketWtx(revisionToSet)); } /** * {@inheritDoc} */ @Override public void close() throws TTException { if (!isClosed()) { mDelegate.close(); } } /** * Setting a new name in the metapage. * * @param pName * to be set * @throws TTException */ private int insertName(final String pName) throws TTException { final String string = (pName == null ? "" : pName); final int nameKey = NamePageHash.generateHashForString(string); NodeMetaPageFactory.MetaKey key = new NodeMetaPageFactory.MetaKey(nameKey); NodeMetaPageFactory.MetaValue value = new NodeMetaPageFactory.MetaValue(string); getPageWtx().getMetaBucket().put(key, value); return nameKey; } // //////////////////////////////////////////////////////////// // insert operation // ////////////////////////////////////////////////////////// /** * Adapting everything for insert operations. * * @param paramNewNode * pointer of the new node to be inserted * @param addAsFirstChild * determines the position where to insert * @throws TTIOException * if anything weird happens */ private void adaptForInsert(final ITreeData paramNewNode, final boolean addAsFirstChild) throws TTException { assert paramNewNode != null; if (paramNewNode instanceof ITreeStructData) { final ITreeStructData strucNode = (ITreeStructData)paramNewNode; final ITreeStructData parent = (ITreeStructData)getPtx().getData(paramNewNode.getParentKey()); parent.incrementChildCount(); if (addAsFirstChild) { parent.setFirstChildKey(paramNewNode.getDataKey()); } getPtx().setData(parent); if (strucNode.hasRightSibling()) { final ITreeStructData rightSiblingNode = (ITreeStructData)getPtx().getData(strucNode.getRightSiblingKey()); rightSiblingNode.setLeftSiblingKey(paramNewNode.getDataKey()); getPtx().setData(rightSiblingNode); } if (strucNode.hasLeftSibling()) { final ITreeStructData leftSiblingNode = (ITreeStructData)getPtx().getData(strucNode.getLeftSiblingKey()); leftSiblingNode.setRightSiblingKey(paramNewNode.getDataKey()); getPtx().setData(leftSiblingNode); } } } // //////////////////////////////////////////////////////////// // end of insert operation // //////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////// // remove operation // //////////////////////////////////////////////////////////// /** * Adapting everything for remove operations. * * @param pOldNode * pointer of the old node to be replaces * @throws TTIOException * if anything weird happens */ private void adaptForRemove(final ITreeStructData pOldNode) throws TTException { assert pOldNode != null; // Adapt left sibling node if there is one. if (pOldNode.hasLeftSibling()) { final ITreeStructData leftSibling = (ITreeStructData)getPtx().getData(pOldNode.getLeftSiblingKey()); leftSibling.setRightSiblingKey(pOldNode.getRightSiblingKey()); getPtx().setData(leftSibling); } // Adapt right sibling node if there is one. if (pOldNode.hasRightSibling()) { final ITreeStructData rightSibling = (ITreeStructData)getPtx().getData(pOldNode.getRightSiblingKey()); rightSibling.setLeftSiblingKey(pOldNode.getLeftSiblingKey()); getPtx().setData(rightSibling); } // Adapt parent, if node has now left sibling it is a first child. final ITreeStructData parent = (ITreeStructData)getPtx().getData(pOldNode.getParentKey()); if (!pOldNode.hasLeftSibling()) { parent.setFirstChildKey(pOldNode.getRightSiblingKey()); } parent.decrementChildCount(); getPtx().setData(parent); if (pOldNode.getKind() == IConstants.ELEMENT) { // removing attributes for (int i = 0; i < ((ElementNode)pOldNode).getAttributeCount(); i++) { moveTo(((ElementNode)pOldNode).getAttributeKey(i)); getPtx().removeData(mDelegate.getCurrentNode()); } // removing namespaces moveTo(pOldNode.getDataKey()); for (int i = 0; i < ((ElementNode)pOldNode).getNamespaceCount(); i++) { moveTo(((ElementNode)pOldNode).getNamespaceKey(i)); getPtx().removeData(mDelegate.getCurrentNode()); } } // Remove old node. getPtx().removeData(pOldNode); } // //////////////////////////////////////////////////////////// // end of remove operation // //////////////////////////////////////////////////////////// /** * Getter for superclasses. * * @return The state of this transaction. */ private BucketWriteTrx getPtx() { return (BucketWriteTrx)mDelegate.mPageReadTrx; } /** * Adapting the structure with a hash for all ancestors only with insert. * * @throws TTIOException * of anything weird happened. */ private void adaptHashesWithAdd() throws TTException { switch (mHashKind) { case Rolling: rollingAdd(); break; case Postorder: postorderAdd(); break; default: } } /** * Adapting the structure with a hash for all ancestors only with remove. * * @throws TTIOException * of anything weird happened. */ private void adaptHashesWithRemove() throws TTException { switch (mHashKind) { case Rolling: rollingRemove(); break; case Postorder: postorderRemove(); break; default: } } /** * Adapting the structure with a hash for all ancestors only with update. * * @param paramOldHash * paramOldHash to be removed * @throws TTIOException * of anything weird happened. */ private void adaptHashedWithUpdate(final long paramOldHash) throws TTException { switch (mHashKind) { case Rolling: rollingUpdate(paramOldHash); break; case Postorder: postorderAdd(); break; default: } } /** * Removal operation for postorder hash computation. * * @throws TTIOException * if anything weird happens */ private void postorderRemove() throws TTException { moveTo(mDelegate.getCurrentNode().getParentKey()); postorderAdd(); } /** * Adapting the structure with a rolling hash for all ancestors only with * insert. * * @throws TTIOException * if anything weird happened */ private void postorderAdd() throws TTException { // start with hash to add final long startKey = mDelegate.getCurrentNode().getDataKey(); // long for adapting the hash of the parent long hashCodeForParent = 0; // adapting the parent if the current node is no structural one. if (!(mDelegate.getCurrentNode() instanceof ITreeStructData)) { getPtx().getData(mDelegate.getCurrentNode().getDataKey()); mDelegate.getCurrentNode().setHash(mDelegate.getCurrentNode().hashCode()); getPtx().setData(mDelegate.getCurrentNode()); moveTo(mDelegate.getCurrentNode().getParentKey()); } // Cursor to root ITreeStructData cursorToRoot; do { synchronized (mDelegate.getCurrentNode()) { cursorToRoot = (ITreeStructData)getPtx().getData(mDelegate.getCurrentNode().getDataKey()); hashCodeForParent = mDelegate.getCurrentNode().hashCode() + hashCodeForParent * PRIME; // Caring about attributes and namespaces if node is an element. if (cursorToRoot.getKind() == IConstants.ELEMENT) { final ElementNode currentElement = (ElementNode)cursorToRoot; // setting the attributes and namespaces for (int i = 0; i < ((ElementNode)cursorToRoot).getAttributeCount(); i++) { moveTo(currentElement.getAttributeKey(i)); hashCodeForParent = mDelegate.getCurrentNode().hashCode() + hashCodeForParent * PRIME; } for (int i = 0; i < ((ElementNode)cursorToRoot).getNamespaceCount(); i++) { moveTo(currentElement.getNamespaceKey(i)); hashCodeForParent = mDelegate.getCurrentNode().hashCode() + hashCodeForParent * PRIME; } moveTo(cursorToRoot.getDataKey()); } // Caring about the children of a node if (moveTo(((ITreeStructData)getNode()).getFirstChildKey())) { do { hashCodeForParent = mDelegate.getCurrentNode().getHash() + hashCodeForParent * PRIME; } while (moveTo(((ITreeStructData)getNode()).getRightSiblingKey())); moveTo(((ITreeStructData)getNode()).getParentKey()); } // setting hash and resetting hash cursorToRoot.setHash(hashCodeForParent); getPtx().setData(cursorToRoot); hashCodeForParent = 0; } } while (moveTo(cursorToRoot.getParentKey())); moveTo(startKey); } /** * Adapting the structure with a rolling hash for all ancestors only with * update. * * @param paramOldHash * paramOldHash to be removed * @throws TTIOException * if anything weird happened */ private void rollingUpdate(final long paramOldHash) throws TTException { final ITreeData newNode = mDelegate.getCurrentNode(); final long newNodeHash = newNode.hashCode(); long resultNew = newNode.hashCode(); // go the path to the root do { synchronized (mDelegate.getCurrentNode()) { getPtx().getData(mDelegate.getCurrentNode().getDataKey()); if (mDelegate.getCurrentNode().getDataKey() == newNode.getDataKey()) { resultNew = mDelegate.getCurrentNode().getHash() - paramOldHash; resultNew = resultNew + newNodeHash; } else { resultNew = mDelegate.getCurrentNode().getHash() - (paramOldHash * PRIME); resultNew = resultNew + newNodeHash * PRIME; } mDelegate.getCurrentNode().setHash(resultNew); getPtx().setData(mDelegate.getCurrentNode()); } } while (moveTo(mDelegate.getCurrentNode().getParentKey())); mDelegate.setCurrentNode(newNode); } /** * Adapting the structure with a rolling hash for all ancestors only with * remove. * * @throws TTIOException * if anything weird happened */ private void rollingRemove() throws TTException { final ITreeData startNode = mDelegate.getCurrentNode(); long hashToRemove = startNode.getHash(); long hashToAdd = 0; long newHash = 0; // go the path to the root do { synchronized (mDelegate.getCurrentNode()) { getPtx().getData(mDelegate.getCurrentNode().getDataKey()); if (mDelegate.getCurrentNode().getDataKey() == startNode.getDataKey()) { // the begin node is always null newHash = 0; } else if (mDelegate.getCurrentNode().getDataKey() == startNode.getParentKey()) { // the parent node is just removed newHash = mDelegate.getCurrentNode().getHash() - (hashToRemove * PRIME); hashToRemove = mDelegate.getCurrentNode().getHash(); } else { // the ancestors are all touched regarding the modification newHash = mDelegate.getCurrentNode().getHash() - (hashToRemove * PRIME); newHash = newHash + hashToAdd * PRIME; hashToRemove = mDelegate.getCurrentNode().getHash(); } mDelegate.getCurrentNode().setHash(newHash); hashToAdd = newHash; getPtx().setData(mDelegate.getCurrentNode()); } } while (moveTo(mDelegate.getCurrentNode().getParentKey())); mDelegate.setCurrentNode(startNode); } /** * Adapting the structure with a rolling hash for all ancestors only with * insert. * * @throws TTIOException * if anything weird happened */ private void rollingAdd() throws TTException { // start with hash to add final ITreeData startNode = mDelegate.getCurrentNode(); long hashToAdd = startNode.hashCode(); long newHash = 0; long possibleOldHash = 0; // go the path to the root do { synchronized (mDelegate.getCurrentNode()) { getPtx().getData(mDelegate.getCurrentNode().getDataKey()); if (mDelegate.getCurrentNode().getDataKey() == startNode.getDataKey()) { // at the beginning, take the hashcode of the node only newHash = hashToAdd; } else if (mDelegate.getCurrentNode().getDataKey() == startNode.getParentKey()) { // at the parent level, just add the node possibleOldHash = mDelegate.getCurrentNode().getHash(); newHash = possibleOldHash + hashToAdd * PRIME; hashToAdd = newHash; } else { // at the rest, remove the existing old key for this element // and add the new one newHash = mDelegate.getCurrentNode().getHash() - (possibleOldHash * PRIME); newHash = newHash + hashToAdd * PRIME; hashToAdd = newHash; possibleOldHash = mDelegate.getCurrentNode().getHash(); } mDelegate.getCurrentNode().setHash(newHash); getPtx().setData(mDelegate.getCurrentNode()); } } while (moveTo(mDelegate.getCurrentNode().getParentKey())); mDelegate.setCurrentNode(startNode); } /** * {@inheritDoc} */ @Override public boolean moveTo(long pKey) throws TTIOException { return mDelegate.moveTo(pKey); } /** * {@inheritDoc} */ @Override public boolean moveToAttribute(int pIndex) throws TTIOException { return mDelegate.moveToAttribute(pIndex); } /** * {@inheritDoc} */ @Override public boolean moveToNamespace(int pIndex) throws TTIOException { return mDelegate.moveToNamespace(pIndex); } /** * {@inheritDoc} */ @Override public String getValueOfCurrentNode() { return mDelegate.getValueOfCurrentNode(); } /** * {@inheritDoc} */ @Override public QName getQNameOfCurrentNode() { return mDelegate.getQNameOfCurrentNode(); } /** * {@inheritDoc} */ @Override public String getTypeOfCurrentNode() { return mDelegate.getTypeOfCurrentNode(); } /** * {@inheritDoc} */ @Override public String nameForKey(int pKey) { return mDelegate.nameForKey(pKey); } /** * {@inheritDoc} */ @Override public ITreeData getNode() { return mDelegate.getNode(); } /** * {@inheritDoc} */ @Override public boolean isClosed() { return mDelegate.isClosed(); } /** * {@inheritDoc} */ @Override public IBucketWriteTrx getPageWtx() throws TTException { return getPtx(); } /** * Building name consisting out of prefix and name. NamespaceUri is not used * over here. * * @param pQName * the {@link QName} of an element * @return a string with [prefix:]localname */ public static String buildName(final QName pQName) { if (pQName == null) { throw new NullPointerException("mQName must not be null!"); } String name; if (pQName.getPrefix().isEmpty()) { name = pQName.getLocalPart(); } else { name = new StringBuilder(pQName.getPrefix()).append(":").append(pQName.getLocalPart()).toString(); } return name; } /** * {@inheritDoc} */ @Override public String toString() { return toStringHelper(this).add("mSession", mSession).add("mHashKind", mHashKind).add("mDelegate", mDelegate).toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy