diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/IndexPartsCache.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/IndexPartsCache.java
new file mode 100644
index 000000000000..4ad314304765
--- /dev/null
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/IndexPartsCache.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002-2018 "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.schema;
+
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+abstract class IndexPartsCache implements Iterable
+{
+ final ConcurrentHashMap cache = new ConcurrentHashMap<>();
+ final Lock instantiateCloseLock = new ReentrantLock();
+ // guarded by instantiateCloseLock
+ private boolean closed;
+
+ void assertOpen()
+ {
+ if ( closed )
+ {
+ throw new IllegalStateException( this + " is already closed" );
+ }
+ }
+
+ void closeInstantiateCloseLock()
+ {
+ instantiateCloseLock.lock();
+ closed = true;
+ instantiateCloseLock.unlock();
+ }
+
+ @Override
+ public Iterator iterator()
+ {
+ return cache.values().iterator();
+ }
+}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexCache.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexCache.java
index 1d9f264a5759..44e6c43506ea 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexCache.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/SpatialIndexCache.java
@@ -21,10 +21,6 @@
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import org.neo4j.values.storable.CoordinateReferenceSystem;
@@ -37,13 +33,9 @@
*
* @param Type of parts
*/
-class SpatialIndexCache implements Iterable
+class SpatialIndexCache extends IndexPartsCache
{
private final Factory factory;
- private ConcurrentHashMap spatials = new ConcurrentHashMap<>();
- private final Lock instantiateCloseLock = new ReentrantLock();
- // guarded by instantiateCloseLock
- private boolean closed;
SpatialIndexCache( Factory factory )
{
@@ -59,7 +51,7 @@ class SpatialIndexCache implements Iterable
*/
T uncheckedSelect( CoordinateReferenceSystem crs )
{
- T existing = spatials.get( crs );
+ T existing = cache.get( crs );
if ( existing != null )
{
return existing;
@@ -72,7 +64,7 @@ T uncheckedSelect( CoordinateReferenceSystem crs )
try
{
assertOpen();
- return spatials.computeIfAbsent( crs, key ->
+ return cache.computeIfAbsent( crs, key ->
{
try
{
@@ -90,21 +82,6 @@ T uncheckedSelect( CoordinateReferenceSystem crs )
}
}
- protected void assertOpen()
- {
- if ( closed )
- {
- throw new IllegalStateException( this + " is already closed" );
- }
- }
-
- void closeInstantiateCloseLock()
- {
- instantiateCloseLock.lock();
- closed = true;
- instantiateCloseLock.unlock();
- }
-
/**
* Select the part corresponding to the given CoordinateReferenceSystem. Creates the part if needed,
* in which case an exception of type E might be thrown.
@@ -136,7 +113,7 @@ T select( CoordinateReferenceSystem crs ) throws IOException
*/
RESULT selectOrElse( CoordinateReferenceSystem crs, Function function, RESULT orElse )
{
- T part = spatials.get( crs );
+ T part = cache.get( crs );
if ( part == null )
{
return orElse;
@@ -152,12 +129,6 @@ void loadAll()
}
}
- @Override
- public Iterator iterator()
- {
- return spatials.values().iterator();
- }
-
/**
* Factory used by the SpatialIndexCache to create parts.
*
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexAccessor.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexAccessor.java
index 214b898d8433..a4920e47d1de 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexAccessor.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexAccessor.java
@@ -96,7 +96,7 @@ public void refresh()
@Override
public void close() throws IOException
{
- shutInstantiateCloseLock();
+ closeInstantiateCloseLock();
forAll( NativeSchemaIndexAccessor::close, this );
}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCache.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCache.java
index 20263208bdab..5b577da47542 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCache.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCache.java
@@ -21,10 +21,6 @@
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import org.neo4j.function.ThrowingSupplier;
@@ -46,7 +42,7 @@
*
* @param Type of parts
*/
-class TemporalIndexCache implements Iterable
+class TemporalIndexCache extends IndexPartsCache
{
private final Factory factory;
@@ -60,11 +56,6 @@ enum Offset
duration
}
- private final ConcurrentHashMap cache = new ConcurrentHashMap<>();
- private final Lock instantiateCloseLock = new ReentrantLock();
- // guarded by instantiateCloseLock
- private boolean closed;
-
TemporalIndexCache( Factory factory )
{
this.factory = factory;
@@ -163,21 +154,6 @@ RESULT selectOrElse( ValueGroup valueGroup, Function function
return cachedValue != null ? function.apply( cachedValue ) : orElse;
}
- private void assertOpen()
- {
- if ( closed )
- {
- throw new IllegalStateException( this + " is already closed" );
- }
- }
-
- void shutInstantiateCloseLock()
- {
- instantiateCloseLock.lock();
- closed = true;
- instantiateCloseLock.unlock();
- }
-
private T getOrCreatePart( Offset key, ThrowingSupplier factory ) throws UncheckedIOException
{
T existing = cache.get( key );
@@ -258,12 +234,6 @@ void loadAll()
}
}
- @Override
- public Iterator iterator()
- {
- return cache.values().iterator();
- }
-
/**
* Factory used by the TemporalIndexCache to create parts.
*
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPopulator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPopulator.java
index d150bc2b77b3..0b2fee3c0c98 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPopulator.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/TemporalIndexPopulator.java
@@ -109,7 +109,7 @@ public IndexUpdater newPopulatingUpdater( PropertyAccessor accessor )
@Override
public synchronized void close( boolean populationCompletedSuccessfully ) throws IOException
{
- shutInstantiateCloseLock();
+ closeInstantiateCloseLock();
for ( NativeSchemaIndexPopulator part : this )
{
part.close( populationCompletedSuccessfully );
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessor.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessor.java
index 0b0a5a46f804..9127008d9918 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessor.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessor.java
@@ -62,7 +62,7 @@ class FusionIndexAccessor extends FusionIndexBase implements Inde
@Override
public void drop() throws IOException
{
- forAll( IndexAccessor::drop, instanceSelector );
+ instanceSelector.forAll( IndexAccessor::drop );
dropAction.drop( indexId );
}
@@ -77,19 +77,19 @@ public IndexUpdater newUpdater( IndexUpdateMode mode )
@Override
public void force( IOLimiter ioLimiter ) throws IOException
{
- forAll( accessor -> accessor.force( ioLimiter ), instanceSelector );
+ instanceSelector.forAll( accessor -> accessor.force( ioLimiter ) );
}
@Override
public void refresh() throws IOException
{
- forAll( IndexAccessor::refresh, instanceSelector );
+ instanceSelector.forAll( IndexAccessor::refresh );
}
@Override
public void close() throws IOException
{
- forAll( IndexAccessor::close, instanceSelector );
+ instanceSelector.close( IndexAccessor::close );
}
@Override
@@ -103,7 +103,7 @@ public IndexReader newReader()
@Override
public BoundedIterable newAllEntriesReader()
{
- BoundedIterable[] entries = instancesAs( new BoundedIterable[INSTANCE_COUNT], IndexAccessor::newAllEntriesReader );
+ BoundedIterable[] entries = instanceSelector.instancesAs( new BoundedIterable[INSTANCE_COUNT], IndexAccessor::newAllEntriesReader );
return new BoundedIterable()
{
@Override
@@ -149,7 +149,8 @@ public Iterator iterator()
@Override
public ResourceIterator snapshotFiles() throws IOException
{
- return concatResourceIterators( iterator( instancesAs( new ResourceIterator[INSTANCE_COUNT], accessor -> accessor.snapshotFiles() ) ) );
+ return concatResourceIterators(
+ iterator( instanceSelector.instancesAs( new ResourceIterator[INSTANCE_COUNT], accessor -> accessor.snapshotFiles() ) ) );
}
@Override
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java
index 81dea2696d09..9abada43564d 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexBase.java
@@ -22,16 +22,11 @@
import java.util.Arrays;
import java.util.function.Function;
-import org.neo4j.collection.primitive.PrimitiveIntCollections;
import org.neo4j.function.ThrowingConsumer;
-import org.neo4j.function.ThrowingFunction;
import org.neo4j.helpers.Exceptions;
-import org.neo4j.kernel.api.index.IndexProvider;
import org.neo4j.values.storable.Value;
import org.neo4j.values.storable.ValueGroup;
-import static org.neo4j.kernel.impl.index.schema.fusion.SlotSelector.INSTANCE_COUNT;
-
/**
* Acting as a simplifier for the multiplexing that is going in inside a fusion index. A fusion index consists of multiple parts,
* each handling one or more value groups. Each instance, be it a reader, populator or accessor should extend this class
@@ -52,67 +47,6 @@ public abstract class FusionIndexBase
this.instanceSelector = instanceSelector;
}
- /**
- * Short-hand for calling the static {@link #instancesAs(InstanceSelector, Object[], ThrowingFunction)}, here with the local {@link #instanceSelector}.
- */
- R[] instancesAs( R[] target, ThrowingFunction converter ) throws E
- {
- return instancesAs( instanceSelector, target, converter );
- }
-
- /**
- * Convenience method typically for calling a method on each of the sub-parts of a fusion entity,
- * one which creates another instance. All those instances are returned as an array, or actually put into an array
- * created by the caller to avoid reflection to instantiate the array.
- *
- * @param instanceSelector {@link InstanceSelector} to use as the source.
- * @param target array to put the created instances into, also returned.
- * @param converter {@link ThrowingFunction} which converts from the source to target instance.
- * @param type of source instance.
- * @param type of target instance.
- * @param type of exception that converter may throw.
- * @return the target array which was passed in, now populated.
- * @throws E exception from converter.
- */
- static T[] instancesAs( InstanceSelector instanceSelector, T[] target, ThrowingFunction converter ) throws E
- {
- for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
- {
- target[slot] = converter.apply( instanceSelector.select( slot ) );
- }
- return target;
- }
-
- static void forInstantiated( ThrowingConsumer consumer, InstanceSelector instanceSelector ) throws E
- {
- E exception = null;
- for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
- {
- T instance = instanceSelector.getIfInstantiated( slot );
- if ( instance != null )
- {
- exception = consume( exception, consumer, instance );
- }
- }
- if ( exception != null )
- {
- throw exception;
- }
- }
-
- public static void forAll( ThrowingConsumer consumer, InstanceSelector instanceSelector ) throws E
- {
- E exception = null;
- for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
- {
- exception = consume( exception, consumer, instanceSelector.select( slot ) );
- }
- if ( exception != null )
- {
- throw exception;
- }
- }
-
/**
* See {@link #forAll(ThrowingConsumer, Object[])}
*
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulator.java
index b735414d5413..118e81e41809 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulator.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulator.java
@@ -53,13 +53,13 @@ class FusionIndexPopulator extends FusionIndexBase implements In
public void create() throws IOException
{
dropAction.drop( indexId, archiveFailedIndex );
- forAll( IndexPopulator::create, instanceSelector );
+ instanceSelector.forAll( IndexPopulator::create );
}
@Override
public void drop() throws IOException
{
- forAll( IndexPopulator::drop, instanceSelector );
+ instanceSelector.forAll( IndexPopulator::drop );
dropAction.drop( indexId );
}
@@ -105,13 +105,13 @@ public IndexUpdater newPopulatingUpdater( PropertyAccessor accessor )
@Override
public void close( boolean populationCompletedSuccessfully ) throws IOException
{
- forAll( populator -> populator.close( populationCompletedSuccessfully ), instanceSelector );
+ instanceSelector.close( populator -> populator.close( populationCompletedSuccessfully ) );
}
@Override
public void markAsFailed( String failure ) throws IOException
{
- forAll( populator -> populator.markAsFailed( failure ), instanceSelector );
+ instanceSelector.forAll( populator -> populator.markAsFailed( failure ) );
}
@Override
@@ -123,6 +123,6 @@ public void includeSample( IndexEntryUpdate> update )
@Override
public IndexSample sampleResult()
{
- return combineSamples( instancesAs( new IndexSample[INSTANCE_COUNT], IndexPopulator::sampleResult ) );
+ return combineSamples( instanceSelector.instancesAs( new IndexSample[INSTANCE_COUNT], IndexPopulator::sampleResult ) );
}
}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java
index 522797672be0..5aded0c65345 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexProvider.java
@@ -43,8 +43,6 @@
import static org.neo4j.internal.kernel.api.InternalIndexState.FAILED;
import static org.neo4j.internal.kernel.api.InternalIndexState.POPULATING;
-import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.forAll;
-import static org.neo4j.kernel.impl.index.schema.fusion.FusionIndexBase.instancesAs;
import static org.neo4j.kernel.impl.index.schema.fusion.SlotSelector.INSTANCE_COUNT;
import static org.neo4j.kernel.impl.index.schema.fusion.SlotSelector.LUCENE;
import static org.neo4j.kernel.impl.index.schema.fusion.SlotSelector.NUMBER;
@@ -102,7 +100,7 @@ private void fillProvidersArray( IndexProvider[] providers,
public IndexPopulator getPopulator( long indexId, SchemaIndexDescriptor descriptor, IndexSamplingConfig samplingConfig )
{
IndexPopulator[] populators =
- instancesAs( providers, new IndexPopulator[INSTANCE_COUNT], provider -> provider.getPopulator( indexId, descriptor, samplingConfig ) );
+ providers.instancesAs( new IndexPopulator[INSTANCE_COUNT], provider -> provider.getPopulator( indexId, descriptor, samplingConfig ) );
return new FusionIndexPopulator( slotSelector, new InstanceSelector<>( populators ), indexId, dropAction, archiveFailedIndex );
}
@@ -111,7 +109,7 @@ public IndexAccessor getOnlineAccessor( long indexId, SchemaIndexDescriptor desc
IndexSamplingConfig samplingConfig ) throws IOException
{
IndexAccessor[] accessors =
- instancesAs( providers, new IndexAccessor[INSTANCE_COUNT], provider -> provider.getOnlineAccessor( indexId, descriptor, samplingConfig ) );
+ providers.instancesAs( new IndexAccessor[INSTANCE_COUNT], provider -> provider.getOnlineAccessor( indexId, descriptor, samplingConfig ) );
return new FusionIndexAccessor( slotSelector, new InstanceSelector<>( accessors ), indexId, descriptor, dropAction );
}
@@ -119,7 +117,7 @@ public IndexAccessor getOnlineAccessor( long indexId, SchemaIndexDescriptor desc
public String getPopulationFailure( long indexId, SchemaIndexDescriptor descriptor ) throws IllegalStateException
{
StringBuilder builder = new StringBuilder();
- forAll( p -> writeFailure( p.getClass().getSimpleName(), builder, p, indexId, descriptor ), providers );
+ providers.forAll( p -> writeFailure( p.getClass().getSimpleName(), builder, p, indexId, descriptor ) );
String failure = builder.toString();
if ( !failure.isEmpty() )
{
@@ -146,7 +144,7 @@ private void writeFailure( String indexName, StringBuilder builder, IndexProvide
@Override
public InternalIndexState getInitialState( long indexId, SchemaIndexDescriptor descriptor )
{
- InternalIndexState[] states = instancesAs( providers, new InternalIndexState[INSTANCE_COUNT], p -> p.getInitialState( indexId, descriptor ) );
+ InternalIndexState[] states = providers.instancesAs( new InternalIndexState[INSTANCE_COUNT], p -> p.getInitialState( indexId, descriptor ) );
if ( Arrays.stream( states ).anyMatch( state -> state == FAILED ) )
{
// One of the state is FAILED, the whole state must be considered FAILED
@@ -165,7 +163,7 @@ public InternalIndexState getInitialState( long indexId, SchemaIndexDescriptor d
public IndexCapability getCapability( SchemaIndexDescriptor schemaIndexDescriptor )
{
IndexCapability[] capabilities =
- instancesAs( providers, new IndexCapability[INSTANCE_COUNT], provider -> provider.getCapability( schemaIndexDescriptor ) );
+ providers.instancesAs( new IndexCapability[INSTANCE_COUNT], provider -> provider.getCapability( schemaIndexDescriptor ) );
return new UnionIndexCapability( capabilities )
{
@Override
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexReader.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexReader.java
index 166e950f36a1..200c3e019280 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexReader.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexReader.java
@@ -52,7 +52,7 @@ class FusionIndexReader extends FusionIndexBase implements IndexRea
@Override
public void close()
{
- forInstantiated( Resource::close, instanceSelector );
+ instanceSelector.close( Resource::close );
}
@Override
@@ -64,15 +64,16 @@ public long countIndexedNodes( long nodeId, Value... propertyValues )
@Override
public IndexSampler createSampler()
{
- return new FusionIndexSampler( instancesAs( new IndexSampler[INSTANCE_COUNT], IndexReader::createSampler ) );
+ return new FusionIndexSampler( instanceSelector.instancesAs( new IndexSampler[INSTANCE_COUNT], IndexReader::createSampler ) );
}
@Override
public PrimitiveLongResourceIterator query( IndexQuery... predicates ) throws IndexNotApplicableKernelException
{
int slot = slotSelector.selectSlot( predicates, IndexQuery::valueGroup );
- return slot != UNKNOWN ? instanceSelector.select( slot ).query( predicates )
- : concat( instancesAs( new PrimitiveLongResourceIterator[INSTANCE_COUNT], reader -> reader.query( predicates ) ) );
+ return slot != UNKNOWN
+ ? instanceSelector.select( slot ).query( predicates )
+ : concat( instanceSelector.instancesAs( new PrimitiveLongResourceIterator[INSTANCE_COUNT], reader -> reader.query( predicates ) ) );
}
@Override
@@ -95,7 +96,7 @@ public void query( IndexProgressor.NodeValueClient cursor, IndexOrder indexOrder
BridgingIndexProgressor multiProgressor = new BridgingIndexProgressor( cursor,
descriptor.schema().getPropertyIds() );
cursor.initialize( descriptor, multiProgressor, predicates );
- forAll( reader -> reader.query( multiProgressor, indexOrder, predicates ), instanceSelector );
+ instanceSelector.forAll( reader -> reader.query( multiProgressor, indexOrder, predicates ) );
}
}
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdater.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdater.java
index f5f30d7524d1..bce9d040a986 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdater.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdater.java
@@ -72,7 +72,7 @@ public void close() throws IOException, IndexEntryConflictException
{
try
{
- forInstantiated( IndexUpdater::close, instanceSelector );
+ instanceSelector.close( IndexUpdater::close );
}
catch ( IOException | IndexEntryConflictException | RuntimeException e )
{
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/InstanceSelector.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/InstanceSelector.java
index a8668a703bd3..ce6461b5dced 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/InstanceSelector.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/index/schema/fusion/InstanceSelector.java
@@ -21,6 +21,12 @@
import java.util.function.IntFunction;
+import org.neo4j.function.ThrowingConsumer;
+import org.neo4j.function.ThrowingFunction;
+import org.neo4j.helpers.Exceptions;
+
+import static org.neo4j.kernel.impl.index.schema.fusion.SlotSelector.INSTANCE_COUNT;
+
/**
* Selects an instance given a certain slot.
* @param type of instance
@@ -29,6 +35,7 @@ class InstanceSelector
{
private final T[] instances;
private final IntFunction factory;
+ private boolean closed;
/**
* @param instances fully instantiated instances so that no factory is needed.
@@ -51,17 +58,137 @@ class InstanceSelector
this.factory = factory;
}
+ /**
+ * Returns the instance at the given slot. Instantiating it if it hasn't already been instantiated.
+ *
+ * @param slot slot number to return instance for.
+ * @return the instance at the given {@code slot}.
+ */
T select( int slot )
{
if ( instances[slot] == null )
{
+ assertOpen();
instances[slot] = factory.apply( slot );
}
return instances[slot];
}
+ private void assertOpen()
+ {
+ if ( closed )
+ {
+ throw new IllegalStateException( "This selector has been closed" );
+ }
+ }
+
+ /**
+ * Returns the instance at the given slot. If the instance at the given {@code slot} hasn't been instantiated yet, {@code null} is returned.
+ *
+ * @param slot slot number to return instance for.
+ * @return the instance at the given {@code slot}, or {@code null}.
+ */
T getIfInstantiated( int slot )
{
return instances[slot];
}
+
+ /**
+ * Convenience method typically for calling a method on each of the instances, a method that returns another type of instance.
+ * Even called on instances that haven't been instantiated yet. All those created instances are put into the provided array and returned.
+ *
+ * @param target array to put the created instances into, also returned.
+ * @param converter {@link ThrowingFunction} which converts from the source to target instance.
+ * @param type of returned instance.
+ * @param type of exception that converter may throw.
+ * @return the target array which was passed in, now populated.
+ * @throws E exception from converter.
+ */
+ R[] instancesAs( R[] target, ThrowingFunction converter ) throws E
+ {
+ for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
+ {
+ target[slot] = converter.apply( select( slot ) );
+ }
+ return target;
+ }
+
+ /**
+ * Convenience method for doing something to already instantiated instances.
+ *
+ * @param consumer {@link ThrowingConsumer} which performs some action on an instance.
+ * @param type of exception the action may throw.
+ * @throws E exception from action.
+ */
+ void forInstantiated( ThrowingConsumer consumer ) throws E
+ {
+ E exception = null;
+ for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
+ {
+ T instance = getIfInstantiated( slot );
+ if ( instance != null )
+ {
+ exception = consume( exception, consumer, instance );
+ }
+ }
+ if ( exception != null )
+ {
+ throw exception;
+ }
+ }
+
+ /**
+ * Convenience method for doing something to all instances, even those that haven't already been instantiated.
+ *
+ * @param consumer {@link ThrowingConsumer} which performs some action on an instance.
+ * @param type of exception the action may throw.
+ * @throws E exception from action.
+ */
+ void forAll( ThrowingConsumer consumer ) throws E
+ {
+ E exception = null;
+ for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
+ {
+ exception = consume( exception, consumer, select( slot ) );
+ }
+ if ( exception != null )
+ {
+ throw exception;
+ }
+ }
+
+ /**
+ * Perform a final action on instantiated instances and then closes this selector, preventing further instantiation.
+ *
+ * @param consumer {@link ThrowingConsumer} which performs some action on an instance.
+ * @param type of exception the action may throw.
+ * @throws E exception from action.
+ */
+ void close( ThrowingConsumer consumer ) throws E
+ {
+ if ( !closed )
+ {
+ try
+ {
+ forInstantiated( consumer );
+ }
+ finally
+ {
+ closed = true;
+ }
+ }
+ }
+
+ private static E consume( E exception, ThrowingConsumer consumer, T instance )
+ {
+ try
+ {
+ consumer.accept( instance );
+ }
+ catch ( Exception e )
+ {
+ exception = Exceptions.chain( exception, (E) e );
+ }
+ return exception;
+ }
}
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/MultipleIndexPopulatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/MultipleIndexPopulatorTest.java
index c57d79d4f162..4a93933bf019 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/MultipleIndexPopulatorTest.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/MultipleIndexPopulatorTest.java
@@ -27,6 +27,7 @@
import org.mockito.junit.MockitoJUnitRunner;
import java.io.IOException;
+import java.io.UncheckedIOException;
import java.util.concurrent.Callable;
import java.util.function.IntPredicate;
@@ -53,9 +54,9 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -386,7 +387,7 @@ public void testMultiplePopulatorUpdater() throws IOException, IndexEntryConflic
addPopulator( indexPopulator1, 1 );
addPopulator( indexPopulator2, 2 );
- doThrow( getPopulatorException() ).when( indexPopulator2 )
+ doThrow( new UncheckedIOException( getPopulatorException() ) ).when( indexPopulator2 )
.newPopulatingUpdater( any( PropertyAccessor.class ) );
IndexUpdater multipleIndexUpdater =
@@ -490,7 +491,7 @@ private IOException getPopulatorException()
private void checkPopulatorFailure( IndexPopulator populator ) throws IOException
{
- verify( populator ).markAsFailed( startsWith( "java.io.IOException: something went wrong" ) );
+ verify( populator ).markAsFailed( contains( "something went wrong" ) );
verify( populator ).close( false );
}
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCacheTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCacheTest.java
index 10711ed25557..666ad25bc9f2 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCacheTest.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/TemporalIndexCacheTest.java
@@ -28,20 +28,16 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.test.Race;
-import org.neo4j.values.storable.CoordinateReferenceSystem;
import org.neo4j.values.storable.ValueGroup;
-import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.neo4j.helpers.collection.Iterables.count;
@@ -132,7 +128,7 @@ public void stressInstantiationWithClose() throws Throwable
}, 1 );
race.addContestant( () ->
{
- cache.shutInstantiateCloseLock();
+ cache.closeInstantiateCloseLock();
instantiatedAtClose.setValue( count( cache ) );
}, 1 );
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessorTest.java
index 07652c6d2000..a26c527ee80c 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessorTest.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexAccessorTest.java
@@ -251,20 +251,22 @@ public void closeMustCloseAll() throws Exception
@Test
public void closeMustThrowIfOneThrow() throws Exception
{
- for ( IndexAccessor accessor : aliveAccessors )
+ for ( int i = 0; i < aliveAccessors.length; i++ )
{
+ IndexAccessor accessor = aliveAccessors[i];
verifyFusionCloseThrowOnSingleCloseThrow( accessor, fusionIndexAccessor );
- resetMocks();
+ initiateMocks();
}
}
@Test
public void closeMustCloseOthersIfOneThrow() throws Exception
{
- for ( IndexAccessor accessor : aliveAccessors )
+ for ( int i = 0; i < aliveAccessors.length; i++ )
{
+ IndexAccessor accessor = aliveAccessors[i];
verifyOtherIsClosedOnSingleThrow( accessor, fusionIndexAccessor, without( aliveAccessors, accessor ) );
- resetMocks();
+ initiateMocks();
}
}
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulatorTest.java
index 7ecae7c00eb0..3cb3baf2baa4 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulatorTest.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexPopulatorTest.java
@@ -301,9 +301,10 @@ private void closeAndVerifyPropagation( boolean populationCompletedSuccessfully
@Test
public void closeMustThrowIfCloseAnyThrow() throws Exception
{
- for ( IndexPopulator alivePopulator : alivePopulators )
+ for ( int i = 0; i < alivePopulators.length; i++ )
{
// given
+ IndexPopulator alivePopulator = alivePopulators[i];
IOException failure = new IOException( "fail" );
doThrow( failure ).when( alivePopulator ).close( anyBoolean() );
@@ -313,8 +314,7 @@ public void closeMustThrowIfCloseAnyThrow() throws Exception
return null;
} );
- // reset throw for testing of next populator
- doAnswer( invocation -> null ).when( alivePopulator ).close( anyBoolean() );
+ initiateMocks();
}
}
@@ -344,10 +344,11 @@ private void verifyOtherCloseOnThrow( IndexPopulator throwingPopulator ) throws
@Test
public void closeMustCloseOthersIfAnyThrow() throws Exception
{
- for ( IndexPopulator throwingPopulator : alivePopulators )
+ for ( int i = 0; i < alivePopulators.length; i++ )
{
+ IndexPopulator throwingPopulator = alivePopulators[i];
verifyOtherCloseOnThrow( throwingPopulator );
- resetMocks();
+ initiateMocks();
}
}
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdaterTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdaterTest.java
index 1830dcd05732..e3042ef86915 100644
--- a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdaterTest.java
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/FusionIndexUpdaterTest.java
@@ -327,20 +327,22 @@ public void closeMustCloseAll() throws Exception
@Test
public void closeMustThrowIfAnyThrow() throws Exception
{
- for ( IndexUpdater updater : aliveUpdaters )
+ for ( int i = 0; i < aliveUpdaters.length; i++ )
{
+ IndexUpdater updater = aliveUpdaters[i];
FusionIndexTestHelp.verifyFusionCloseThrowOnSingleCloseThrow( updater, fusionIndexUpdater );
- resetMocks();
+ initiateMocks();
}
}
@Test
public void closeMustCloseOthersIfAnyThrow() throws Exception
{
- for ( IndexUpdater updater : aliveUpdaters )
+ for ( int i = 0; i < aliveUpdaters.length; i++ )
{
+ IndexUpdater updater = aliveUpdaters[i];
FusionIndexTestHelp.verifyOtherIsClosedOnSingleThrow( updater, fusionIndexUpdater, without( aliveUpdaters, updater ) );
- resetMocks();
+ initiateMocks();
}
}
diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/InstanceSelectorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/InstanceSelectorTest.java
new file mode 100644
index 000000000000..9ba286da7e00
--- /dev/null
+++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/index/schema/fusion/InstanceSelectorTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2002-2018 "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.schema.fusion;
+
+import org.junit.Test;
+
+import java.util.function.IntFunction;
+
+import org.neo4j.function.ThrowingConsumer;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+import static org.neo4j.kernel.impl.index.schema.fusion.SlotSelector.INSTANCE_COUNT;
+
+public class InstanceSelectorTest
+{
+ @Test
+ public void shouldInstantiateLazilyOnFirstSelect()
+ {
+ // given
+ IntFunction factory = mock( IntFunction.class );
+ when( factory.apply( anyInt() ) ).then( invocationOnMock -> String.valueOf( (Integer) invocationOnMock.getArgument( 0 ) ) );
+ InstanceSelector selector = new InstanceSelector<>( new String[INSTANCE_COUNT], factory );
+
+ // when
+ for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
+ {
+ for ( int candidate = 0; candidate < INSTANCE_COUNT; candidate++ )
+ {
+ // then
+ if ( candidate < slot )
+ {
+ verify( factory, times( 1 ) ).apply( candidate );
+ selector.select( candidate );
+ verify( factory, times( 1 ) ).apply( candidate );
+ }
+ else if ( candidate == slot )
+ {
+ verify( factory, times( 0 ) ).apply( candidate );
+ selector.select( candidate );
+ verify( factory, times( 1 ) ).apply( candidate );
+ }
+ else
+ {
+ assertNull( selector.getIfInstantiated( candidate ) );
+ }
+ }
+ }
+ }
+
+ @Test
+ public void shouldPerformActionOnInstantiated()
+ {
+ // given
+ IntFunction factory = mock( IntFunction.class );
+ when( factory.apply( anyInt() ) ).then( invocationOnMock -> String.valueOf( (Integer) invocationOnMock.getArgument( 0 ) ) );
+ InstanceSelector selector = new InstanceSelector<>( new String[INSTANCE_COUNT], factory );
+ selector.select( 0 );
+ selector.select( 2 );
+
+ // when
+ ThrowingConsumer consumer = mock( ThrowingConsumer.class );
+ selector.forInstantiated( consumer );
+
+ // then
+ verify( consumer, times( 1 ) ).accept( "0" );
+ verify( consumer, times( 1 ) ).accept( "2" );
+ verifyNoMoreInteractions( consumer );
+ }
+
+ @Test
+ public void shouldPerformActionOnAll()
+ {
+ // given
+ IntFunction factory = mock( IntFunction.class );
+ when( factory.apply( anyInt() ) ).then( invocationOnMock -> String.valueOf( (Integer) invocationOnMock.getArgument( 0 ) ) );
+ InstanceSelector selector = new InstanceSelector<>( new String[INSTANCE_COUNT], factory );
+ selector.select( 1 );
+
+ // when
+ ThrowingConsumer consumer = mock( ThrowingConsumer.class );
+ selector.forAll( consumer );
+
+ // then
+ for ( int slot = 0; slot < INSTANCE_COUNT; slot++ )
+ {
+ verify( consumer, times( 1 ) ).accept( String.valueOf( slot ) );
+ }
+ verifyNoMoreInteractions( consumer );
+ }
+
+ @Test
+ public void shouldCloseAllInstantiated()
+ {
+ // given
+ IntFunction factory = mock( IntFunction.class );
+ when( factory.apply( anyInt() ) ).then( invocationOnMock -> String.valueOf( (Integer) invocationOnMock.getArgument( 0 ) ) );
+ InstanceSelector selector = new InstanceSelector<>( new String[INSTANCE_COUNT], factory );
+ selector.select( 1 );
+ selector.select( 3 );
+
+ // when
+ ThrowingConsumer consumer = mock( ThrowingConsumer.class );
+ selector.close( consumer );
+
+ // then
+ verify( consumer, times( 1 ) ).accept( "1" );
+ verify( consumer, times( 1 ) ).accept( "3" );
+ verifyNoMoreInteractions( consumer );
+ }
+
+ @Test
+ public void shouldPreventInstantiationAfterClose()
+ {
+ // given
+ IntFunction factory = mock( IntFunction.class );
+ when( factory.apply( anyInt() ) ).then( invocationOnMock -> String.valueOf( (Integer) invocationOnMock.getArgument( 0 ) ) );
+ InstanceSelector selector = new InstanceSelector<>( new String[INSTANCE_COUNT], factory );
+ selector.select( 1 );
+ selector.select( 3 );
+
+ // when
+ selector.close( mock( ThrowingConsumer.class ) );
+
+ // then
+ try
+ {
+ selector.select( 0 );
+ fail( "Should have failed" );
+ }
+ catch ( IllegalStateException e )
+ {
+ // then good
+ }
+ }
+}