1717
1818package org .apache .ignite .cache .affinity .rendezvous ;
1919
20- import java .util .HashMap ;
2120import java .util .List ;
22- import java .util .Map ;
2321import org .apache .ignite .cluster .ClusterNode ;
22+ import org .apache .ignite .internal .util .typedef .internal .S ;
2423import 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}
0 commit comments