Skip to content

Commit a1c6b3f

Browse files
IGNITE-26580 Address review comments
1 parent c1c0fa1 commit a1c6b3f

File tree

2 files changed

+76
-35
lines changed

2 files changed

+76
-35
lines changed

modules/core/src/main/java/org/apache/ignite/cache/affinity/rendezvous/MdcAffinityBackupFilter.java

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@
1717

1818
package org.apache.ignite.cache.affinity.rendezvous;
1919

20-
import java.util.HashMap;
2120
import java.util.List;
22-
import java.util.Map;
2321
import org.apache.ignite.cluster.ClusterNode;
22+
import org.apache.ignite.internal.util.typedef.internal.S;
2423
import org.apache.ignite.lang.IgniteBiPredicate;
2524

2625
/**
@@ -77,16 +76,34 @@ public class MdcAffinityBackupFilter implements IgniteBiPredicate<ClusterNode, L
7776
/** */
7877
private final int partCopiesPerDc;
7978

80-
/** Map is used to optimize the time it takes to perform a partition assignment procedure. */
81-
private final Map<String, Integer> partsDistrMap;
82-
8379
/**
8480
* @param dcsNum Number of data centers.
8581
* @param backups Number of backups.
8682
*/
8783
public MdcAffinityBackupFilter(int dcsNum, int backups) {
88-
partsDistrMap = new HashMap<>(dcsNum + 1);
89-
partCopiesPerDc = (backups + 1) / dcsNum;
84+
if (dcsNum < 2) {
85+
throw new IllegalArgumentException("MdcAffinityBackupFilter cannot be used in an environment with only one datacenter. " +
86+
"Number of datacenters must be at least 2.");
87+
}
88+
89+
int numCopies = backups + 1;
90+
91+
partCopiesPerDc = numCopies / dcsNum;
92+
int remainder = numCopies % dcsNum;
93+
94+
if (remainder != 0) {
95+
String suggestion = "recommended ";
96+
if (numCopies - remainder <= 0)
97+
suggestion += "value is " + (backups + (dcsNum - remainder));
98+
else
99+
suggestion += "values are " + (backups - remainder) + " and " + (backups + (dcsNum - remainder));
100+
101+
throw new IllegalArgumentException("Number of copies is not completely divisible by number of datacenters, " +
102+
"copies cannot be distributed evenly across DCs. " +
103+
"Please adjust the number of backups, " + suggestion);
104+
}
105+
106+
90107
}
91108

92109
/**
@@ -98,33 +115,23 @@ public MdcAffinityBackupFilter(int dcsNum, int backups) {
98115
* The primary is first.
99116
*/
100117
@Override public boolean apply(ClusterNode candidate, List<ClusterNode> previouslySelected) {
101-
if (previouslySelected.size() == 1) { //list contains only primary node, thus we started new assignment round.
102-
partsDistrMap.replaceAll((e, v) -> -1);
103-
104-
partsDistrMap.put(previouslySelected.get(0).dataCenterId(), 1);
105-
}
106-
107-
boolean res = false;
108118
String candidateDcId = candidate.dataCenterId();
119+
int candDcCopiesAssigned = 0;
109120

110-
if (candidateDcId == null)
111-
throw new IllegalStateException("Data center ID is not specified for the node: " + candidate);
121+
for (int i = 0; i < previouslySelected.size(); i++) {
122+
String prevDcId = previouslySelected.get(i).dataCenterId();
112123

113-
Integer candDcPartsCopies = partsDistrMap.get(candidateDcId);
124+
if (prevDcId == null)
125+
return false;
114126

115-
if (candDcPartsCopies == null || candDcPartsCopies == -1) {
116-
partsDistrMap.put(candidateDcId, 1);
117-
118-
res = true;
127+
candDcCopiesAssigned += prevDcId.equals(candidateDcId) ? 1 : 0;
119128
}
120-
else {
121-
if (candDcPartsCopies < partCopiesPerDc) {
122-
partsDistrMap.put(candidateDcId, candDcPartsCopies + 1);
123129

124-
res = true;
125-
}
126-
}
130+
return candDcCopiesAssigned < partCopiesPerDc;
131+
}
127132

128-
return res;
133+
/** {@inheritDoc} */
134+
@Override public String toString() {
135+
return S.toString(MdcAffinityBackupFilter.class, this);
129136
}
130137
}

