Skip to content

Commit

Permalink
Make indexes platform independent
Browse files Browse the repository at this point in the history
The previous Base64 encoding could introduce new lines if the encoded
string was longer than a given number of bytes.  Since new line
encodings are platform dependent so were our indexes.  This change
fixes that by removing the new lines from the Base64 encoding and
provides a migration path from older versions of the database, i.e.,
indexes that might contain the problematic encoding as values will be
forcely rebuilt.

Bump store version up to '0.A.5' in order to fail when trying to use
stores from 2.2-M0{1,2,3}.

Small refactor around UpgredableDatabase: added method
hasCurrentVersion for checking if the store has the current and
avoiding using the NeoStoreUtil directly.
  • Loading branch information
davidegrohmann committed Feb 6, 2015
1 parent d0a1af6 commit ea86375
Show file tree
Hide file tree
Showing 34 changed files with 1,058 additions and 255 deletions.
Expand Up @@ -19,13 +19,14 @@
*/ */
package org.neo4j.consistency.checking.full; package org.neo4j.consistency.checking.full;


import org.junit.Test;

import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;

import java.util.Set;
import org.junit.Test;


import org.neo4j.collection.primitive.PrimitiveLongCollections; import org.neo4j.collection.primitive.PrimitiveLongCollections;
import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.collection.primitive.PrimitiveLongIterator;
Expand All @@ -47,13 +48,11 @@
import org.neo4j.register.Register; import org.neo4j.register.Register;


import static java.util.Arrays.asList; import static java.util.Arrays.asList;

import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;

import static org.neo4j.collection.primitive.PrimitiveLongCollections.emptyIterator; import static org.neo4j.collection.primitive.PrimitiveLongCollections.emptyIterator;
import static org.neo4j.kernel.api.properties.Property.stringProperty; import static org.neo4j.kernel.api.properties.Property.stringProperty;
import static org.neo4j.kernel.impl.store.record.IndexRule.constraintIndexRule; import static org.neo4j.kernel.impl.store.record.IndexRule.constraintIndexRule;
Expand Down Expand Up @@ -238,6 +237,12 @@ public int getIndexedCount( long nodeId, Object propertyValue )
return count; return count;
} }


@Override
public Set<Class> valueTypesInIndex()
{
throw new UnsupportedOperationException();
}

@Override @Override
public long sampleIndex( Register.DoubleLong.Out sampler ) public long sampleIndex( Register.DoubleLong.Out sampler )
{ {
Expand Down
Expand Up @@ -52,7 +52,7 @@ public static void assertConsistentStore( File dir ) throws ConsistencyCheckInco
dir.getAbsolutePath(), dir.getAbsolutePath(),
configuration, configuration,
ProgressMonitorFactory.NONE, ProgressMonitorFactory.NONE,
StringLogger.DEV_NULL StringLogger.SYSTEM_ERR
); );


assertTrue( result.isSuccessful() ); assertTrue( result.isSuccessful() );
Expand Down
Expand Up @@ -101,6 +101,8 @@
import org.neo4j.kernel.impl.store.StoreId; import org.neo4j.kernel.impl.store.StoreId;
import org.neo4j.kernel.impl.store.record.SchemaRule; import org.neo4j.kernel.impl.store.record.SchemaRule;
import org.neo4j.kernel.impl.storemigration.StoreUpgrader; import org.neo4j.kernel.impl.storemigration.StoreUpgrader;
import org.neo4j.kernel.impl.storemigration.StoreVersionCheck;
import org.neo4j.kernel.impl.storemigration.UpgradableDatabase;
import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory;
import org.neo4j.kernel.impl.transaction.TransactionMonitor; import org.neo4j.kernel.impl.transaction.TransactionMonitor;
import org.neo4j.kernel.impl.transaction.log.LogFile; import org.neo4j.kernel.impl.transaction.log.LogFile;
Expand Down Expand Up @@ -552,7 +554,8 @@ public void transactionRecovered( long txId )
// of the dependency tree, starting at the bottom // of the dependency tree, starting at the bottom
private void upgradeStore( File store, StoreUpgrader storeMigrationProcess, SchemaIndexProvider indexProvider ) private void upgradeStore( File store, StoreUpgrader storeMigrationProcess, SchemaIndexProvider indexProvider )
{ {
storeMigrationProcess.addParticipant( indexProvider.storeMigrationParticipant() ); UpgradableDatabase upgradableDatabase = new UpgradableDatabase( new StoreVersionCheck( fs ) );
storeMigrationProcess.addParticipant( indexProvider.storeMigrationParticipant( fs, upgradableDatabase ) );
storeMigrationProcess.migrateIfNeeded( store.getParentFile(), indexProvider, pageCache ); storeMigrationProcess.migrateIfNeeded( store.getParentFile(), indexProvider, pageCache );
} }


Expand Down
Expand Up @@ -19,17 +19,16 @@
*/ */
package org.neo4j.kernel.api.index; package org.neo4j.kernel.api.index;


import sun.misc.BASE64Encoder;

import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Array; import java.lang.reflect.Array;


import sun.misc.BASE64Encoder;

import org.neo4j.kernel.impl.util.Charsets; import org.neo4j.kernel.impl.util.Charsets;


public class ArrayEncoder public class ArrayEncoder
{ {
private static final byte[] LINE_ENDING = System.lineSeparator().getBytes();
private static final BASE64Encoder base64Encoder = new BASE64Encoder() private static final BASE64Encoder base64Encoder = new BASE64Encoder()
{ {
@Override @Override
Expand All @@ -38,12 +37,22 @@ protected void encodeBufferPrefix( OutputStream out ) throws IOException
// don't initialize the non-thread-safe state // don't initialize the non-thread-safe state
} }


@Override
protected void encodeBufferSuffix( OutputStream outputStream ) throws IOException
{
// nothing to do here
}

@Override
protected void encodeLinePrefix( OutputStream outputStream, int i ) throws IOException
{
// nothing to do here
}

@Override @Override
protected void encodeLineSuffix( OutputStream out ) throws IOException protected void encodeLineSuffix( OutputStream out ) throws IOException
{ {
// don't use the non-thread-safe state, instead do the same thing in a thread safe way, // don't use the non-thread-safe state, but do nothing
// although, this still makes the encoded value platform dependant...
out.write( LINE_ENDING );
} }
}; };


Expand Down
Expand Up @@ -19,6 +19,9 @@
*/ */
package org.neo4j.kernel.api.index; package org.neo4j.kernel.api.index;


import java.util.Collections;
import java.util.Set;

import org.neo4j.collection.primitive.PrimitiveLongCollections; import org.neo4j.collection.primitive.PrimitiveLongCollections;
import org.neo4j.collection.primitive.PrimitiveLongIterator; import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.graphdb.Resource; import org.neo4j.graphdb.Resource;
Expand Down Expand Up @@ -50,6 +53,12 @@ public int getIndexedCount( long nodeId, Object propertyValue )
return 0; return 0;
} }


@Override
public Set<Class> valueTypesInIndex()
{
return Collections.emptySet();
}

@Override @Override
public long sampleIndex( DoubleLong.Out result ) public long sampleIndex( DoubleLong.Out result )
{ {
Expand All @@ -68,6 +77,12 @@ public void close()
*/ */
int getIndexedCount( long nodeId, Object propertyValue ); int getIndexedCount( long nodeId, Object propertyValue );


/**
*
* @return the set of value types present in the index
*/
Set<Class> valueTypesInIndex();

/** /**
* Sample this index (on the current thread) * Sample this index (on the current thread)
* @param result contains the unique values and the sampled size * @param result contains the unique values and the sampled size
Expand Down Expand Up @@ -97,6 +112,12 @@ public int getIndexedCount( long nodeId, Object propertyValue )
return delegate.getIndexedCount( nodeId, propertyValue ); return delegate.getIndexedCount( nodeId, propertyValue );
} }


@Override
public Set<Class> valueTypesInIndex()
{
return delegate.valueTypesInIndex();
}

@Override @Override
public long sampleIndex( DoubleLong.Out result ) throws IndexNotFoundKernelException public long sampleIndex( DoubleLong.Out result ) throws IndexNotFoundKernelException
{ {
Expand Down
Expand Up @@ -28,10 +28,12 @@
import org.neo4j.graphdb.DependencyResolver.SelectionStrategy; import org.neo4j.graphdb.DependencyResolver.SelectionStrategy;
import org.neo4j.graphdb.ResourceIterator; import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.helpers.collection.IteratorUtil; import org.neo4j.helpers.collection.IteratorUtil;
import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.api.index.IndexingService; import org.neo4j.kernel.impl.api.index.IndexingService;
import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig; import org.neo4j.kernel.impl.api.index.sampling.IndexSamplingConfig;
import org.neo4j.kernel.impl.storemigration.StoreMigrationParticipant; import org.neo4j.kernel.impl.storemigration.StoreMigrationParticipant;
import org.neo4j.kernel.impl.storemigration.UpgradableDatabase;
import org.neo4j.kernel.lifecycle.LifecycleAdapter; import org.neo4j.kernel.lifecycle.LifecycleAdapter;


import static org.neo4j.graphdb.factory.GraphDatabaseSettings.store_dir; import static org.neo4j.graphdb.factory.GraphDatabaseSettings.store_dir;
Expand Down Expand Up @@ -96,41 +98,47 @@
* {@link #getOnlineAccessor(long, IndexConfiguration, IndexSamplingConfig) online accessor} to * {@link #getOnlineAccessor(long, IndexConfiguration, IndexSamplingConfig) online accessor} to
* write to the index. * write to the index.
*/ */
public abstract class SchemaIndexProvider extends LifecycleAdapter public abstract class SchemaIndexProvider extends LifecycleAdapter implements Comparable<SchemaIndexProvider>
implements Comparable<SchemaIndexProvider>
{ {
public static final SchemaIndexProvider NO_INDEX_PROVIDER = public static final SchemaIndexProvider NO_INDEX_PROVIDER =
new SchemaIndexProvider( new Descriptor("no-index-provider", "1.0"), -1 ) new SchemaIndexProvider( new Descriptor( "no-index-provider", "1.0" ), -1 )
{ {
private final IndexAccessor singleWriter = new IndexAccessor.Adapter(); private final IndexAccessor singleWriter = new IndexAccessor.Adapter();
private final IndexPopulator singlePopulator = new IndexPopulator.Adapter(); private final IndexPopulator singlePopulator = new IndexPopulator.Adapter();


@Override @Override
public IndexAccessor getOnlineAccessor( long indexId, IndexConfiguration config, public IndexAccessor getOnlineAccessor( long indexId, IndexConfiguration config,
IndexSamplingConfig samplingConfig ) IndexSamplingConfig samplingConfig )
{ {
return singleWriter; return singleWriter;
} }


@Override @Override
public IndexPopulator getPopulator( long indexId, IndexDescriptor descriptor, IndexConfiguration config, public IndexPopulator getPopulator( long indexId, IndexDescriptor descriptor, IndexConfiguration config,
IndexSamplingConfig samplingConfig ) IndexSamplingConfig samplingConfig )
{ {
return singlePopulator; return singlePopulator;
} }


@Override @Override
public InternalIndexState getInitialState( long indexId ) public InternalIndexState getInitialState( long indexId )
{ {
return InternalIndexState.POPULATING; return InternalIndexState.POPULATING;
} }


@Override @Override
public String getPopulationFailure( long indexId ) throws IllegalStateException public StoreMigrationParticipant storeMigrationParticipant( FileSystemAbstraction fs,
{ UpgradableDatabase upgradableDatabase )
throw new IllegalStateException(); {
} return StoreMigrationParticipant.NOT_PARTICIPATING;
}; }

@Override
public String getPopulationFailure( long indexId ) throws IllegalStateException
{
throw new IllegalStateException();
}
};


public static final SelectionStrategy HIGHEST_PRIORITIZED_OR_NONE = public static final SelectionStrategy HIGHEST_PRIORITIZED_OR_NONE =
new SelectionStrategy() new SelectionStrategy()
Expand Down Expand Up @@ -238,10 +246,8 @@ public static File getRootDirectory( File storeDir, String key )
return new File( new File( new File( storeDir, "schema" ), "index" ), key ); return new File( new File( new File( storeDir, "schema" ), "index" ), key );
} }


public StoreMigrationParticipant storeMigrationParticipant() public abstract StoreMigrationParticipant storeMigrationParticipant( FileSystemAbstraction fs,
{ UpgradableDatabase upgradableDatabase );
return StoreMigrationParticipant.NOT_PARTICIPATING;
}


/** /**
* Provides a snapshot of meta files about this index provider, not the indexes themselves. * Provides a snapshot of meta files about this index provider, not the indexes themselves.
Expand Down
Expand Up @@ -54,4 +54,34 @@ public boolean backgroundSampling()
{ {
return backgroundSampling; return backgroundSampling;
} }

@Override
public boolean equals( Object o )
{
if ( this == o )
{
return true;
}

if ( o == null || getClass() != o.getClass() )
{
return false;
}

IndexSamplingConfig that = (IndexSamplingConfig) o;

return backgroundSampling == that.backgroundSampling &&
bufferSize == that.bufferSize &&
Double.compare( that.updateRatio, updateRatio ) == 0;
}

@Override
public int hashCode()
{
int result = bufferSize;
long temp = Double.doubleToLongBits( updateRatio );
result = 31 * result + (int) (temp ^ (temp >>> 32));
result = 31 * result + (backgroundSampling ? 1 : 0);
return result;
}
} }
Expand Up @@ -58,7 +58,7 @@
*/ */
public abstract class CommonAbstractStore implements IdSequence, AutoCloseable public abstract class CommonAbstractStore implements IdSequence, AutoCloseable
{ {
public static final String ALL_STORES_VERSION = "v0.A.4"; public static final String ALL_STORES_VERSION = "v0.A.5";
public static final String UNKNOWN_VERSION = "Unknown"; public static final String UNKNOWN_VERSION = "Unknown";
protected final Config configuration; protected final Config configuration;
protected final PageCache pageCache; protected final PageCache pageCache;
Expand Down

0 comments on commit ea86375

Please sign in to comment.