
org.neo4j.kernel.impl.index.IndexDefineCommand Maven / Gradle / Ivy
/*
* Copyright (c) 2002-2016 "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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.kernel.impl.index;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import org.neo4j.collection.primitive.Primitive;
import org.neo4j.collection.primitive.PrimitiveIntObjectMap;
import org.neo4j.kernel.impl.api.CommandVisitor;
import org.neo4j.kernel.impl.transaction.command.Command;
import org.neo4j.kernel.impl.transaction.command.NeoCommandType;
import org.neo4j.storageengine.api.WritableChannel;
import static java.lang.String.format;
import static org.neo4j.collection.primitive.Primitive.intObjectMap;
import static org.neo4j.kernel.impl.util.IoPrimitiveUtils.write2bLengthAndString;
/**
* A command which have to be first in the transaction. It will map index names
* and keys to ids so that all other commands in that transaction only refer
* to ids instead of names. This reduced the number of bytes needed for commands
* roughly 50% for transaction with more than a couple of commands in it,
* depending on the size of the value.
*
* After this command has been created it will act as a factory for other
* commands so that it can spit out correct index name and key ids.
*/
public class IndexDefineCommand extends Command
{
static final int HIGHEST_POSSIBLE_ID = 0xFFFF - 1; // -1 since the actual value -1 is reserved for all-ones
private final AtomicInteger nextIndexNameId = new AtomicInteger();
private final AtomicInteger nextKeyId = new AtomicInteger();
private Map indexNameIdRange;
private Map keyIdRange;
private PrimitiveIntObjectMap idToIndexName;
private PrimitiveIntObjectMap idToKey;
public IndexDefineCommand()
{
setIndexNameIdRange( new HashMap() );
setKeyIdRange( new HashMap() );
idToIndexName = intObjectMap( 16 );
idToKey = intObjectMap( 16 );
}
public void init( Map indexNames, Map keys )
{
this.setIndexNameIdRange( indexNames );
this.setKeyIdRange( keys );
idToIndexName = reverse( indexNames );
idToKey = reverse( keys );
}
private static PrimitiveIntObjectMap reverse( Map map )
{
PrimitiveIntObjectMap result = Primitive.intObjectMap( map.size() );
for ( Map.Entry entry : map.entrySet() )
{
result.put( entry.getValue().intValue(), entry.getKey() );
}
return result;
}
private static String getFromMap( PrimitiveIntObjectMap map, int id )
{
if ( id == -1 )
{
return null;
}
String result = map.get( id );
if ( result == null )
{
throw new IllegalArgumentException( "" + id );
}
return result;
}
public String getIndexName( int id )
{
return getFromMap( idToIndexName, id );
}
public String getKey( int id )
{
return getFromMap( idToKey, id );
}
public int getOrAssignIndexNameId( String indexName )
{
return getOrAssignId( indexNameIdRange, idToIndexName, nextIndexNameId, indexName );
}
public int getOrAssignKeyId( String key )
{
return getOrAssignId( keyIdRange, idToKey, nextKeyId, key );
}
private int getOrAssignId( Map stringToId, PrimitiveIntObjectMap idToString,
AtomicInteger nextId, String string )
{
if ( string == null )
{
return -1;
}
Integer id = stringToId.get( string );
if ( id != null )
{
return id;
}
int nextIdInt = nextId.incrementAndGet();
if ( nextIdInt > HIGHEST_POSSIBLE_ID ) // >= since the actual value -1 is reserved for all-ones
{
throw new IllegalStateException( format(
"Modifying more than %d indexes in a single transaction is not supported",
HIGHEST_POSSIBLE_ID + 1 ) );
}
id = nextIdInt;
stringToId.put( string, id );
idToString.put( id, string );
return id;
}
@Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}
if ( o == null || getClass() != o.getClass() )
{
return false;
}
if ( !super.equals( o ) )
{
return false;
}
IndexDefineCommand that = (IndexDefineCommand) o;
return nextIndexNameId.get() == that.nextIndexNameId.get() &&
nextKeyId.get() == that.nextKeyId.get() &&
Objects.equals( indexNameIdRange, that.indexNameIdRange ) &&
Objects.equals( keyIdRange, that.keyIdRange ) &&
Objects.equals( idToIndexName, that.idToIndexName ) &&
Objects.equals( idToKey, that.idToKey );
}
@Override
public int hashCode()
{
return Objects.hash( super.hashCode(), nextIndexNameId.get(), nextKeyId.get(), indexNameIdRange, keyIdRange,
idToIndexName, idToKey );
}
@Override
public boolean handle( CommandVisitor visitor ) throws IOException
{
return visitor.visitIndexDefineCommand( this );
}
public Map getIndexNameIdRange()
{
return indexNameIdRange;
}
public void setIndexNameIdRange( Map indexNameIdRange )
{
this.indexNameIdRange = indexNameIdRange;
}
public Map getKeyIdRange()
{
return keyIdRange;
}
public void setKeyIdRange( Map keyIdRange )
{
this.keyIdRange = keyIdRange;
}
@Override
public String toString()
{
return getClass().getSimpleName() + "[names:" + indexNameIdRange + ", keys:" + keyIdRange + "]";
}
@Override
public void serialize( WritableChannel channel ) throws IOException
{
channel.put( NeoCommandType.INDEX_DEFINE_COMMAND );
byte zero = 0;
IndexCommand.writeIndexCommandHeader( channel, zero, zero, zero, zero, zero, zero, zero );
writeMap( channel, getIndexNameIdRange() );
writeMap( channel, getKeyIdRange() );
}
private void writeMap( WritableChannel channel, Map map ) throws IOException
{
channel.put( (byte) map.size() );
for ( Map.Entry entry : map.entrySet() )
{
write2bLengthAndString( channel, entry.getKey() );
int id = entry.getValue();
channel.putShort( (short) id );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy