diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java index fa41b00dcfe27..be4dd7e41f4b8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java @@ -40,6 +40,7 @@ import org.neo4j.kernel.api.exceptions.schema.CreateConstraintFailureException; import org.neo4j.kernel.api.labelscan.LabelScanStore; import org.neo4j.kernel.api.labelscan.LabelScanWriter; +import org.neo4j.kernel.api.labelscan.LoggingMonitor; import org.neo4j.kernel.api.txstate.TransactionCountingStateVisitor; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.api.BatchTransactionApplier; @@ -203,6 +204,7 @@ public RecordStorageEngine( NeoStoreIndexStoreView neoStoreIndexStoreView = new NeoStoreIndexStoreView( lockService, neoStores ); Boolean readOnly = config.get( GraphDatabaseSettings.read_only ) && operationalMode == OperationalMode.single; + monitors.addMonitorListener( new LoggingMonitor( logProvider.getLog( NativeLabelScanStore.class ) ) ); labelScanStore = new NativeLabelScanStore( pageCache, storeDir, new FullLabelStream( neoStoreIndexStoreView ), readOnly, monitors, recoveryCleanupWorkCollector ); diff --git a/community/neo4j/src/test/java/recovery/RecoveryCleanupIT.java b/community/neo4j/src/test/java/recovery/RecoveryCleanupIT.java index 30db19c411b63..3fbb3aeeb50cf 100644 --- a/community/neo4j/src/test/java/recovery/RecoveryCleanupIT.java +++ b/community/neo4j/src/test/java/recovery/RecoveryCleanupIT.java @@ -46,6 +46,7 @@ import org.neo4j.kernel.internal.DatabaseHealth; import org.neo4j.kernel.internal.GraphDatabaseAPI; import org.neo4j.kernel.monitoring.Monitors; +import org.neo4j.logging.AssertableLogProvider; import org.neo4j.test.Barrier; import org.neo4j.test.Race; import org.neo4j.test.TestGraphDatabaseFactory; @@ -69,12 +70,6 @@ public class RecoveryCleanupIT public void setup() { storeDir = testDirectory.graphDbDir(); - - Monitors monitors = new Monitors(); - recoveryCompleteBarrier = new Barrier.Control(); - LabelScanStore.Monitor recoveryBarrierMonitor = new RecoveryBarrierMonitor( recoveryCompleteBarrier ); - monitors.addMonitorListener( recoveryBarrierMonitor ); - factory.setMonitors( monitors ); } @After @@ -91,17 +86,12 @@ public void recoveryCleanupShouldBlockCheckpoint() throws Throwable AtomicReference error = new AtomicReference<>(); try { - db = startDatabase(); - - DatabaseHealth databaseHealth = databaseHealth( db ); - someData( db ); - checkpoint( db ); - someData( db ); - databaseHealth.panic( new Throwable( "Trigger recovery on next startup" ) ); - db.shutdown(); - db = null; + dirtyDatabase(); // WHEN + recoveryCompleteBarrier = new Barrier.Control(); + LabelScanStore.Monitor recoveryBarrierMonitor = new RecoveryBarrierMonitor( recoveryCompleteBarrier ); + setMonitor( recoveryBarrierMonitor ); db = startDatabase(); recoveryCompleteBarrier.awaitUninterruptibly(); // Ensure we are mid recovery cleanup @@ -123,6 +113,42 @@ public void recoveryCleanupShouldBlockCheckpoint() throws Throwable } } + @Test + public void scanStoreMustLogCrashPointerCleanupDuringRecovery() throws Exception + { + // given + dirtyDatabase(); + + // when + AssertableLogProvider logProvider = new AssertableLogProvider( true ); + factory.setUserLogProvider( logProvider ); + factory.setInternalLogProvider( logProvider ); + startDatabase().shutdown(); + + // then + logProvider.assertContainsLogCallContaining( "Scan store recovery completed" ); + } + + private void setMonitor( Object monitor ) + { + Monitors monitors = new Monitors(); + monitors.addMonitorListener( monitor ); + factory.setMonitors( monitors ); + } + + private void dirtyDatabase() throws IOException + { + db = startDatabase(); + + DatabaseHealth databaseHealth = databaseHealth( db ); + someData( db ); + checkpoint( db ); + someData( db ); + databaseHealth.panic( new Throwable( "Trigger recovery on next startup" ) ); + db.shutdown(); + db = null; + } + private void reportError( Race.ThrowingRunnable checkpoint, AtomicReference error ) { try