Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright (c) 2002-2014 "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 <http://www.gnu.org/licenses/>.
 
 package recovery;
 
 import static java.lang.Integer.parseInt;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 import static org.neo4j.graphdb.DynamicRelationshipType.withName;
 import static org.neo4j.helpers.collection.MapUtil.stringMap;
 
 import java.io.File;
 import java.util.Set;
 
 import org.junit.Test;
Tries to trigger log file version errors that could happen if the db was killed at the exact right time, resulting in logs (or transactions in logs) gone missing.

Author(s):
Mattias Persson
Johan Svensson
 
 {
     private static final DynamicRelationshipType TYPE = withName"TYPE" );
 
     private final CountDownLatch breakpointNotification = new CountDownLatch( 1 );
     private final BreakPoint SET_VERSION = BreakPoint.thatCrashesTheProcess, 0,
             NeoStore.class"setVersion"long.class );
             XaLogicalLog.class"releaseCurrentLogFile" );
     private final BreakPoint RENAME_LOG_FILE = BreakPoint.thatCrashesTheProcess, 0,
             XaLogicalLog.class"renameLogFileToRightVersion"File.classlong.class );
     private final BreakPoint SET_VERSION_2 = BreakPoint.thatCrashesTheProcess, 1,
             NeoStore.class"setVersion"long.class );
             XaLogicalLog.class"releaseCurrentLogFile" );
     private final BreakPoint RENAME_LOG_FILE_2 = BreakPoint.thatCrashesTheProcess, 1,
             XaLogicalLog.class"renameLogFileToRightVersion"File.classlong.class );
             BreakPoint.stackTraceMustContainClassLuceneDataSource.class ), XaLogicalLog.class"renameLogFileToRightVersion"File.classlong.class );
             BreakPoint.stackTraceMustNotContainClassLuceneDataSource.class ), XaLogicalLog.class"renameLogFileToRightVersion"File.classlong.class );
     
     private final BreakPoint[] breakpoints = new BreakPoint[] {
     
     @Override
     protected BreakPoint[] breakpointsint id )
     {
         return ;
     }
     
     
     @Override
     protected Bootstrapper bootstrapint id ) throws IOException
     {
         return ;
     }
     
    static class DoSimpleTransaction implements Task
    {
        @Override
        public void runGraphDatabaseAPI graphdb )
        {
            Transaction tx = graphdb.beginTx();
            try
            {
                Node parent = graphdb.createNode();
                for ( int i = 0; i < 10; i++ )
                {
                    Node child = graphdb.createNode();
                    parent.createRelationshipTochild );
                }
                tx.success();
            }
            finally
            {
                tx.finish();
            }
        }
    }
    
    static class DoGraphAndIndexTransaction implements Task
    {
        @Override
        public void runGraphDatabaseAPI graphdb )
        {
            Transaction tx = graphdb.beginTx();
            try
            {
                Node parent = graphdb.createNode();
                graphdb.index().forNodes"index" ).addparent"name""test" );
                for ( int i = 0; i < 10; i++ )
                {
                    Node child = graphdb.createNode();
                    parent.createRelationshipTochild );
                }
                tx.success();
            }
            finally
            {
                tx.finish();
            }
        }
    }
    
    static class RotateLogs implements Task
    {
        private final Set<StringdataSources = new HashSet<String>();
        
        RotateLogsString... dataSources )
        {
            this..addAll( Arrays.asListdataSources ) );
        }
        
        @Override
        public void runGraphDatabaseAPI graphdb )
        {
            try
            {
                if ( .isEmpty() )
                    graphdb.getXaDataSourceManager().getNeoStoreDataSource().rotateLogicalLog();
                else
                {
                    for ( XaDataSource ds : graphdb.getXaDataSourceManager().getAllRegisteredDataSources() )
                    {
                        if ( .containsds.getName() ) )
                            ds.rotateLogicalLog();
                    }
                }
            }
            catch ( IOException e )
            {
                e.printStackTrace();
                throw new RuntimeExceptione );
            }
        }
    }
    
    static class GetCommittedTransactions implements Task
    {
        private final long highestLogVersion;
        private final long highestTxId;
        public GetCommittedTransactionslong highestLogVersionlong highestTxId )
        {
            this. = highestLogVersion;
            this. = highestTxId;
        }
        
        @Override
        public void runGraphDatabaseAPI graphdb )
        {
            try
            {
                XaDataSource dataSource = graphdb.getXaDataSourceManager().getNeoStoreDataSource();
                for ( long logVersion = 0; logVersion < logVersion++ )
                {
                    dataSource.getLogicalLoglogVersion );
                }
                
                LogExtractor extractor = dataSource.getLogExtractor( 2,  );
                try
                {
                    for ( long txId = 2; txId <= txId++ )
                    {
                        extractor.extractNext. );
                    }
                }
                finally
                {
                    extractor.close();
                }
            }
            catch ( Exception e )
            {
                throw new RuntimeExceptione );
            }
        }
    }
    
    static class Shutdown implements Task
    {
        @Override
        public void runGraphDatabaseAPI graphdb )
        {
            graphdb.shutdown();
        }
    }
    
    private static class VerifyLastTxId implements Task
    {
        private long tx;
        private String dataSource;
        VerifyLastTxIdString dataSourcelong tx )
        {
            this. = dataSource;
            this. = tx;
        }
        
        @Override
        public void runGraphDatabaseAPI graphdb )
        {
        }
    }
    private void crashDuringRotateAndVerifylong highestLogVersionlong highestTxId ) throws Exception
    {
        runInThreadnew RotateLogs() );
        .await();
        startSubprocesses();
        runnew GetCommittedTransactionshighestLogVersionhighestTxId ) );
    }
    
    @Test
    {
        [0].enable();
        runnew DoSimpleTransaction() );
        // tx(2) is the first one, for creating the relationship type
        // tx(3) is the second one, for doing the actual transaction in DoSimpleTransaction
        crashDuringRotateAndVerify( 1, 3 );
    }
    @Test
    {
        [1].enable();
        runnew DoSimpleTransaction() );
        crashDuringRotateAndVerify( 1, 3 );
    }
    @Test
    {
        [2].enable();
        runnew DoSimpleTransaction() );
        crashDuringRotateAndVerify( 1, 3 );
    }
    @Test
    {
        [3].enable();
        runnew DoSimpleTransaction() );
        runnew RotateLogs() );
        runnew DoSimpleTransaction() );
        crashDuringRotateAndVerify( 2, 4 );
    }
    @Test
    {
        [4].enable();
        runnew DoSimpleTransaction() );
        runnew RotateLogs() );
        runnew DoSimpleTransaction() );
        crashDuringRotateAndVerify( 2, 4 );
    }
    @Test
    {
        [5].enable();
        runnew DoSimpleTransaction() );
        runnew RotateLogs() );
        runnew DoSimpleTransaction() );
        crashDuringRotateAndVerify( 2, 4 );
    }
    @Test
    {
        [2].enable();
        runInThreadnew Shutdown() );
        .await();
        startSubprocesses();
        runnew Shutdown() );
    }
    @Test
    {
        [6].enable();
        runInThreadnew Shutdown() );
        .await();
        startSubprocesses();
        runnew Shutdown() );
        assertLuceneLogVersionsExists( 0, 1 );
    }
    @Test
    {
        [7].enable();
        runnew DoSimpleTransaction() );
        runInThreadnew RotateLogs. ) );
        .await();
        startSubprocesses();
        runnew Shutdown() );
        assertLuceneLogVersionsExists( 0, 1 );
    }
    
    @Test
    {
        [6].enable();
        runnew DoGraphAndIndexTransaction() );
        runInThreadnew Shutdown() );
        .await();
        startSubprocesses();
        runnew VerifyLastTxId., 3 ) );
    }
    
    @Test
    {
        [7].enable();
        runnew DoSimpleTransaction() );
        runInThreadnew Shutdown() );
        .await();
        startSubprocesses();
        runnew VerifyLastTxId., 3 ) );
    }
    
    private void assertLuceneLogVersionsExistsint... versions ) throws Exception
    {
        Set<IntegerversionSet = new HashSet<Integer>();
        for ( int version : versions )
            versionSet.addversion );
        File path = new FilegetStoreDirthis, 0, false ), "index" );
        for ( File file : path.listFiles() )
        {
            if ( file.getName().contains".log.v" ) )
            {
                int v = parseIntfile.getName().substringfile.getName().lastIndexOf".v" )+2 ) );
                assertTrue"Unexpected version found " + vversionSet.removev ) );
            }
        }
        assertTrue"These versions weren't found " + versionSetversionSet.isEmpty() );
    }
New to GrepCode? Check out our FAQ X