Skip to content

Commit

Permalink
Wait for recovery cleaner to complete in LabelScanStoreLoggingTest
Browse files Browse the repository at this point in the history
Fix recently introduced component start race by waiting for cleanup job
to be always completed before checking recovery log messages.
  • Loading branch information
MishaDemianenko committed May 22, 2017
1 parent bd34af2 commit fbb4778
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 65 deletions.
Expand Up @@ -19,6 +19,8 @@
*/
package org.neo4j.kernel.lifecycle;

import java.util.Arrays;

public class Lifecycles
{
private Lifecycles()
Expand All @@ -27,43 +29,57 @@ private Lifecycles()

public static Lifecycle multiple( final Iterable<? extends Lifecycle> lifecycles )
{
return new Lifecycle()
return new CombinedLifecycle( lifecycles );
}

public static Lifecycle multiple( Lifecycle... lifecycles )
{
return new CombinedLifecycle( Arrays.asList( lifecycles ) );
}

private static class CombinedLifecycle implements Lifecycle
{
private final Iterable<? extends Lifecycle> lifecycles;

CombinedLifecycle( Iterable<? extends Lifecycle> lifecycles )
{
this.lifecycles = lifecycles;
}

@Override
public void init() throws Throwable
{
@Override
public void init() throws Throwable
for ( Lifecycle lifecycle : lifecycles )
{
for ( Lifecycle lifecycle : lifecycles )
{
lifecycle.init();
}
lifecycle.init();
}
}

@Override
public void start() throws Throwable
@Override
public void start() throws Throwable
{
for ( Lifecycle lifecycle : lifecycles )
{
for ( Lifecycle lifecycle : lifecycles )
{
lifecycle.start();
}
lifecycle.start();
}
}

@Override
public void stop() throws Throwable
@Override
public void stop() throws Throwable
{
for ( Lifecycle lifecycle : lifecycles )
{
for ( Lifecycle lifecycle : lifecycles )
{
lifecycle.stop();
}
lifecycle.stop();
}
}

@Override
public void shutdown() throws Throwable
@Override
public void shutdown() throws Throwable
{
for ( Lifecycle lifecycle : lifecycles )
{
for ( Lifecycle lifecycle : lifecycles )
{
lifecycle.shutdown();
}
lifecycle.shutdown();
}
};
}
}
}
Expand Up @@ -46,7 +46,6 @@
import org.neo4j.kernel.impl.transaction.log.checkpoint.CheckPointerMonitor;
import org.neo4j.kernel.impl.transaction.log.checkpoint.StoreCopyCheckPointMutex;
import org.neo4j.kernel.impl.transaction.state.DataSourceManager;
import org.neo4j.scheduler.JobScheduler;
import org.neo4j.kernel.impl.util.Neo4jJobScheduler;
import org.neo4j.kernel.info.DiagnosticsManager;
import org.neo4j.kernel.info.JvmChecker;
Expand All @@ -61,6 +60,7 @@
import org.neo4j.logging.Level;
import org.neo4j.logging.Log;
import org.neo4j.logging.LogProvider;
import org.neo4j.scheduler.JobScheduler;
import org.neo4j.time.Clocks;
import org.neo4j.time.SystemNanoClock;
import org.neo4j.udc.UsageData;
Expand Down Expand Up @@ -286,7 +286,7 @@ protected LogService createLogService( LogProvider userLogProvider )
return life.add( logService );
}

protected Neo4jJobScheduler createJobScheduler()
protected JobScheduler createJobScheduler()
{
return new Neo4jJobScheduler();
}
Expand Down
Expand Up @@ -22,20 +22,37 @@
import org.junit.Rule;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.ThreadFactory;

import org.neo4j.graphdb.DependencyResolver;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactoryState;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.helpers.NamedThreadFactory;
import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
import org.neo4j.kernel.api.impl.labelscan.LuceneLabelScanStore;
import org.neo4j.kernel.api.labelscan.LabelScanStore;
import org.neo4j.kernel.api.labelscan.LabelScanWriter;
import org.neo4j.kernel.api.labelscan.NodeLabelUpdate;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.factory.CommunityEditionModule;
import org.neo4j.kernel.impl.factory.DatabaseInfo;
import org.neo4j.kernel.impl.factory.GraphDatabaseFacade;
import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory;
import org.neo4j.kernel.impl.factory.PlatformModule;
import org.neo4j.kernel.impl.index.labelscan.NativeLabelScanStore;
import org.neo4j.kernel.impl.logging.LogService;
import org.neo4j.kernel.impl.logging.NullLogService;
import org.neo4j.kernel.impl.logging.SimpleLogService;
import org.neo4j.kernel.internal.GraphDatabaseAPI;
import org.neo4j.kernel.lifecycle.Lifecycle;
import org.neo4j.kernel.lifecycle.Lifecycles;
import org.neo4j.logging.AssertableLogProvider;
import org.neo4j.logging.LogProvider;
import org.neo4j.scheduler.JobScheduler;
import org.neo4j.test.OnDemandJobScheduler;
import org.neo4j.test.TestGraphDatabaseFactory;
import org.neo4j.test.rule.TestDirectory;

