diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupCoreIT.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupCoreIT.java index 5eef0f15d3d48..5bd08ac6da0c9 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupCoreIT.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupCoreIT.java @@ -24,28 +24,20 @@ import org.junit.Test; import java.io.File; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.List; import org.neo4j.backup.OnlineBackupSettings; -import org.neo4j.causalclustering.core.CausalClusteringSettings; -import org.neo4j.causalclustering.core.CoreGraphDatabase; import org.neo4j.causalclustering.discovery.Cluster; import org.neo4j.causalclustering.discovery.CoreClusterMember; -import org.neo4j.graphdb.Node; -import org.neo4j.graphdb.factory.GraphDatabaseSettings; -import org.neo4j.helpers.collection.MapUtil; -import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; -import org.neo4j.kernel.impl.store.format.standard.Standard; import org.neo4j.test.DbRepresentation; import org.neo4j.test.causalclustering.ClusterRule; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.neo4j.backup.OnlineBackupCommandIT.runBackupToolFromOtherJvmToGetExitCode; -import static org.neo4j.graphdb.Label.label; +import static org.neo4j.causalclustering.helpers.BackupUtil.backupAddress; +import static org.neo4j.causalclustering.helpers.BackupUtil.backupArguments; +import static org.neo4j.causalclustering.helpers.BackupUtil.getConfig; +import static org.neo4j.causalclustering.helpers.DataCreator.createSomeData; public class BackupCoreIT { @@ -86,37 +78,4 @@ public void makeSureBackupCanBePerformedFromAnyInstance() throws Throwable assertNotEquals( backupRepresentation, afterChange ); } } - - static CoreGraphDatabase createSomeData( Cluster cluster ) throws Exception - { - return cluster.coreTx( ( db, tx ) -> - { - Node node = db.createNode( label( "boo" ) ); - node.setProperty( "foobar", "baz_bat" ); - tx.success(); - } ).database(); - } - - static String backupAddress( GraphDatabaseFacade db ) - { - InetSocketAddress inetSocketAddress = db.getDependencyResolver() - .resolveDependency( Config.class ).get( CausalClusteringSettings.transaction_advertised_address ) - .socketAddress(); - return inetSocketAddress.getHostName() + ":" + (inetSocketAddress.getPort() + 2000); - } - - static String[] backupArguments( String from, File backupsDir, String name ) - { - List args = new ArrayList<>(); - args.add( "--from=" + from ); - args.add( "--cc-report-dir=" + backupsDir ); - args.add( "--backup-dir=" + backupsDir ); - args.add( "--name=" + name ); - return args.toArray( new String[args.size()] ); - } - - static Config getConfig() - { - return Config.embeddedDefaults( MapUtil.stringMap( GraphDatabaseSettings.record_format.name(), Standard.LATEST_NAME ) ); - } } diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupReadReplicaIT.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupReadReplicaIT.java index 5610cae27066b..bd42670f81705 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupReadReplicaIT.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/BackupReadReplicaIT.java @@ -43,14 +43,14 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.neo4j.backup.OnlineBackupCommandIT.runBackupToolFromOtherJvmToGetExitCode; -import static org.neo4j.causalclustering.backup.BackupCoreIT.backupArguments; -import static org.neo4j.causalclustering.backup.BackupCoreIT.createSomeData; -import static org.neo4j.causalclustering.backup.BackupCoreIT.getConfig; +import static org.neo4j.causalclustering.helpers.BackupUtil.backupArguments; +import static org.neo4j.causalclustering.helpers.BackupUtil.getConfig; +import static org.neo4j.causalclustering.helpers.DataCreator.createSomeData; import static org.neo4j.function.Predicates.awaitEx; public class BackupReadReplicaIT { - private int backupPort = findFreePort( 22000, 23000); + private int backupPort = findFreePort( 22000, 23000 ); @Rule public ClusterRule clusterRule = new ClusterRule( BackupReadReplicaIT.class ).withNumberOfCoreMembers( 3 ) diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/ClusterSeedingIT.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/ClusterSeedingIT.java index e2d6d4a62113f..e692a1e06aa29 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/ClusterSeedingIT.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/ClusterSeedingIT.java @@ -21,16 +21,21 @@ import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; import java.io.File; +import java.util.Arrays; import java.util.Map; import java.util.function.IntFunction; import org.neo4j.backup.OnlineBackupSettings; -import org.neo4j.causalclustering.core.CoreGraphDatabase; +import org.neo4j.causalclustering.backup.backup_stores.BackupStore; +import org.neo4j.causalclustering.backup.backup_stores.BackupStoreWithSomeData; +import org.neo4j.causalclustering.backup.backup_stores.BackupStoreWithSomeDataButNoTransactionLogs; +import org.neo4j.causalclustering.backup.backup_stores.EmptyBackupStore; import org.neo4j.causalclustering.discovery.Cluster; import org.neo4j.causalclustering.discovery.CoreClusterMember; import org.neo4j.causalclustering.discovery.IpFamily; @@ -43,17 +48,34 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; -import static org.junit.Assert.assertEquals; -import static org.neo4j.backup.OnlineBackupCommandIT.runBackupToolFromOtherJvmToGetExitCode; -import static org.neo4j.causalclustering.backup.BackupCoreIT.backupAddress; +import static org.junit.Assert.assertFalse; import static org.neo4j.causalclustering.discovery.Cluster.dataMatchesEventually; -import static org.neo4j.causalclustering.helpers.DataCreator.createEmptyNodes; +import static org.neo4j.causalclustering.helpers.BackupUtil.restoreFromBackup; +@RunWith( Parameterized.class ) public class ClusterSeedingIT { private Cluster backupCluster; private Cluster cluster; private FileSystemAbstraction fsa; + private FileCopyDetector fileCopyDetector; + + @Parameterized.Parameters( name = "{0}" ) + public static Iterable data() throws Exception + { + return stores(); + } + + private static Iterable stores() + { + return Arrays.asList( + new EmptyBackupStore(), + new BackupStoreWithSomeData(), + new BackupStoreWithSomeDataButNoTransactionLogs() ); + } + + @Parameterized.Parameter() + public BackupStore initialStore; @Rule public TestDirectory testDir = TestDirectory.testDirectory(); @@ -63,6 +85,7 @@ public class ClusterSeedingIT @Before public void setup() throws Exception { + this.fileCopyDetector = new FileCopyDetector(); fsa = fileSystemRule.get(); backupCluster = new Cluster( testDir.directory( "cluster-for-backup" ), 3, 0, new SharedDiscoveryService(), emptyMap(), backupParams(), emptyMap(), emptyMap(), Standard @@ -95,101 +118,27 @@ public void after() throws Exception } } - private File createBackupUsingAnotherCluster() throws Exception + @Test + public void shouldSeedNewCluster() throws Exception { + // given backupCluster.start(); - CoreGraphDatabase db = BackupCoreIT.createSomeData( backupCluster ); - - File backup = createBackup( db, "some-backup" ); + File backup = initialStore.get( baseBackupDir, backupCluster ); backupCluster.shutdown(); - return backup; - } - - private File createBackup( CoreGraphDatabase db, String backupName ) throws Exception - { - String[] args = BackupCoreIT.backupArguments( backupAddress( db ), baseBackupDir, backupName ); - assertEquals( 0, runBackupToolFromOtherJvmToGetExitCode( testDir.absolutePath(), args ) ); - return new File( baseBackupDir, backupName ); - } + for ( CoreClusterMember coreClusterMember : cluster.coreMembers() ) + { + restoreFromBackup( backup, fsa, coreClusterMember ); + } - @Test - public void shouldRestoreBySeedingAllMembers() throws Throwable - { - // given - File backupDir = createBackupUsingAnotherCluster(); - DbRepresentation before = DbRepresentation.of( backupDir ); + // we want the cluster to seed from backup. No instance should delete and re-copy the store. + cluster.coreMembers().forEach( ccm -> ccm.monitors().addMonitorListener( fileCopyDetector ) ); // when - fsa.copyRecursively( backupDir, cluster.getCoreMemberById( 0 ).storeDir() ); - fsa.copyRecursively( backupDir, cluster.getCoreMemberById( 1 ).storeDir() ); - fsa.copyRecursively( backupDir, cluster.getCoreMemberById( 2 ).storeDir() ); - cluster.start(); - // then - dataMatchesEventually( before, cluster.coreMembers() ); - } - - @Test - public void shouldSeedNewMemberFromEmptyIdleCluster() throws Throwable - { - // given - cluster = new Cluster( testDir.directory( "cluster-b" ), 3, 0, - new SharedDiscoveryService(), emptyMap(), backupParams(), emptyMap(), emptyMap(), Standard - .LATEST_NAME, IpFamily.IPV4, false ); - cluster.start(); - - // when: creating a backup - File backupDir = createBackup( cluster.getCoreMemberById( 0 ).database(), "the-backup" ); - - // and: seeding new member with said backup - CoreClusterMember newMember = cluster.addCoreMemberWithId( 3 ); - fsa.copyRecursively( backupDir, newMember.storeDir() ); - newMember.start(); - - // then - dataMatchesEventually( DbRepresentation.of( newMember.database() ), cluster.coreMembers() ); - } - - @Test - public void shouldSeedNewMemberFromNonEmptyIdleCluster() throws Throwable - { - // given - cluster = new Cluster( testDir.directory( "cluster-b" ), 3, 0, - new SharedDiscoveryService(), emptyMap(), backupParams(), emptyMap(), emptyMap(), Standard - .LATEST_NAME, IpFamily.IPV4, false ); - cluster.start(); - createEmptyNodes( cluster, 100 ); - - // when: creating a backup - File backupDir = createBackup( cluster.getCoreMemberById( 0 ).database(), "the-backup" ); - - // and: seeding new member with said backup - CoreClusterMember newMember = cluster.addCoreMemberWithId( 3 ); - fsa.copyRecursively( backupDir, newMember.storeDir() ); - newMember.start(); - - // then - dataMatchesEventually( DbRepresentation.of( newMember.database() ), cluster.coreMembers() ); - } - - @Test - @Ignore( "need to seed all members for now" ) - public void shouldRestoreBySeedingSingleMember() throws Throwable - { - // given - File backupDir = createBackupUsingAnotherCluster(); - DbRepresentation before = DbRepresentation.of( backupDir ); - - // when - fsa.copyRecursively( backupDir, cluster.getCoreMemberById( 0 ).storeDir() ); - cluster.getCoreMemberById( 0 ).start(); - Thread.sleep( 2_000 ); - cluster.getCoreMemberById( 1 ).start(); - cluster.getCoreMemberById( 2 ).start(); - - // then - dataMatchesEventually( before, cluster.coreMembers() ); + //then + dataMatchesEventually( DbRepresentation.of( backup ), cluster.coreMembers() ); + assertFalse( fileCopyDetector.hasDetectedAnyFileCopied() ); } } diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/FileCopyDetector.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/FileCopyDetector.java new file mode 100644 index 0000000000000..77dfb0728c675 --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/FileCopyDetector.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.backup; + +import java.io.File; + +import org.neo4j.causalclustering.catchup.tx.FileCopyMonitor; + +public class FileCopyDetector implements FileCopyMonitor +{ + private volatile boolean hasCopiedFile = false; + + @Override + public void copyFile( File file ) + { + hasCopiedFile = true; + } + + public boolean hasDetectedAnyFileCopied() + { + return hasCopiedFile; + } +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/NewMemberSeedingIT.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/NewMemberSeedingIT.java new file mode 100644 index 0000000000000..ab478db5866df --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/NewMemberSeedingIT.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.backup; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.File; +import java.util.Arrays; +import java.util.Map; +import java.util.function.IntFunction; + +import org.neo4j.backup.OnlineBackupSettings; +import org.neo4j.causalclustering.backup.backup_stores.BackupStore; +import org.neo4j.causalclustering.backup.backup_stores.BackupStoreWithSomeData; +import org.neo4j.causalclustering.backup.backup_stores.BackupStoreWithSomeDataButNoTransactionLogs; +import org.neo4j.causalclustering.backup.backup_stores.EmptyBackupStore; +import org.neo4j.causalclustering.discovery.Cluster; +import org.neo4j.causalclustering.discovery.CoreClusterMember; +import org.neo4j.causalclustering.discovery.IpFamily; +import org.neo4j.causalclustering.discovery.SharedDiscoveryService; +import org.neo4j.io.fs.DefaultFileSystemAbstraction; +import org.neo4j.kernel.impl.store.format.standard.Standard; +import org.neo4j.test.rule.TestDirectory; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonMap; +import static org.junit.Assert.assertFalse; +import static org.neo4j.causalclustering.discovery.Cluster.dataMatchesEventually; +import static org.neo4j.causalclustering.helpers.BackupUtil.restoreFromBackup; + +@RunWith( Parameterized.class ) +public class NewMemberSeedingIT +{ + private Cluster cluster; + private DefaultFileSystemAbstraction fsa = new DefaultFileSystemAbstraction(); + private FileCopyDetector fileCopyDetector; + + @Parameterized.Parameters( name = "{0}" ) + public static Iterable data() throws Exception + { + return stores(); + } + + private static Iterable stores() + { + return Arrays + .asList( new EmptyBackupStore(), new BackupStoreWithSomeData(), + new BackupStoreWithSomeDataButNoTransactionLogs() ); + } + + @Parameterized.Parameter() + public BackupStore seedStore; + + @Rule + public TestDirectory testDir = TestDirectory.testDirectory(); + private File baseBackupDir; + + @Before + public void setup() throws Exception + { + this.fileCopyDetector = new FileCopyDetector(); + cluster = new Cluster( testDir.directory( "cluster-b" ), 3, 0, + new SharedDiscoveryService(), emptyMap(), backupParams(), emptyMap(), emptyMap(), Standard.LATEST_NAME, + IpFamily.IPV4, false ); + baseBackupDir = testDir.directory( "backups" ); + } + + private Map> backupParams() + { + return singletonMap( + OnlineBackupSettings.online_backup_server.name(), + serverId -> ":" + (8000 + serverId) ); + } + + @After + public void after() throws Exception + { + if ( cluster != null ) + { + cluster.shutdown(); + } + } + + @Test + public void shouldSeedNewMemberToCluster() throws Exception + { + // given + cluster.start(); + + // when + File backup = seedStore.get( baseBackupDir, cluster ); + CoreClusterMember newCoreClusterMember = cluster.addCoreMemberWithId( 3 ); + restoreFromBackup( backup, fsa, newCoreClusterMember ); + // we want the new instance to seed from backup and not delete and re-download the store + newCoreClusterMember.monitors().addMonitorListener( fileCopyDetector ); + newCoreClusterMember.start(); + + // then + dataMatchesEventually( newCoreClusterMember, cluster.coreMembers() ); + assertFalse( fileCopyDetector.hasDetectedAnyFileCopied() ); + } +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/AbstractStoreGenerator.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/AbstractStoreGenerator.java new file mode 100644 index 0000000000000..d3c4aecd6f61a --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/AbstractStoreGenerator.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.backup.backup_stores; + +import java.io.File; +import java.util.UUID; + +import org.neo4j.causalclustering.core.CoreGraphDatabase; +import org.neo4j.causalclustering.discovery.Cluster; + +import static org.neo4j.causalclustering.helpers.BackupUtil.createBackupFromCore; + +public abstract class AbstractStoreGenerator implements BackupStore +{ + private File backup; + + abstract CoreGraphDatabase createData( Cluster cluster ) throws Exception; + + abstract void modify( File backup ); + + private void generate( File backupDir, Cluster backupCluster ) throws Exception + { + CoreGraphDatabase db = createData( backupCluster ); + this.backup = createBackupFromCore( db, backupName(), backupDir ); + modify( backup ); + } + + @Override + public File get( File backupDir, Cluster backupCluster ) throws Exception + { + if ( backup == null ) + { + generate( backupDir, backupCluster ); + } + return backup; + } + + private String backupName() + { + return "backup-" + UUID.randomUUID().toString().substring( 5 ); + } +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStore.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStore.java new file mode 100644 index 0000000000000..6a3775ed07cff --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStore.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.backup.backup_stores; + +import java.io.File; + +import org.neo4j.causalclustering.discovery.Cluster; + +public interface BackupStore +{ + File get(File backupDir, Cluster backupCluster) throws Exception; +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStoreWithSomeData.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStoreWithSomeData.java new file mode 100644 index 0000000000000..1d7abe9b6100c --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStoreWithSomeData.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.backup.backup_stores; + +import java.io.File; + +import org.neo4j.causalclustering.core.CoreGraphDatabase; +import org.neo4j.causalclustering.discovery.Cluster; + +import static org.neo4j.causalclustering.helpers.DataCreator.createEmptyNodes; + +public class BackupStoreWithSomeData extends AbstractStoreGenerator +{ + @Override + CoreGraphDatabase createData( Cluster cluster ) throws Exception + { + return createEmptyNodes( cluster, 15 ).database(); + } + + @Override + void modify( File backup ) + { + // do nothing + } +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStoreWithSomeDataButNoTransactionLogs.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStoreWithSomeDataButNoTransactionLogs.java new file mode 100644 index 0000000000000..753d823e3363a --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/BackupStoreWithSomeDataButNoTransactionLogs.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.backup.backup_stores; + +import java.io.File; + +import org.neo4j.causalclustering.core.CoreGraphDatabase; +import org.neo4j.causalclustering.discovery.Cluster; + +import static org.junit.Assert.assertTrue; +import static org.neo4j.causalclustering.helpers.DataCreator.createEmptyNodes; + +public class BackupStoreWithSomeDataButNoTransactionLogs extends AbstractStoreGenerator +{ + @Override + CoreGraphDatabase createData( Cluster cluster ) throws Exception + { + return createEmptyNodes( cluster, 10 ).database(); + } + + @Override + void modify( File backup ) + { + for ( File transaction : backup.listFiles( ( dir, name ) -> name.contains( "transaction" ) ) ) + { + assertTrue( transaction.delete() ); + } + } +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/EmptyBackupStore.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/EmptyBackupStore.java new file mode 100644 index 0000000000000..21669e5102417 --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/backup/backup_stores/EmptyBackupStore.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.backup.backup_stores; + +import java.io.File; + +import org.neo4j.causalclustering.core.CoreGraphDatabase; +import org.neo4j.causalclustering.discovery.Cluster; + +public class EmptyBackupStore extends AbstractStoreGenerator +{ + @Override + CoreGraphDatabase createData( Cluster cluster ) + { + return cluster.coreMembers().iterator().next().database(); + } + + @Override + void modify( File backup ) + { + // do nothing + } +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/discovery/CoreClusterMember.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/discovery/CoreClusterMember.java index 67e8f24e9d2fc..d4ba7de3efd72 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/discovery/CoreClusterMember.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/discovery/CoreClusterMember.java @@ -44,6 +44,7 @@ import org.neo4j.kernel.configuration.HttpConnector; import org.neo4j.kernel.configuration.HttpConnector.Encryption; import org.neo4j.kernel.configuration.Settings; +import org.neo4j.kernel.monitoring.Monitors; import org.neo4j.logging.Level; import static java.lang.String.format; @@ -64,6 +65,7 @@ public class CoreClusterMember implements ClusterMember private final int serverId; private final String boltAdvertisedSocketAddress; private CoreGraphDatabase database; + private final Monitors monitors = new Monitors(); public CoreClusterMember( int serverId, int clusterSize, List addresses, @@ -146,7 +148,7 @@ public String directURI() public void start() { database = new CoreGraphDatabase( storeDir, Config.embeddedDefaults( config ), - GraphDatabaseDependencies.newDependencies(), discoveryServiceFactory ); + GraphDatabaseDependencies.newDependencies().monitors( monitors ), discoveryServiceFactory ); } @Override @@ -216,6 +218,11 @@ public ClientConnectorAddresses clientConnectorAddresses() return ClientConnectorAddresses.extractFromConfig( Config.embeddedDefaults( this.config ) ); } + public Monitors monitors() + { + return monitors; + } + public File clusterStateDirectory() { return clusterStateDir; @@ -228,6 +235,11 @@ public File raftLogDirectory() public void stopCatchupServer() throws Throwable { - database.getDependencyResolver().resolveDependency( CatchupServer.class).stop(); + database.getDependencyResolver().resolveDependency( CatchupServer.class ).stop(); + } + + public Config config() + { + return Config.embeddedDefaults( config ); } } diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/helpers/BackupUtil.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/helpers/BackupUtil.java new file mode 100644 index 0000000000000..32b0bf8292838 --- /dev/null +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/helpers/BackupUtil.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2002-2017 "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 Affero 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.helpers; + +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; + +import org.neo4j.causalclustering.backup.BackupCoreIT; +import org.neo4j.causalclustering.core.CausalClusteringSettings; +import org.neo4j.causalclustering.core.CoreGraphDatabase; +import org.neo4j.causalclustering.discovery.Cluster; +import org.neo4j.causalclustering.discovery.CoreClusterMember; +import org.neo4j.commandline.admin.CommandFailed; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.factory.GraphDatabaseSettings; +import org.neo4j.helpers.collection.MapUtil; +import org.neo4j.io.fs.FileSystemAbstraction; +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; +import org.neo4j.kernel.impl.store.format.standard.Standard; +import org.neo4j.kernel.impl.store.format.standard.StandardV3_0; +import org.neo4j.restore.RestoreDatabaseCommand; + +import static org.junit.Assert.assertEquals; +import static org.neo4j.backup.OnlineBackupCommandIT.runBackupToolFromOtherJvmToGetExitCode; +import static org.neo4j.graphdb.Label.label; + +public class BackupUtil +{ + public static String backupAddress( GraphDatabaseFacade db ) + { + InetSocketAddress inetSocketAddress = db.getDependencyResolver() + .resolveDependency( Config.class ).get( CausalClusteringSettings.transaction_advertised_address ) + .socketAddress(); + return inetSocketAddress.getHostName() + ":" + (inetSocketAddress.getPort() + 2000); + } + + public static String[] backupArguments( String from, File backupsDir, String name ) + { + List args = new ArrayList<>(); + args.add( "--from=" + from ); + args.add( "--cc-report-dir=" + backupsDir ); + args.add( "--backup-dir=" + backupsDir ); + args.add( "--name=" + name ); + return args.toArray( new String[args.size()] ); + } + + public static Config getConfig() + { + return Config.embeddedDefaults( MapUtil.stringMap( GraphDatabaseSettings.record_format.name(), Standard.LATEST_NAME ) ); + } + + public static File createBackupFromCore( CoreGraphDatabase db, String backupName, File baseBackupDir ) throws Exception + { + String[] args = backupArguments( backupAddress( db ), baseBackupDir, backupName ); + assertEquals( 0, runBackupToolFromOtherJvmToGetExitCode( baseBackupDir, args ) ); + return new File( baseBackupDir, backupName ); + } + + public static void restoreFromBackup( File backup, FileSystemAbstraction fsa, CoreClusterMember coreClusterMember ) + throws IOException, CommandFailed + { + Config config = coreClusterMember.config(); + RestoreDatabaseCommand restoreDatabaseCommand = + new RestoreDatabaseCommand( fsa, backup, config, "graph-db", true ); + restoreDatabaseCommand.execute(); + } +} diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/helpers/DataCreator.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/helpers/DataCreator.java index 4753bb4a4a4db..0675eb41b0b8c 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/helpers/DataCreator.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/helpers/DataCreator.java @@ -29,10 +29,21 @@ import org.neo4j.graphdb.Transaction; import org.neo4j.helpers.collection.Pair; +import static org.neo4j.graphdb.Label.label; import static org.neo4j.helpers.collection.Iterables.count; public class DataCreator { + public static CoreGraphDatabase createSomeData( Cluster cluster ) throws Exception + { + return cluster.coreTx( ( db, tx ) -> + { + Node node = db.createNode( label( "boo" ) ); + node.setProperty( "foobar", "baz_bat" ); + tx.success(); + } ).database(); + } + public static CoreClusterMember createLabelledNodesWithProperty( Cluster cluster, int numberOfNodes, Label label, Supplier> supplier ) throws Exception {