@@ -288,13 +288,27 @@ func (b *Bundle) String() string {
288288
289289// Tidy will post optimize Rules, trying to generate rules that suits PD. 
290290func  (b  * Bundle ) Tidy () error  {
291- 	tempRules  :=  b .Rules [:0 ]
292- 	id  :=  0 
291+ 	extraCnt  :=  map [PeerRoleType ]int {}
292+ 	newRules  :=  b .Rules [:0 ]
293+ 
294+ 	// One Bundle is from one PlacementSettings, rule share same location labels, so we can use the first rule's location labels. 
295+ 	var  locationLabels  []string 
293296	for  _ , rule  :=  range  b .Rules  {
297+ 		if  len (rule .LocationLabels ) >  0  {
298+ 			locationLabels  =  rule .LocationLabels 
299+ 			break 
300+ 		}
301+ 	}
302+ 	for  i , rule  :=  range  b .Rules  {
294303		// useless Rule 
295304		if  rule .Count  <=  0  {
296305			continue 
297306		}
307+ 		// merge all empty constraints 
308+ 		if  len (rule .Constraints ) ==  0  {
309+ 			extraCnt [rule .Role ] +=  rule .Count 
310+ 			continue 
311+ 		}
298312		// refer to tidb#22065. 
299313		// add -engine=tiflash to every rule to avoid schedules to tiflash instances. 
300314		// placement rules in SQL is not compatible with `set tiflash replica` yet 
@@ -306,139 +320,36 @@ func (b *Bundle) Tidy() error {
306320		if  err  !=  nil  {
307321			return  err 
308322		}
309- 		rule .ID  =  strconv .Itoa (id )
310- 		tempRules  =  append (tempRules , rule )
311- 		id ++ 
312- 	}
313- 
314- 	groups  :=  make (map [string ]* constraintsGroup )
315- 	finalRules  :=  tempRules [:0 ]
316- 	for  _ , rule  :=  range  tempRules  {
317- 		key  :=  rule .Constraints .FingerPrint ()
318- 		existing , ok  :=  groups [key ]
319- 		if  ! ok  {
320- 			groups [key ] =  & constraintsGroup {rules : []* Rule {rule }}
323+ 		// Constraints.Add() will automatically avoid duplication 
324+ 		// if -engine=tiflash is added and there is only one constraint 
325+ 		// then it must be -engine=tiflash 
326+ 		// it is seen as an empty constraint, so merge it 
327+ 		if  len (rule .Constraints ) ==  1  {
328+ 			extraCnt [rule .Role ] +=  rule .Count 
321329			continue 
322330		}
323- 		existing .rules  =  append (existing .rules , rule )
324- 	}
325- 	for  _ , group  :=  range  groups  {
326- 		group .MergeRulesByRole ()
327- 	}
328- 	if  err  :=  transformableLeaderConstraint (groups ); err  !=  nil  {
329- 		return  err 
330- 	}
331- 	for  _ , group  :=  range  groups  {
332- 		finalRules  =  append (finalRules , group .rules ... )
333- 	}
334- 	// sort by id 
335- 	sort .SliceStable (finalRules , func (i , j  int ) bool  {
336- 		return  finalRules [i ].ID  <  finalRules [j ].ID 
337- 	})
338- 	b .Rules  =  finalRules 
339- 	return  nil 
340- }
341- 
342- // constraintsGroup is a group of rules with the same constraints. 
343- type  constraintsGroup  struct  {
344- 	rules  []* Rule 
345- 	// canBecameLeader means the group has leader/voter role, 
346- 	// it's valid if it has leader. 
347- 	canBecameLeader  bool 
348- 	// isLeaderGroup means it has specified leader role in this group. 
349- 	isLeaderGroup  bool 
350- }
351- 
352- func  transformableLeaderConstraint (groups  map [string ]* constraintsGroup ) error  {
353- 	var  leaderGroup  * constraintsGroup 
354- 	canBecameLeaderNum  :=  0 
355- 	for  _ , group  :=  range  groups  {
356- 		if  group .isLeaderGroup  {
357- 			if  leaderGroup  !=  nil  {
358- 				return  ErrInvalidPlacementOptions 
359- 			}
360- 			leaderGroup  =  group 
361- 		}
362- 		if  group .canBecameLeader  {
363- 			canBecameLeaderNum ++ 
364- 		}
365- 	}
366- 	// If there is a specified group should have leader, and only this group can be a leader, that means 
367- 	// the leader's priority is certain, so we can merge the transformable rules into one. 
368- 	// eg: 
369- 	//  - [ group1 (L F), group2 (F) ], after merging is [group1 (2*V), group2 (F)], we still know the leader prefers group1. 
370- 	//  - [ group1 (L F), group2 (V) ], after merging is [group1 (2*V), group2 (V)], we can't know leader priority after merge. 
371- 	if  leaderGroup  !=  nil  &&  canBecameLeaderNum  ==  1  {
372- 		leaderGroup .MergeTransformableRoles ()
331+ 		rule .ID  =  strconv .Itoa (i )
332+ 		newRules  =  append (newRules , rule )
333+ 	}
334+ 	for  role , cnt  :=  range  extraCnt  {
335+ 		// add -engine=tiflash, refer to tidb#22065. 
336+ 		newRules  =  append (newRules , & Rule {
337+ 			ID :    string (role ),
338+ 			Role :  role ,
339+ 			Count : cnt ,
340+ 			Constraints : []Constraint {{
341+ 				Op :     NotIn ,
342+ 				Key :    EngineLabelKey ,
343+ 				Values : []string {EngineLabelTiFlash },
344+ 			}},
345+ 			// the merged rule should have the same location labels with the original rules. 
346+ 			LocationLabels : locationLabels ,
347+ 		})
373348	}
349+ 	b .Rules  =  newRules 
374350	return  nil 
375351}
376352
377- // MergeRulesByRole merges the rules with the same role. 
378- func  (c  * constraintsGroup ) MergeRulesByRole () {
379- 	// Create a map to store rules by role 
380- 	rulesByRole  :=  make (map [PeerRoleType ][]* Rule )
381- 
382- 	// Iterate through each rule 
383- 	for  _ , rule  :=  range  c .rules  {
384- 		// Add the rule to the map based on its role 
385- 		rulesByRole [rule .Role ] =  append (rulesByRole [rule .Role ], rule )
386- 		if  rule .Role  ==  Leader  ||  rule .Role  ==  Voter  {
387- 			c .canBecameLeader  =  true 
388- 		}
389- 		if  rule .Role  ==  Leader  {
390- 			c .isLeaderGroup  =  true 
391- 		}
392- 	}
393- 
394- 	// Clear existing rules 
395- 	c .rules  =  nil 
396- 
397- 	// Iterate through each role and merge the rules 
398- 	for  _ , rules  :=  range  rulesByRole  {
399- 		mergedRule  :=  rules [0 ]
400- 		for  i , rule  :=  range  rules  {
401- 			if  i  ==  0  {
402- 				continue 
403- 			}
404- 			mergedRule .Count  +=  rule .Count 
405- 			if  mergedRule .ID  >  rule .ID  {
406- 				mergedRule .ID  =  rule .ID 
407- 			}
408- 		}
409- 		c .rules  =  append (c .rules , mergedRule )
410- 	}
411- }
412- 
413- // MergeTransformableRoles merges all the rules to one that can be transformed to other roles. 
414- func  (c  * constraintsGroup ) MergeTransformableRoles () {
415- 	if  len (c .rules ) ==  0  ||  len (c .rules ) ==  1  {
416- 		return 
417- 	}
418- 	var  mergedRule  * Rule 
419- 	newRules  :=  make ([]* Rule , 0 , len (c .rules ))
420- 	for  _ , rule  :=  range  c .rules  {
421- 		// Learner is not transformable, it should be promote by PD. 
422- 		if  rule .Role  ==  Learner  {
423- 			newRules  =  append (newRules , rule )
424- 			continue 
425- 		}
426- 		if  mergedRule  ==  nil  {
427- 			mergedRule  =  rule 
428- 			continue 
429- 		}
430- 		mergedRule .Count  +=  rule .Count 
431- 		if  mergedRule .ID  >  rule .ID  {
432- 			mergedRule .ID  =  rule .ID 
433- 		}
434- 	}
435- 	if  mergedRule  !=  nil  {
436- 		mergedRule .Role  =  Voter 
437- 		newRules  =  append (newRules , mergedRule )
438- 	}
439- 	c .rules  =  newRules 
440- }
441- 
442353// Reset resets the bundle ID and keyrange of all rules. 
443354func  (b  * Bundle ) Reset (ruleIndex  int , newIDs  []int64 ) * Bundle  {
444355	// eliminate the redundant rules. 
0 commit comments