/** * Copyright (c) 2002-2010 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.neo4j.index.impl.btree; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Relationship; import org.neo4j.index.impl.btree.BTree.RelTypes; import org.neo4j.index.impl.map.BTreeMap; /** * Wraps the functionality of one entry in a {@link BTree}. */ public class KeyEntry { static final String KEY = "key"; static final String VALUE = "val"; static final String KEY_VALUE = "key_val"; private Relationship entryRelationship; private TreeNode treeNode; KeyEntry( TreeNode treeNode, Relationship underlyingRelationship ) { assert treeNode != null; assert underlyingRelationship != null; this.treeNode = treeNode; this.entryRelationship = underlyingRelationship; } Relationship getUnderlyingRelationship() { return entryRelationship; } TreeNode getTreeNode() { return treeNode; } private BTree getBTree() { return treeNode.getBTree(); } TreeNode getBeforeSubTree() { Relationship subTreeRel = getStartNode().getSingleRelationship( RelTypes.SUB_TREE, Direction.OUTGOING ); if ( subTreeRel != null ) { return new TreeNode( getBTree(), subTreeRel.getEndNode() ); } return null; } TreeNode getAfterSubTree() { Relationship subTreeRel = getEndNode().getSingleRelationship( RelTypes.SUB_TREE, Direction.OUTGOING ); if ( subTreeRel != null ) { return new TreeNode( getBTree(), subTreeRel.getEndNode() ); } return null; } KeyEntry getNextKey() { Relationship nextKeyRel = getEndNode().getSingleRelationship( RelTypes.KEY_ENTRY, Direction.OUTGOING ); if ( nextKeyRel != null ) { return new KeyEntry( getTreeNode(), nextKeyRel ); } return null; } KeyEntry getPreviousKey() { Relationship prevKeyRel = getStartNode().getSingleRelationship( RelTypes.KEY_ENTRY, Direction.INCOMING ); if ( prevKeyRel != null ) { return new KeyEntry( getTreeNode(), prevKeyRel ); } return null; } /** * Returns the key for this entry, the key added via * {@link BTree#addEntry(long, Object)}. * * @return the key for this entry. */ public long getKey() { return (Long) entryRelationship.getProperty( KEY ); } void setKey( long key ) { entryRelationship.setProperty( KEY, key ); } /** * Returns the value for this entry. This is the value added via * {@link BTree#addEntry(long, Object)}. * * @return the value for this entry. */ public Object getValue() { return entryRelationship.getProperty( VALUE ); } /** * Sets or changes the value for this entry. The type of the value must * be one of the property types supported by neo4j. * * @param value the new value for this entry. */ public void setValue( Object value ) { entryRelationship.setProperty( VALUE, value ); } /** * Set the key value, it represents the actual key which we can derive the * {@link #getKey()} from, f.ex. a String. This is optional and is used in * some implementations, f.ex {@link BTreeMap}. * * @param keyValue the actual value which the key ({@link #getKey()}) is * derived from. */ public void setKeyValue( Object keyValue ) { entryRelationship.setProperty( KEY_VALUE, keyValue ); } /** * Returns the actual key value which the key ({@link #getKey()}) can be * derived from, f.ex. a String. * * @return the actual key value. */ public Object getKeyValue() { return entryRelationship.getProperty( KEY_VALUE, null ); } /** * Removes this entry from the b-tree. */ public void remove() { treeNode.removeEntry( this.getKey() ); } @Override public String toString() { return "Entry[" + getKey() + "," + getValue() + "]"; } boolean isLeaf() { if ( getUnderlyingRelationship().getStartNode().getSingleRelationship( RelTypes.SUB_TREE, Direction.OUTGOING ) != null ) { assert getUnderlyingRelationship().getEndNode(). getSingleRelationship( RelTypes.SUB_TREE, Direction.OUTGOING ) != null; return false; } assert getUnderlyingRelationship().getEndNode().getSingleRelationship( RelTypes.SUB_TREE, Direction.OUTGOING ) == null; return true; } Node getStartNode() { return entryRelationship.getStartNode(); } Node getEndNode() { return entryRelationship.getEndNode(); } void move( TreeNode node, Node startNode, Node endNode ) { assert node != null; this.treeNode = node; long key = getKey(); Object value = getValue(); Object keyValue = getKeyValue(); entryRelationship.delete(); entryRelationship = startNode.createRelationshipTo( endNode, RelTypes.KEY_ENTRY ); setKey( key ); setValue( value ); if ( keyValue != null ) { setKeyValue( keyValue ); } } }