/*
* 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.kernel.impl.nioneo.store;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* This class contains the references to the "NodeStore,RelationshipStore,
* PropertyStore and RelationshipTypeStore". NeoStore doesn't actually "store"
* anything but extends the AbstractStore for the "type and version" validation
* performed in there.
*/
public class NeoStore extends AbstractStore
{
// neo store version, store should end with this string
// (byte encoded)
private static final String VERSION = "NeoStore v0.9.5";
// 3 longs in header (long + in use), time | random | version
private static final int RECORD_SIZE = 9;
private NodeStore nodeStore;
private PropertyStore propStore;
private RelationshipStore relStore;
private RelationshipTypeStore relTypeStore;
private final int REL_GRAB_SIZE;
public NeoStore( Map<?,?> config )
{
super( (String) config.get( "neo_store" ), config );
if ( getConfig() != null )
{
String grabSize = (String) getConfig().get( "relationship_grab_size" );
if ( grabSize != null )
{
REL_GRAB_SIZE = Integer.parseInt( grabSize );
}
else
{
REL_GRAB_SIZE = 100;
}
}
else
{
REL_GRAB_SIZE = 100;
}
}
public NeoStore( String fileName )
{
super( fileName );
REL_GRAB_SIZE = 100;
}
/**
* Initializes the node,relationship,property and relationship type stores.
*/
@Override
protected void initStorage()
{
relTypeStore = new RelationshipTypeStore( getStorageFileName()
+ ".relationshiptypestore.db", getConfig() );
propStore = new PropertyStore( getStorageFileName()
+ ".propertystore.db", getConfig() );
relStore = new RelationshipStore( getStorageFileName()
+ ".relationshipstore.db", getConfig() );
nodeStore = new NodeStore( getStorageFileName() + ".nodestore.db",
getConfig() );
}
/**
* Closes the node,relationship,property and relationship type stores.
*/
@Override
protected void closeStorage()
{
if ( relTypeStore != null )
{
relTypeStore.close();
relTypeStore = null;
}
if ( propStore != null )
{
propStore.close();
propStore = null;
}
if ( relStore != null )
{
relStore.close();
relStore = null;
}
if ( nodeStore != null )
{
nodeStore.close();
nodeStore = null;
}
}
public void flushAll()
{
if ( relTypeStore == null || propStore == null || relStore == null ||
nodeStore == null )
{
return;
}
relTypeStore.flushAll();
propStore.flushAll();
relStore.flushAll();
nodeStore.flushAll();
}
public String getTypeAndVersionDescriptor()
{
return VERSION;
}
public int getRecordSize()
{
return RECORD_SIZE;
}
private static final Random r = new Random( System.currentTimeMillis() );
/**
* Creates the neo,node,relationship,property and relationship type stores.
*
* @param fileName
* The name of store
* @throws IOException
* If unable to create stores or name null
*/
public static void createStore( String fileName, Map<?,?> config )
{
createEmptyStore( fileName, VERSION );
NodeStore.createStore( fileName + ".nodestore.db" );
RelationshipStore.createStore( fileName + ".relationshipstore.db" );
PropertyStore.createStore( fileName + ".propertystore.db", config );
RelationshipTypeStore.createStore( fileName
+ ".relationshiptypestore.db" );
NeoStore neoStore = new NeoStore( fileName );
// created time | random long | backup version
neoStore.nextId(); neoStore.nextId(); neoStore.nextId();
long time = System.currentTimeMillis();
neoStore.setCreationTime( time );
neoStore.setRandomNumber( r.nextLong() );
neoStore.setVersion( 0 );
neoStore.close();
}
public long getCreationTime()
{
return getRecord( 0 );
}
public void setCreationTime( long time )
{
setRecord( 0, time );
}
public long getRandomNumber()
{
return getRecord( 1 );
}
public void setRandomNumber( long nr )
{
setRecord( 1, nr );
}
public void setRecoveredStatus( boolean status )
{
if ( status )
{
setRecovered();
}
else
{
unsetRecovered();
}
}
public long getVersion()
{
return getRecord( 2 );
}
public void setVersion( long version )
{
setRecord( 2, version );
}
public long incrementVersion()
{
long current = getVersion();
setVersion( current + 1 );
return current;
}
private long getRecord( int id )
{
PersistenceWindow window = acquireWindow( id, OperationType.READ );
try
{
Buffer buffer = window.getOffsettedBuffer( id );
buffer.get();
return buffer.getLong();
}
finally
{
releaseWindow( window );
}
}
private void setRecord( int id, long value )
{
PersistenceWindow window = acquireWindow( id, OperationType.WRITE );
try
{
Buffer buffer = window.getOffsettedBuffer( id );
buffer.put( Record.IN_USE.byteValue() ).putLong( value );
}
finally
{
releaseWindow( window );
}
}
/**
* Returns the node store.
*
* @return The node store
*/
public NodeStore getNodeStore()
{
return nodeStore;
}
/**
* The relationship store.
*
* @return The relationship store
*/
public RelationshipStore getRelationshipStore()
{
return relStore;
}
/**
* Returns the relationship type store.
*
* @return The relationship type store
*/
public RelationshipTypeStore getRelationshipTypeStore()
{
return relTypeStore;
}
/**
* Returns the property store.
*
* @return The property store
*/
public PropertyStore getPropertyStore()
{
return propStore;
}
@Override
public void makeStoreOk()
{
relTypeStore.makeStoreOk();
propStore.makeStoreOk();
relStore.makeStoreOk();
nodeStore.makeStoreOk();
super.makeStoreOk();
}
public void rebuildIdGenerators()
{
relTypeStore.rebuildIdGenerators();
propStore.rebuildIdGenerators();
relStore.rebuildIdGenerators();
nodeStore.rebuildIdGenerators();
super.rebuildIdGenerators();
}
public void updateIdGenerators()
{
this.updateHighId();
relTypeStore.updateIdGenerators();
propStore.updateIdGenerators();
relStore.updateHighId();
nodeStore.updateHighId();
}
@Override
protected boolean versionFound( String version )
{
if ( !version.startsWith( "NeoStore" ) )
{
// non clean shutdown, need to do recover with right neo
return false;
}
if ( version.equals( "NeoStore v0.9.3" ) )
{
ByteBuffer buffer = ByteBuffer.wrap( new byte[ 3 * RECORD_SIZE ] );
long time = System.currentTimeMillis();
long random = r.nextLong();
buffer.put( Record.IN_USE.byteValue() ).putLong( time );
buffer.put( Record.IN_USE.byteValue() ).putLong( random );
buffer.put( Record.IN_USE.byteValue() ).putLong( 0 );
buffer.flip();
try
{
getFileChannel().write( buffer, 0 );
}
catch ( IOException e )
{
throw new UnderlyingStorageException( e );
}
rebuildIdGenerator();
closeIdGenerator();
return true;
}
else if ( version.equals( "NeoStore v0.9.4" ) )
{
rebuildIdGenerator();
closeIdGenerator();
return true;
}
throw new IllegalStoreVersionException( "Store version [" + version +
"]. Please make sure you are not running old Neo4j kernel " +
" towards a store that has been created by newer version " +
" of Neo4j." );
}
public int getRelationshipGrabSize()
{
return REL_GRAB_SIZE;
}
public List<WindowPoolStats> getAllWindowPoolStats()
{
List<WindowPoolStats> list = new ArrayList<WindowPoolStats>();
list.addAll( nodeStore.getAllWindowPoolStats() );
list.addAll( propStore.getAllWindowPoolStats() );
list.addAll( relStore.getAllWindowPoolStats() );
list.addAll( relTypeStore.getAllWindowPoolStats() );
return list;
}
}