Expand All @@ -49,17 +66,17 @@ public class LabelScanStoreLoggingTest
public void noLuceneLabelScanStoreMonitorMessages() throws Throwable
{
AssertableLogProvider logProvider = new AssertableLogProvider( true );
GraphDatabaseService database = new TestGraphDatabaseFactory()
.setInternalLogProvider( logProvider )
.newEmbeddedDatabase( testDirectory.directory() );
GraphDatabaseService database = newEmbeddedGraphDatabaseWithOnDemandScheduler( logProvider );
try
{

NativeLabelScanStore labelScanStore = resolveDependency( (GraphDatabaseAPI) database, NativeLabelScanStore.class);
NativeLabelScanStore labelScanStore = resolveDependency( database, NativeLabelScanStore.class);
RecoveryCleanupWorkCollector recoveryCleanupWorkCollector =
resolveDependency( (GraphDatabaseAPI) database, RecoveryCleanupWorkCollector.class );
resolveDependency( database, RecoveryCleanupWorkCollector.class );
performSomeWrites( labelScanStore );
restartAll( recoveryCleanupWorkCollector, labelScanStore );
OnDemandJobScheduler jobScheduler = getOnDemandScheduler( database );
jobScheduler.runJob();

logProvider.assertNoLogCallContaining( LuceneLabelScanStore.class.getName() );
logProvider.assertContainsLogCallContaining( NativeLabelScanStore.class.getName() );
logProvider.assertContainsMessageContaining(
Expand All @@ -75,14 +92,15 @@ public void noLuceneLabelScanStoreMonitorMessages() throws Throwable
public void noNativeLabelScanStoreMonitorMessages() throws Throwable
{
AssertableLogProvider logProvider = new AssertableLogProvider( true );

GraphDatabaseService database = new TestGraphDatabaseFactory()
.setInternalLogProvider( logProvider )
.newEmbeddedDatabaseBuilder( testDirectory.directory() )
.setConfig( GraphDatabaseSettings.label_index.name(), GraphDatabaseSettings.LabelIndex.LUCENE.name() )
.newGraphDatabase();
try
{
LuceneLabelScanStore labelScanStore = resolveDependency( (GraphDatabaseAPI) database, LuceneLabelScanStore.class);
LuceneLabelScanStore labelScanStore = resolveDependency( database, LuceneLabelScanStore.class);
performSomeWrites( labelScanStore );
restartAll( labelScanStore );
logProvider.assertNoLogCallContaining( NativeLabelScanStore.class.getName() );
Expand All @@ -94,12 +112,19 @@ public void noNativeLabelScanStoreMonitorMessages() throws Throwable
}
}

private void restartAll( Lifecycle... lifecycles ) throws Throwable
private OnDemandJobScheduler getOnDemandScheduler( GraphDatabaseService database )
{
return (OnDemandJobScheduler) resolveDependency( database, JobScheduler.class );
}

private static void restartAll( Lifecycle... lifecycles ) throws Throwable
{
stopAll( lifecycles );
shutdownAll( lifecycles );
initAll( lifecycles );
startAll( lifecycles );
Lifecycle combinedLifecycle = Lifecycles.multiple( lifecycles );
combinedLifecycle.stop();
combinedLifecycle.shutdown();

combinedLifecycle.init();
combinedLifecycle.start();
}

private void performSomeWrites( LabelScanStore labelScanStore ) throws IOException
Expand All @@ -110,41 +135,47 @@ private void performSomeWrites( LabelScanStore labelScanStore ) throws IOExcepti
}
}

private void stopAll( Lifecycle... lifecycles ) throws Throwable
private static <T> T resolveDependency( GraphDatabaseService database, Class<T> clazz )
{
for ( Lifecycle lifecycle : lifecycles )
{
lifecycle.stop();
}
DependencyResolver resolver = ((GraphDatabaseAPI) database).getDependencyResolver();
return resolver.resolveDependency( clazz );
}

private void shutdownAll( Lifecycle... lifecycles ) throws Throwable
private GraphDatabaseService newEmbeddedGraphDatabaseWithOnDemandScheduler( LogProvider logProvider )
{
for ( Lifecycle lifecycle : lifecycles )
GraphDatabaseFactoryState graphDatabaseFactoryState = new GraphDatabaseFactoryState();
graphDatabaseFactoryState.setUserLogProvider( NullLogService.getInstance().getUserLogProvider() );
return new GraphDatabaseFacadeFactory( DatabaseInfo.COMMUNITY, CommunityEditionModule::new )
{
lifecycle.shutdown();
}
}
@Override
protected PlatformModule createPlatform( File storeDir, Config config, Dependencies dependencies,
GraphDatabaseFacade graphDatabaseFacade )
{
return new PlatformModule( storeDir, config, databaseInfo, dependencies, graphDatabaseFacade )
{
@Override
protected JobScheduler createJobScheduler()
{
return new TestScheduler();
}

private void initAll( Lifecycle... lifecycles ) throws Throwable
{
for ( Lifecycle lifecycle : lifecycles )
{
lifecycle.init();
}
@Override
protected LogService createLogService( LogProvider userLogProvider )
{
return new SimpleLogService( logProvider, logProvider );
}
};
}
}.newFacade( testDirectory.graphDbDir(), Config.embeddedDefaults(),
graphDatabaseFactoryState.databaseDependencies() );
}

private void startAll( Lifecycle... lifecycles ) throws Throwable
private static class TestScheduler extends OnDemandJobScheduler
{
for ( Lifecycle lifecycle : lifecycles )
@Override
public ThreadFactory threadFactory( Group group )
{
lifecycle.start();
return new NamedThreadFactory( "test", true );
}
}

private static <T> T resolveDependency( GraphDatabaseAPI database, Class<T> clazz )
{
DependencyResolver resolver = database.getDependencyResolver();
return resolver.resolveDependency( clazz );
}
}

0 comments on commit fbb4778

Please sign in to comment.