Skip to content

Commit

Permalink
Made DatabaseAvailabilityGuard database aware. Remove availability
Browse files Browse the repository at this point in the history
listener addition from global facade factory.
  • Loading branch information
MishaDemianenko committed Aug 24, 2018
1 parent 5de90cb commit eafa544
Show file tree
Hide file tree
Showing 14 changed files with 88 additions and 70 deletions.
Expand Up @@ -51,6 +51,7 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.neo4j.dbms.database.DatabaseManager.DEFAULT_DATABASE_NAME;

class BoltStateMachineFactoryImplTest
{
Expand Down Expand Up @@ -98,7 +99,7 @@ private static BoltStateMachineFactoryImpl newBoltFactory()
private static BoltStateMachineFactoryImpl newBoltFactory( DatabaseManager databaseManager )
{
return new BoltStateMachineFactoryImpl( databaseManager, new UsageData( new OnDemandJobScheduler() ),
new DatabaseAvailabilityGuard( CLOCK, NullLog.getInstance() ), mock( Authentication.class ), CLOCK, Config.defaults(),
new DatabaseAvailabilityGuard( DEFAULT_DATABASE_NAME, CLOCK, NullLog.getInstance() ), mock( Authentication.class ), CLOCK, Config.defaults(),
NullLogService.getInstance() );
}

Expand All @@ -111,7 +112,7 @@ private static DatabaseManager newDbMock()
when( queryService.getDependencyResolver() ).thenReturn( dependencyResolver );
when( dependencyResolver.resolveDependency( GraphDatabaseQueryService.class ) ).thenReturn( queryService );
DatabaseManager databaseManager = mock( DatabaseManager.class );
when( databaseManager.getDatabaseFacade( DatabaseManager.DEFAULT_DATABASE_NAME ) ).thenReturn( Optional.of( db ) );
when( databaseManager.getDatabaseFacade( DEFAULT_DATABASE_NAME ) ).thenReturn( Optional.of( db ) );
return databaseManager;
}
}
Expand Up @@ -47,6 +47,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.neo4j.dbms.database.DatabaseManager.DEFAULT_DATABASE_NAME;