modules/core/src/test/java/org/apache/ignite/cache/affinity/rendezvous/MdcAffinityBackupFilterSelfTest.java

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import java.util.Map;
2424
import java.util.stream.Collectors;
2525
import org.apache.ignite.IgniteCache;
26-
import org.apache.ignite.IgniteCheckedException;
2726
import org.apache.ignite.IgniteSystemProperties;
2827
import org.apache.ignite.cache.affinity.Affinity;
2928
import org.apache.ignite.cluster.ClusterNode;
@@ -38,7 +37,7 @@
3837
*/
3938
public class MdcAffinityBackupFilterSelfTest extends GridCommonAbstractTest {
4039
/** */
41-
private static final int PARTS_CNT = 1024;
40+
private static final int PARTS_CNT = 8;
4241

4342
/** */
4443
private int backups;
@@ -59,18 +58,40 @@ public class MdcAffinityBackupFilterSelfTest extends GridCommonAbstractTest {
5958
return cfg;
6059
}
6160

62-
/** {@inheritDoc} */
63-
@Override protected IgniteConfiguration optimize(IgniteConfiguration cfg) throws IgniteCheckedException {
64-
return super.optimize(cfg).setIncludeProperties((String[])null);
65-
}
66-
6761
/** {@inheritDoc} */
6862
@Override protected void afterTest() throws Exception {
6963
super.afterTest();
7064

7165
stopAllGrids();
7266
}
7367

68+
/**
69+
* Verifies that {@link MdcAffinityBackupFilter} prohibits single data center deployment.
70+
*/
71+
@Test
72+
public void testSingleDcDeploymentIsProhibited() {
73+
dcIds = new String[] {"DC_0"};
74+
System.setProperty(IgniteSystemProperties.IGNITE_DATA_CENTER_ID, dcIds[0]);
75+
76+
backups = 1;
77+
verifyGridFailsToStartWithMessage("Number of datacenters must be at least 2.");
78+
}
79+
80+
/**
81+
* Verifies that {@link MdcAffinityBackupFilter} enforces even number of partition copies per datacenter.
82+
*/
83+
@Test
84+
public void testEvenNumberOfPartitionCopiesPerDcIsEnforced() {
85+
dcIds = new String[] {"DC_0", "DC_1", "DC_2"};
86+
System.setProperty(IgniteSystemProperties.IGNITE_DATA_CENTER_ID, dcIds[0]);
87+
88+
backups = 1;
89+
verifyGridFailsToStartWithMessage("recommended value is 2");
90+
91+
backups = 7;
92+
verifyGridFailsToStartWithMessage("recommended values are 5 and 8");
93+
}
94+
7495
/**
7596
* Verifies that partition copies are assigned evenly across a cluster in two data centers.
7697
* <p/>
@@ -119,6 +140,19 @@ public void test3DcDistribution() throws Exception {
119140
verifyDistributionProperties(srv, dcIds, nodesPerDc, backups);
120141
}
121142

143+
/** */
144+
private void verifyGridFailsToStartWithMessage(String msg) {
145+
try {
146+
startGrid(0);
147+
} catch (IllegalArgumentException argEx) {
148+
String errMsg = argEx.getMessage();
149+
150+
assertTrue(errMsg.contains(msg));
151+
} catch (Exception e) {
152+
fail("Unexpected exception was thrown: " + e);
153+
}
154+
}
155+
122156
/** Starts specified number of nodes in each DC. */
123157
private IgniteEx startClusterAcrossDataCenters(String[] dcIds, int nodesPerDc) throws Exception {
124158
int nodeIdx = 0;

0 commit comments

Comments
 (0)