@@ -110,13 +110,23 @@ public class AwarenessAllocationDecider extends AllocationDecider {
110110 Property .NodeScope
111111 );
112112
113+ public static final Setting <Boolean > CLUSTER_ROUTING_ALLOCATION_AWARENESS_ZONE_OPTIMISED = Setting .boolSetting (
114+ "cluster.routing.allocation.awareness.zone_optimised" ,
115+ false ,
116+ Setting .Property .Dynamic ,
117+ Setting .Property .NodeScope
118+ );
119+
113120 private volatile List <String > awarenessAttributes ;
114121
122+ private volatile boolean isAllocationZoneOptimised ;
115123 private volatile Map <String , List <String >> forcedAwarenessAttributes ;
116124
117125 public AwarenessAllocationDecider (Settings settings , ClusterSettings clusterSettings ) {
118126 this .awarenessAttributes = CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING .get (settings );
119127 clusterSettings .addSettingsUpdateConsumer (CLUSTER_ROUTING_ALLOCATION_AWARENESS_ATTRIBUTE_SETTING , this ::setAwarenessAttributes );
128+ this .isAllocationZoneOptimised = CLUSTER_ROUTING_ALLOCATION_AWARENESS_ZONE_OPTIMISED .get (settings );
129+ clusterSettings .addSettingsUpdateConsumer (CLUSTER_ROUTING_ALLOCATION_AWARENESS_ZONE_OPTIMISED , this ::setAllocationZoneOptimised );
120130 setForcedAwarenessAttributes (CLUSTER_ROUTING_ALLOCATION_AWARENESS_FORCE_GROUP_SETTING .get (settings ));
121131 clusterSettings .addSettingsUpdateConsumer (
122132 CLUSTER_ROUTING_ALLOCATION_AWARENESS_FORCE_GROUP_SETTING ,
@@ -140,6 +150,10 @@ private void setAwarenessAttributes(List<String> awarenessAttributes) {
140150 this .awarenessAttributes = awarenessAttributes ;
141151 }
142152
153+ private void setAllocationZoneOptimised (boolean isAllocationZoneOptimised ) {
154+ this .isAllocationZoneOptimised = isAllocationZoneOptimised ;
155+ }
156+
143157 @ Override
144158 public Decision canAllocate (ShardRouting shardRouting , RoutingNode node , RoutingAllocation allocation ) {
145159 return underCapacity (shardRouting , node , allocation , true );
@@ -164,7 +178,7 @@ private Decision underCapacity(ShardRouting shardRouting, RoutingNode node, Rout
164178 int shardCount = indexMetadata .getNumberOfReplicas () + 1 ; // 1 for primary
165179 for (String awarenessAttribute : awarenessAttributes ) {
166180 // the node the shard exists on must be associated with an awareness attribute
167- if (node . node (). getAttributes (). containsKey ( awarenessAttribute ) == false ) {
181+ if (isAwarenessAttributeAssociatedWithNode ( node , awarenessAttribute ) == false ) {
168182 return allocation .decision (
169183 Decision .NO ,
170184 NAME ,
@@ -175,36 +189,10 @@ private Decision underCapacity(ShardRouting shardRouting, RoutingNode node, Rout
175189 );
176190 }
177191
192+ int currentNodeCount = getCurrentNodeCountForAttribute (shardRouting , node , allocation , moveToNode , awarenessAttribute );
193+
178194 // build attr_value -> nodes map
179195 Set <String > nodesPerAttribute = allocation .routingNodes ().nodesPerAttributesCounts (awarenessAttribute );
180-
181- // build the count of shards per attribute value
182- Map <String , Integer > shardPerAttribute = new HashMap <>();
183- for (ShardRouting assignedShard : allocation .routingNodes ().assignedShards (shardRouting .shardId ())) {
184- if (assignedShard .started () || assignedShard .initializing ()) {
185- // Note: this also counts relocation targets as that will be the new location of the shard.
186- // Relocation sources should not be counted as the shard is moving away
187- RoutingNode routingNode = allocation .routingNodes ().node (assignedShard .currentNodeId ());
188- shardPerAttribute .merge (routingNode .node ().getAttributes ().get (awarenessAttribute ), 1 , Integer ::sum );
189- }
190- }
191-
192- if (moveToNode ) {
193- if (shardRouting .assignedToNode ()) {
194- String nodeId = shardRouting .relocating () ? shardRouting .relocatingNodeId () : shardRouting .currentNodeId ();
195- if (node .nodeId ().equals (nodeId ) == false ) {
196- // we work on different nodes, move counts around
197- shardPerAttribute .compute (
198- allocation .routingNodes ().node (nodeId ).node ().getAttributes ().get (awarenessAttribute ),
199- (k , v ) -> (v == null ) ? 0 : v - 1
200- );
201- shardPerAttribute .merge (node .node ().getAttributes ().get (awarenessAttribute ), 1 , Integer ::sum );
202- }
203- } else {
204- shardPerAttribute .merge (node .node ().getAttributes ().get (awarenessAttribute ), 1 , Integer ::sum );
205- }
206- }
207-
208196 int numberOfAttributes = nodesPerAttribute .size ();
209197 List <String > fullValues = forcedAwarenessAttributes .get (awarenessAttribute );
210198
@@ -216,9 +204,8 @@ private Decision underCapacity(ShardRouting shardRouting, RoutingNode node, Rout
216204 }
217205 numberOfAttributes = attributesSet .size ();
218206 }
219- // TODO should we remove ones that are not part of full list?
220207
221- final int currentNodeCount = shardPerAttribute . get ( node . node (). getAttributes (). get ( awarenessAttribute ));
208+ // TODO should we remove ones that are not part of full list?
222209 final int maximumNodeCount = (shardCount + numberOfAttributes - 1 ) / numberOfAttributes ; // ceil(shardCount/numberOfAttributes)
223210 if (currentNodeCount > maximumNodeCount ) {
224211 return allocation .decision (
@@ -238,4 +225,64 @@ private Decision underCapacity(ShardRouting shardRouting, RoutingNode node, Rout
238225
239226 return allocation .decision (Decision .YES , NAME , "node meets all awareness attribute requirements" );
240227 }
228+
229+ private int getCurrentNodeCountForAttribute (
230+ ShardRouting shardRouting ,
231+ RoutingNode node ,
232+ RoutingAllocation allocation ,
233+ boolean moveToNode ,
234+ String awarenessAttribute
235+ ) {
236+ // build the count of shards per attribute value
237+ final String shardAttributeForNode = getAttributeValueForNode (node , awarenessAttribute );
238+ int currentNodeCount = 0 ;
239+ final List <ShardRouting > assignedShards = allocation .routingNodes ().assignedShards (shardRouting .shardId ());
240+ for (ShardRouting assignedShard : assignedShards ) {
241+ if (assignedShard .started () || assignedShard .initializing ()) {
242+ // Note: this also counts relocation targets as that will be the new location of the shard.
243+ // Relocation sources should not be counted as the shard is moving away
244+ RoutingNode routingNode = allocation .routingNodes ().node (assignedShard .currentNodeId ());
245+ // Increase node count when
246+ if (getAttributeValueForNode (routingNode , awarenessAttribute ).equals (shardAttributeForNode )) {
247+ ++currentNodeCount ;
248+ }
249+ }
250+ }
251+
252+ if (moveToNode ) {
253+ if (shardRouting .assignedToNode ()) {
254+ String nodeId = shardRouting .relocating () ? shardRouting .relocatingNodeId () : shardRouting .currentNodeId ();
255+ if (node .nodeId ().equals (nodeId ) == false ) {
256+ // we work on different nodes, move counts around
257+ if (getAttributeValueForNode (allocation .routingNodes ().node (nodeId ), awarenessAttribute ).equals (shardAttributeForNode )
258+ && currentNodeCount > 0 ) {
259+ --currentNodeCount ;
260+ }
261+
262+ ++currentNodeCount ;
263+ }
264+ } else {
265+ ++currentNodeCount ;
266+ }
267+ }
268+
269+ return currentNodeCount ;
270+ }
271+
272+ private boolean isAwarenessAttributeAssociatedWithNode (RoutingNode node , String awarenessAttribute ) {
273+ if (isAllocationZoneOptimised ) {
274+ return node .node ().hasZoneAttribute ();
275+ } else {
276+ return node .node ().getAttributes ().containsKey (awarenessAttribute );
277+ }
278+ }
279+
280+ private String getAttributeValueForNode (final RoutingNode node , final String awarenessAttribute ) {
281+ if (isAllocationZoneOptimised ) {
282+ return node .node ().getZoneValue ();
283+ } else {
284+ return node .node ().getAttributes ().get (awarenessAttribute );
285+ }
286+ }
287+
241288}
0 commit comments