public class TransactionStateMachineV1SPITest
{
Expand All @@ -61,7 +62,7 @@ public void throwsWhenTxAwaitDurationExpires()
Duration txAwaitDuration = Duration.ofSeconds( 42 );
FakeClock clock = new FakeClock();

DatabaseAvailabilityGuard databaseAvailabilityGuard = spy( new DatabaseAvailabilityGuard( clock, NullLog.getInstance() ) );
DatabaseAvailabilityGuard databaseAvailabilityGuard = spy( new DatabaseAvailabilityGuard( DEFAULT_DATABASE_NAME, clock, NullLog.getInstance() ) );
when( databaseAvailabilityGuard.isAvailable() ).then( invocation ->
{
// move clock forward on the first availability check
Expand Down Expand Up @@ -117,7 +118,7 @@ private static TransactionIdStore fixedTxIdStore( long lastClosedTransactionId )
private static TransactionStateMachineV1SPI createTxSpi( Supplier<TransactionIdStore> txIdStore, Duration txAwaitDuration,
Clock clock )
{
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, NullLog.getInstance() );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( DEFAULT_DATABASE_NAME, clock, NullLog.getInstance() );
return createTxSpi( txIdStore, txAwaitDuration, databaseAvailabilityGuard, clock );
}

Expand Down
Expand Up @@ -39,20 +39,23 @@
*/
public class DatabaseAvailabilityGuard
{
private static final String DATABASE_AVAILABLE_MSG = "Fulfilling of requirement makes database available: ";
private static final String DATABASE_UNAVAILABLE_MSG = "Requirement makes database unavailable: ";
private static final String DATABASE_AVAILABLE_MSG = "Fulfilling of requirement makes database %s available: ";
private static final String DATABASE_UNAVAILABLE_MSG = "Requirement makes database %s unavailable: ";

private final AtomicInteger requirementCount = new AtomicInteger( 0 );
private final Set<AvailabilityRequirement> blockingRequirements = new CopyOnWriteArraySet<>();
private final AtomicBoolean isShutdown = new AtomicBoolean( false );
private final Listeners<AvailabilityListener> listeners = new Listeners<>();
private final String databaseName;
private final Clock clock;
private final Log log;

public DatabaseAvailabilityGuard( Clock clock, Log log )
public DatabaseAvailabilityGuard( String databaseName, Clock clock, Log log )
{
this.databaseName = databaseName;
this.clock = clock;
this.log = log;
this.listeners.add( new LoggingAvailabilityListener( log, databaseName ) );
}

/**
Expand All @@ -71,7 +74,7 @@ public void require( AvailabilityRequirement requirement )
{
if ( requirementCount.getAndIncrement() == 0 && !isShutdown.get() )
{
log.info( DATABASE_UNAVAILABLE_MSG + requirement.description() );
log.info( DATABASE_UNAVAILABLE_MSG + requirement.description(), databaseName );
listeners.notify( AvailabilityListener::unavailable );
}
}
Expand All @@ -93,7 +96,7 @@ public void fulfill( AvailabilityRequirement requirement )
{
if ( requirementCount.getAndDecrement() == 1 && !isShutdown.get() )
{
log.info( DATABASE_AVAILABLE_MSG + requirement.description() );
log.info( DATABASE_AVAILABLE_MSG + requirement.description(), databaseName );
listeners.notify( AvailabilityListener::available );
}
}
Expand Down Expand Up @@ -262,4 +265,28 @@ public String describeWhoIsBlocking()
}
return "No blocking components";
}

private static class LoggingAvailabilityListener implements AvailabilityListener
{
private final Log log;
private final String databaseName;

LoggingAvailabilityListener( Log log, String databaseName )
{
this.log = log;
this.databaseName = databaseName;
}

@Override
public void available()
{
log.info( "Database %s is now ready.", databaseName );
}

@Override
public void unavailable()
{
log.info( "Database %s is now unavailable.", databaseName );
}
}
}
Expand Up @@ -48,6 +48,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.neo4j.dbms.database.DatabaseManager.DEFAULT_DATABASE_NAME;
import static org.neo4j.logging.NullLog.getInstance;

public class DatabaseAvailabilityGuardTest
Expand All @@ -62,7 +63,7 @@ public void logOnAvailabilityChange()
{
// Given
Log log = mock( Log.class );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );

// When starting out
verifyZeroInteractions( log );
Expand Down Expand Up @@ -105,7 +106,7 @@ public void givenAccessGuardWith2ConditionsWhenAwaitThenTimeoutAndReturnFalse()
{
// Given
Log log = mock( Log.class );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );
databaseAvailabilityGuard.require( REQUIREMENT_2 );

Expand All @@ -121,7 +122,7 @@ public void givenAccessGuardWith2ConditionsWhenAwaitThenActuallyWaitGivenTimeout
{
// Given
Log log = mock( Log.class );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );
databaseAvailabilityGuard.require( REQUIREMENT_2 );

Expand All @@ -142,7 +143,7 @@ public void givenAccessGuardWith2ConditionsWhenGrantOnceAndAwaitThenTimeoutAndRe
{
// Given
Log log = mock( Log.class );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );
databaseAvailabilityGuard.require( REQUIREMENT_2 );

Expand All @@ -165,7 +166,7 @@ public void givenAccessGuardWith2ConditionsWhenGrantEachAndAwaitThenTrue()
{
// Given
Log log = mock( Log.class );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );
databaseAvailabilityGuard.require( REQUIREMENT_2 );

Expand All @@ -181,7 +182,7 @@ public void givenAccessGuardWith2ConditionsWhenGrantTwiceAndDenyOnceAndAwaitThen
{
// Given
Log log = mock( Log.class );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );
databaseAvailabilityGuard.require( REQUIREMENT_2 );

Expand All @@ -206,7 +207,7 @@ public void givenAccessGuardWith2ConditionsWhenGrantOnceAndAwaitAndGrantAgainThe
{
// Given
Log log = mock( Log.class );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );
databaseAvailabilityGuard.require( REQUIREMENT_2 );

Expand All @@ -222,7 +223,7 @@ public void givenAccessGuardWithConditionWhenGrantThenNotifyListeners()
{
// Given
Log log = mock( Log.class );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );

final AtomicBoolean notified = new AtomicBoolean();
Expand Down Expand Up @@ -254,7 +255,7 @@ public void givenAccessGuardWithConditionWhenGrantAndDenyThenNotifyListeners()
{
// Given
Log log = mock( Log.class );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );
databaseAvailabilityGuard.require( REQUIREMENT_1 );

final AtomicBoolean notified = new AtomicBoolean();
Expand Down Expand Up @@ -287,7 +288,7 @@ public void givenAccessGuardWithConditionWhenShutdownThenInstantlyDenyAccess()
{
// Given
Clock clock = Mockito.mock( Clock.class );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, NullLog.getInstance() );
final DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, NullLog.getInstance() );
databaseAvailabilityGuard.require( REQUIREMENT_1 );

// When
Expand All @@ -303,7 +304,7 @@ public void shouldExplainWhoIsBlockingAccess()
{
// Given
Log log = mock( Log.class );
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, log );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( clock, log );

// When
databaseAvailabilityGuard.require( REQUIREMENT_1 );
Expand All @@ -317,7 +318,7 @@ public void shouldExplainWhoIsBlockingAccess()
public void shouldExplainBlockersOnCheckAvailable() throws Exception
{
// GIVEN
DatabaseAvailabilityGuard databaseAvailabilityGuard = new DatabaseAvailabilityGuard( Clocks.systemClock(), getInstance() );
DatabaseAvailabilityGuard databaseAvailabilityGuard = getDatabaseAvailabilityGuard( Clocks.systemClock(), getInstance() );
// At this point it should be available
databaseAvailabilityGuard.checkAvailable();

Expand All @@ -335,4 +336,9 @@ public void shouldExplainBlockersOnCheckAvailable() throws Exception
assertThat( e.getMessage(), containsString( REQUIREMENT_1.description() ) );
}
}

private static DatabaseAvailabilityGuard getDatabaseAvailabilityGuard( Clock clock, Log log )
{
return new DatabaseAvailabilityGuard( DEFAULT_DATABASE_NAME, clock, log );
}
}
Expand Up @@ -33,7 +33,6 @@
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;

import org.neo4j.dbms.database.DatabaseManager;
import org.neo4j.graphdb.DatabaseShutdownException;
import org.neo4j.graphdb.security.AuthorizationExpiredException;
import org.neo4j.internal.kernel.api.exceptions.TransactionFailureException;
Expand Down Expand Up @@ -108,6 +107,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.neo4j.dbms.database.DatabaseManager.DEFAULT_DATABASE_NAME;
import static org.neo4j.helpers.collection.Iterators.asSet;
import static org.neo4j.internal.kernel.api.Transaction.Type.explicit;
import static org.neo4j.internal.kernel.api.security.LoginContext.AUTH_DISABLED;
Expand All @@ -130,7 +130,7 @@ public class KernelTransactionsTest
@Before
public void setUp()
{
databaseAvailabilityGuard = new DatabaseAvailabilityGuard( clock, NullLog.getInstance() );
databaseAvailabilityGuard = new DatabaseAvailabilityGuard( DEFAULT_DATABASE_NAME, clock, NullLog.getInstance() );
}

@Test
Expand Down Expand Up @@ -615,7 +615,7 @@ null, DEFAULT, commitProcess, null, null, new TransactionHooks(),
AutoIndexing.UNSUPPORTED,
mock( ExplicitIndexStore.class ), EmptyVersionContextSupplier.EMPTY, ON_HEAP,
mock( ConstraintSemantics.class ), mock( SchemaState.class ),
mock( IndexingProvidersService.class), mockedTokenHolders(), DatabaseManager.DEFAULT_DATABASE_NAME, new Dependencies() );
mock( IndexingProvidersService.class), mockedTokenHolders(), DEFAULT_DATABASE_NAME, new Dependencies() );
}

private static TestKernelTransactions createTestTransactions( StorageEngine storageEngine,
Expand Down Expand Up @@ -682,7 +682,7 @@ private static class TestKernelTransactions extends KernelTransactions
transactionIdStore, clock, new AtomicReference<>( CpuClock.NOT_AVAILABLE ), new AtomicReference<>( HeapAllocation.NOT_AVAILABLE ),
accessCapability, autoIndexing, mock( ExplicitIndexStore.class ), versionContextSupplier,
ON_HEAP, new StandardConstraintSemantics(), mock( SchemaState.class ),
mock( IndexingProvidersService.class ), tokenHolders, DatabaseManager.DEFAULT_DATABASE_NAME, dataSourceDependencies );
mock( IndexingProvidersService.class ), tokenHolders, DEFAULT_DATABASE_NAME, dataSourceDependencies );
}

@Override
Expand Down
Expand Up @@ -23,7 +23,6 @@
import java.util.Collections;
import java.util.function.Function;

import org.neo4j.dbms.database.DatabaseManager;
import org.neo4j.graphdb.DependencyResolver;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
Expand Down Expand Up @@ -94,6 +93,7 @@
import static org.mockito.Mockito.RETURNS_MOCKS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.neo4j.dbms.database.DatabaseManager.DEFAULT_DATABASE_NAME;
import static org.neo4j.kernel.impl.util.collection.CollectionsFactorySupplier.ON_HEAP;
import static org.neo4j.kernel.impl.util.watcher.FileSystemWatcherService.EMPTY_WATCHER;
import static org.neo4j.test.MockedNeoStores.mockedTokenHolders;
Expand Down Expand Up @@ -138,23 +138,23 @@ public NeoStoreDataSource getDataSource( DatabaseLayout databaseLayout, FileSyst
TransactionMonitor transactionMonitor = dependency( mutableDependencies, TransactionMonitor.class,
deps -> new DatabaseTransactionStats() );
DatabaseAvailabilityGuard databaseAvailabilityGuard = dependency( mutableDependencies, DatabaseAvailabilityGuard.class,
deps -> new DatabaseAvailabilityGuard( deps.resolveDependency( SystemNanoClock.class ), NullLog.getInstance() ) );
deps -> new DatabaseAvailabilityGuard( DEFAULT_DATABASE_NAME, deps.resolveDependency( SystemNanoClock.class ),
NullLog.getInstance() ) );
dependency( mutableDependencies, DiagnosticsManager.class,
deps -> new DiagnosticsManager( NullLog.getInstance() ) );
dependency( mutableDependencies, IndexProvider.class, deps -> IndexProvider.EMPTY );

dataSource = new NeoStoreDataSource(
new TestDatabaseCreationContext( DatabaseManager.DEFAULT_DATABASE_NAME, databaseLayout, config, idGeneratorFactory, logService,
mock( JobScheduler.class, RETURNS_MOCKS ), mock( TokenNameLookup.class ), mutableDependencies, mockedTokenHolders(), locksFactory,
mock( SchemaWriteGuard.class ), mock( TransactionEventHandlers.class ), IndexingService.NO_MONITOR, fs, transactionMonitor,
databaseHealth, mock( LogFileCreationMonitor.class ), TransactionHeaderInformationFactory.DEFAULT, new CommunityCommitProcessFactory(),
mock( InternalAutoIndexing.class ), mock( IndexConfigStore.class ), mock( ExplicitIndexProvider.class ), pageCache,
new StandardConstraintSemantics(), monitors, new Tracers( "null", NullLog.getInstance(), monitors, jobScheduler, clock ),
mock( Procedures.class ), IOLimiter.UNLIMITED, databaseAvailabilityGuard, clock, new CanWrite(), new StoreCopyCheckPointMutex(),
RecoveryCleanupWorkCollector.immediate(),
new BufferedIdController( new BufferingIdGeneratorFactory( idGeneratorFactory, IdReuseEligibility.ALWAYS, idConfigurationProvider ),
jobScheduler ), DatabaseInfo.COMMUNITY, new TransactionVersionContextSupplier(), ON_HEAP, Collections.emptyList(),
file -> EMPTY_WATCHER, new GraphDatabaseFacade(), Iterables.empty() ) );
dataSource = new NeoStoreDataSource( new TestDatabaseCreationContext( DEFAULT_DATABASE_NAME, databaseLayout, config, idGeneratorFactory, logService,
mock( JobScheduler.class, RETURNS_MOCKS ), mock( TokenNameLookup.class ), mutableDependencies, mockedTokenHolders(), locksFactory,
mock( SchemaWriteGuard.class ), mock( TransactionEventHandlers.class ), IndexingService.NO_MONITOR, fs, transactionMonitor, databaseHealth,
mock( LogFileCreationMonitor.class ), TransactionHeaderInformationFactory.DEFAULT, new CommunityCommitProcessFactory(),
mock( InternalAutoIndexing.class ), mock( IndexConfigStore.class ), mock( ExplicitIndexProvider.class ), pageCache,
new StandardConstraintSemantics(), monitors, new Tracers( "null", NullLog.getInstance(), monitors, jobScheduler, clock ),
mock( Procedures.class ), IOLimiter.UNLIMITED, databaseAvailabilityGuard, clock, new CanWrite(), new StoreCopyCheckPointMutex(),
RecoveryCleanupWorkCollector.immediate(),
new BufferedIdController( new BufferingIdGeneratorFactory( idGeneratorFactory, IdReuseEligibility.ALWAYS, idConfigurationProvider ),
jobScheduler ), DatabaseInfo.COMMUNITY, new TransactionVersionContextSupplier(), ON_HEAP, Collections.emptyList(),
file -> EMPTY_WATCHER, new GraphDatabaseFacade(), Iterables.empty() ) );
return dataSource;
}

Expand Down

0 comments on commit eafa544

Please sign in to comment.