From 08e066ec9cdf370ee1fec17a494c2cb0719c4f60 Mon Sep 17 00:00:00 2001 From: Anton Persson Date: Thu, 5 Jan 2017 08:38:46 +0100 Subject: [PATCH] GBPTree test for recovery replaying transactions from before last checkpoint To make sure nothing breaks if more transactions then necessary is replayed. --- .../index/gbptree/GBPTreeRecoveryTest.java | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/community/index/src/test/java/org/neo4j/index/gbptree/GBPTreeRecoveryTest.java b/community/index/src/test/java/org/neo4j/index/gbptree/GBPTreeRecoveryTest.java index 25ed3a307330a..1488acfe1ad47 100644 --- a/community/index/src/test/java/org/neo4j/index/gbptree/GBPTreeRecoveryTest.java +++ b/community/index/src/test/java/org/neo4j/index/gbptree/GBPTreeRecoveryTest.java @@ -57,7 +57,13 @@ public class GBPTreeRecoveryTest { private static final int PAGE_SIZE = 256; - private static final Action CHECKPOINT = index -> index.checkpoint( unlimited() ); + private static final Action CHECKPOINT = ( index, forRecovery ) -> + { + if ( !forRecovery ) + { + index.checkpoint( unlimited() ); + } + }; private final RandomRule random = new RandomRule(); private final EphemeralFileSystemRule fs = new EphemeralFileSystemRule(); @@ -121,7 +127,20 @@ public void shouldRecoverFromCrashBeforeFirstCheckpoint() throws Exception } @Test - public void shouldRecoverFromAnything() throws Exception + public void shouldRecoverFromAnythingReplayExactFromCheckpoint() throws Exception + { + doShouldRecoverFromAnything( true ); + + } + + @Test + public void shouldRecoverFromAnythingReplayFromBeforeLastCheckpoint() throws Exception + { + doShouldRecoverFromAnything( false ); + + } + + private void doShouldRecoverFromAnything( boolean replayRecoveryExactlyFromCheckpoint ) throws Exception { // GIVEN // a tree which has had random updates and checkpoints in it, load generated with specific seed @@ -139,15 +158,15 @@ public void shouldRecoverFromAnything() throws Exception PageCache pageCache = createPageCache(); GBPTree index = createIndex( pageCache, file ); // Execute all actions up to and including last checkpoint ... - execute( load.subList( 0, lastCheckPointIndex + 1 ), index ); + execute( load.subList( 0, lastCheckPointIndex + 1 ), index, false ); // ... a random amount of the remaining "unsafe" actions ... int numberOfRemainingActions = load.size() - lastCheckPointIndex - 1; int crashFlushIndex = lastCheckPointIndex + random.nextInt( numberOfRemainingActions ) + 1; - execute( load.subList( lastCheckPointIndex + 1, crashFlushIndex ), index ); + execute( load.subList( lastCheckPointIndex + 1, crashFlushIndex ), index, false ); // ... flush ... pageCache.flushAndForce(); // ... execute the remaining actions - execute( load.subList( crashFlushIndex, load.size() ), index ); + execute( load.subList( crashFlushIndex, load.size() ), index, false ); // ... and finally crash fs.snapshot( throwing( () -> { @@ -157,7 +176,15 @@ public void shouldRecoverFromAnything() throws Exception } // WHEN doing recovery - List recoveryActions = load.subList( lastCheckPointIndex + 1, load.size() ); + List recoveryActions; + if ( replayRecoveryExactlyFromCheckpoint ) + { + recoveryActions = load.subList( lastCheckPointIndex + 1, load.size() ); + } + else + { + recoveryActions = load.subList( random.nextInt( lastCheckPointIndex ), load.size() ); + } // first crashing during recovery int numberOfCrashesDuringRecovery = random.intBetween( 0, 3 ); @@ -204,22 +231,22 @@ public void shouldRecoverFromAnything() throws Exception private void recover( List load, GBPTree index ) throws IOException { index.prepareForRecovery(); - execute( load, index ); + execute( load, index, true ); } - private static void execute( List load, Index index ) + private static void execute( List load, Index index, boolean forRecovery ) throws IOException { for ( Action action : load ) { - action.execute( index ); + action.execute( index, forRecovery ); } } private static long[] expectedSortedAggregatedDataFromGeneratedLoad( List load ) throws IOException { CapturingIndex index = new CapturingIndex(); - execute( load, index ); + execute( load, index, false ); @SuppressWarnings( "unchecked" ) Map.Entry[] entries = index.map.entrySet().toArray( new Map.Entry[index.map.size()] ); long[] result = new long[entries.length * 2]; @@ -286,7 +313,7 @@ private Action randomAction( boolean allowCheckPoint ) { // put long[] data = modificationData( 30, 200 ); - return index -> + return ( index, forRecovery ) -> { try ( IndexWriter writer = index.writer() ) { @@ -303,7 +330,7 @@ else if ( randomized <= 0.95 || !allowCheckPoint ) { // remove long[] data = modificationData( 5, 20 ); - return index -> + return ( index, forRecovery ) -> { try ( IndexWriter writer = index.writer() ) { @@ -348,7 +375,7 @@ private PageCache createPageCache() interface Action { - void execute( Index index ) throws IOException; + void execute( Index index, boolean forRecovery ) throws IOException; } private static class CapturingIndex implements Index, IndexWriter