Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The master of a two instance cluster will now serve writes on slave f…
…ailure A two instance cluster cannot tolerate any failures, since quorum is the cluster size. This can be a problem in master+slave_only deployments, where the slave_only instance is meant as simply a read only replica. For this particular scenario, if the slave dies then it makes sense for the master to maintain write capabilities. This commit changes things to make it so that only for two instance clusters, if the slave dies (or a partition happens), the master will continue serving writes
- Loading branch information
1 parent
373f070
commit 326874b
Showing
4 changed files
with
219 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
131 changes: 131 additions & 0 deletions
131
enterprise/ha/src/test/java/org/neo4j/kernel/ha/TwoInstanceClusterIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,131 @@ | |||
/* | |||
* 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 <http://www.gnu.org/licenses/>. | |||
*/ | |||
package org.neo4j.kernel.ha; | |||
|
|||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
|
|||
import org.neo4j.graphdb.Node; | |||
import org.neo4j.graphdb.Transaction; | |||
import org.neo4j.kernel.ha.cluster.HighAvailabilityMemberState; | |||
import org.neo4j.kernel.impl.ha.ClusterManager; | |||
import org.neo4j.test.ha.ClusterRule; | |||
|
|||
import static org.junit.Assert.assertEquals; | |||
import static org.neo4j.kernel.impl.ha.ClusterManager.allSeesAllAsAvailable; | |||
import static org.neo4j.kernel.impl.ha.ClusterManager.clusterOfSize; | |||
import static org.neo4j.kernel.impl.ha.ClusterManager.memberSeesOtherMemberAsFailed; | |||
|
|||
public class TwoInstanceClusterIT | |||
{ | |||
@Rule | |||
public final ClusterRule clusterRule = new ClusterRule( getClass() ); | |||
|
|||
private ClusterManager.ManagedCluster cluster; | |||
|
|||
@Before | |||
public void setup() throws Exception | |||
{ | |||
cluster = clusterRule | |||
.withSharedSetting( HaSettings.read_timeout, "1s" ) | |||
.withSharedSetting( HaSettings.state_switch_timeout, "2s" ) | |||
.withSharedSetting( HaSettings.com_chunk_size, "1024" ) | |||
.withCluster( clusterOfSize( 2 ) ) | |||
.startCluster(); | |||
} | |||
|
|||
@Test | |||
public void masterShouldRemainAvailableIfTheSlaveDiesAndRecovers() throws Throwable | |||
{ | |||
HighlyAvailableGraphDatabase master = cluster.getMaster(); | |||
HighlyAvailableGraphDatabase theSlave = cluster.getAnySlave(); | |||
|
|||
String propertyName = "prop"; | |||
String propertyValue1 = "value1"; | |||
String propertyValue2 = "value2"; | |||
long masterNodeId; | |||
long slaveNodeId; | |||
|
|||
ClusterManager.RepairKit repairKit = cluster.fail( theSlave ); | |||
cluster.await( memberSeesOtherMemberAsFailed( master, theSlave ) ); | |||
|
|||
try( Transaction tx = master.beginTx() ) | |||
{ | |||
Node node = master.createNode(); | |||
node.setProperty( propertyName, propertyValue1 ); | |||
masterNodeId = node.getId(); | |||
tx.success(); | |||
} | |||
|
|||
repairKit.repair(); | |||
|
|||
cluster.await( allSeesAllAsAvailable() ); | |||
|
|||
try( Transaction tx = theSlave.beginTx() ) | |||
{ | |||
Node node = theSlave.createNode(); | |||
node.setProperty( propertyName, propertyValue2 ); | |||
assertEquals( propertyValue1, theSlave.getNodeById( masterNodeId ).getProperty( propertyName ) ); | |||
slaveNodeId = node.getId(); | |||
tx.success(); | |||
} | |||
|
|||
try( Transaction tx = master.beginTx() ) | |||
{ | |||
assertEquals( propertyValue2, master.getNodeById( slaveNodeId ).getProperty( propertyName ) ); | |||
tx.success(); | |||
} | |||
} | |||
|
|||
@Test | |||
public void slaveShouldMoveToPendingAndThenRecoverIfMasterDiesAndThenRecovers() throws Throwable | |||
{ | |||
HighlyAvailableGraphDatabase master = cluster.getMaster(); | |||
HighlyAvailableGraphDatabase theSlave = cluster.getAnySlave(); | |||
|
|||
String propertyName = "prop"; | |||
String propertyValue = "value1"; | |||
long slaveNodeId; | |||
|
|||
ClusterManager.RepairKit repairKit = cluster.fail( master ); | |||
cluster.await( memberSeesOtherMemberAsFailed( theSlave, master) ); | |||
|
|||
assertEquals( HighAvailabilityMemberState.PENDING, theSlave.getInstanceState() ); | |||
|
|||
repairKit.repair(); | |||
|
|||
cluster.await( allSeesAllAsAvailable() ); | |||
|
|||
try( Transaction tx = theSlave.beginTx() ) | |||
{ | |||
Node node = theSlave.createNode(); | |||
slaveNodeId = node.getId(); | |||
node.setProperty( propertyName, propertyValue ); | |||
tx.success(); | |||
} | |||
|
|||
try( Transaction tx = master.beginTx() ) | |||
{ | |||
assertEquals( propertyValue, master.getNodeById( slaveNodeId ).getProperty( propertyName ) ); | |||
tx.success(); | |||
} | |||
} | |||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters