/* * Copyright (c) 2002-2009 "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; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Node; import org.neo4j.index.impl.btree.KeyEntry; /** * A "multi" index implementation using * {@link org.neo4j.index.impl.btree.BTree BTree} that can index multiple nodes * per key. They key is checked for equality using both {@link #hashCode()} and * {@link #equals(Object)} methods. <p> * Note: this implementation is not thread safe (yet). * * This class isn't ready for general usage yet and use of it is discouraged. * * @deprecated */ public class MultiValueIndex extends AbstractIndex { /** * Creates/loads a index. The {@code underlyingNode} can either * be a new (just created) node or a node that already represents a * previously created index. * * @param name The unique name of the index or null if index already * created (using specified underlying node) * @param underlyingNode The underlying node representing the index * @param graphDb The embedded neo instance * @throws IllegalArgumentException if the underlying node is a index with * a different name set. */ public MultiValueIndex( String name, Node underlyingNode, GraphDatabaseService graphDb ) { super( name, underlyingNode, graphDb ); } @Override protected void addOrReplace( KeyEntry entry, long nodeId ) { Object value = entry.getValue(); if ( value.getClass().isArray() ) { long[] values = (long[]) value; long[] newValues = new long[values.length + 1]; boolean addNewValues = true; for ( int i = 0; i < values.length; i++ ) { if ( values[i] == nodeId ) { addNewValues = false; break; } newValues[i] = values[i]; } if ( addNewValues ) { newValues[newValues.length - 1] = nodeId; entry.setValue( newValues ); } } else { long currentId = (Long) value; if ( currentId != nodeId ) { long[] newValues = new long[2]; newValues[0] = currentId; newValues[1] = nodeId; entry.setValue( newValues ); } } } @Override protected void addOrReplace( Node node, long nodeId ) { Object value = node.getProperty( INDEX_VALUES ); if ( value.getClass().isArray() ) { long[] values = (long[]) value; long[] newValues = new long[values.length + 1]; boolean addNewValues = true; for ( int i = 0; i < values.length; i++ ) { if ( values[i] == nodeId ) { addNewValues = false; break; } newValues[i] = values[i]; } if ( addNewValues ) { newValues[newValues.length - 1] = nodeId; node.setProperty( INDEX_VALUES, newValues ); } } else { long currentId = (Long) value; if ( currentId != nodeId ) { long[] newValues = new long[2]; newValues[0] = currentId; newValues[1] = nodeId; node.setProperty( INDEX_VALUES, newValues ); } } } @Override protected boolean removeAllOrOne( Node node, long nodeId ) { Object value = node.getProperty( INDEX_VALUES ); if ( value.getClass().isArray() ) { long[] values = (long[]) value; if ( values.length == 1 ) { if ( values[0] == nodeId ) { return true; } return false; } long[] newValues = new long[values.length - 1]; int j = 0; for ( int i = 0; i < values.length; i++ ) { if ( values[i] != nodeId ) { newValues[j++] = values[i]; } } node.setProperty( INDEX_VALUES, newValues ); return false; } long currentId = (Long) value; if ( currentId == nodeId ) { return true; } return false; } @Override protected boolean removeAllOrOne( KeyEntry entry, long nodeId ) { Object value = entry.getValue(); if ( value.getClass().isArray() ) { long[] values = (long[]) value; if ( values.length == 1 ) { if ( values[0] == nodeId ) { return true; } return false; } long[] newValues = new long[values.length - 1]; int j = 0; for ( int i = 0; i < values.length; i++ ) { if ( values[i] != nodeId ) { newValues[j++] = values[i]; } } entry.setValue( newValues ); return false; } long currentId = (Long) value; if ( currentId == nodeId ) { return true; } return false; } @Override protected long[] getValues( KeyEntry entry ) { Object value = entry.getValue(); if ( value.getClass().isArray() ) { return (long[]) value; } long values[] = new long[1]; values[0] = (Long) value; return values; } @Override protected long[] getValues( Node node ) { Object value = node.getProperty( INDEX_VALUES ); if ( value.getClass().isArray() ) { return (long[]) value; } long values[] = new long[1]; values[0] = (Long) value; return values; } @Override protected String getIndexType() { return "multi"; } @Override protected long getSingleValue( KeyEntry entry ) { Object value = entry.getValue(); if ( value.getClass().isArray() ) { long[] ids = (long[]) value; if ( ids.length > 1 ) { throw new RuntimeException( "Multiple values found" ); } return ids[0]; } return (Long) value; } @Override protected long getSingleValue( Node entry ) { Object value = entry.getProperty( INDEX_VALUES ); if ( value.getClass().isArray() ) { long[] ids = (long[]) value; if ( ids.length > 1 ) { throw new RuntimeException( "Multiple values found" ); } return ids[0]; } return (Long) value; } }