vitess.io/vitess@v0.16.2/go/vt/vtctl/reparentutil/reparent_sorter.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package reparentutil
    18  
    19  import (
    20  	"sort"
    21  
    22  	"vitess.io/vitess/go/mysql"
    23  	"vitess.io/vitess/go/vt/vterrors"
    24  
    25  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    26  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    27  )
    28  
    29  // reparentSorter sorts tablets by GTID positions and Promotion rules aimed at finding the best
    30  // candidate for intermediate promotion in emergency reparent shard, and the new primary in planned reparent shard
    31  type reparentSorter struct {
    32  	tablets    []*topodatapb.Tablet
    33  	positions  []mysql.Position
    34  	durability Durabler
    35  }
    36  
    37  // newReparentSorter creates a new reparentSorter
    38  func newReparentSorter(tablets []*topodatapb.Tablet, positions []mysql.Position, durability Durabler) *reparentSorter {
    39  	return &reparentSorter{
    40  		tablets:    tablets,
    41  		positions:  positions,
    42  		durability: durability,
    43  	}
    44  }
    45  
    46  // Len implements the Interface for sorting
    47  func (rs *reparentSorter) Len() int { return len(rs.tablets) }
    48  
    49  // Swap implements the Interface for sorting
    50  func (rs *reparentSorter) Swap(i, j int) {
    51  	rs.tablets[i], rs.tablets[j] = rs.tablets[j], rs.tablets[i]
    52  	rs.positions[i], rs.positions[j] = rs.positions[j], rs.positions[i]
    53  }
    54  
    55  // Less implements the Interface for sorting
    56  func (rs *reparentSorter) Less(i, j int) bool {
    57  	// Returning "true" in this function means [i] is before [j] in the sorting order,
    58  	// which will lead to [i] be a better candidate for promotion
    59  
    60  	// Should not happen
    61  	// fail-safe code
    62  	if rs.tablets[i] == nil {
    63  		return false
    64  	}
    65  	if rs.tablets[j] == nil {
    66  		return true
    67  	}
    68  
    69  	if !rs.positions[i].AtLeast(rs.positions[j]) {
    70  		// [i] does not have all GTIDs that [j] does
    71  		return false
    72  	}
    73  	if !rs.positions[j].AtLeast(rs.positions[i]) {
    74  		// [j] does not have all GTIDs that [i] does
    75  		return true
    76  	}
    77  
    78  	// at this point, both have the same GTIDs
    79  	// so we check their promotion rules
    80  	jPromotionRule := PromotionRule(rs.durability, rs.tablets[j])
    81  	iPromotionRule := PromotionRule(rs.durability, rs.tablets[i])
    82  	return !jPromotionRule.BetterThan(iPromotionRule)
    83  }
    84  
    85  // sortTabletsForReparent sorts the tablets, given their positions for emergency reparent shard and planned reparent shard.
    86  // Tablets are sorted first by their replication positions, with ties broken by the promotion rules.
    87  func sortTabletsForReparent(tablets []*topodatapb.Tablet, positions []mysql.Position, durability Durabler) error {
    88  	// throw an error internal error in case of unequal number of tablets and positions
    89  	// fail-safe code prevents panic in sorting in case the lengths are unequal
    90  	if len(tablets) != len(positions) {
    91  		return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unequal number of tablets and positions")
    92  	}
    93  
    94  	sort.Sort(newReparentSorter(tablets, positions, durability))
    95  	return nil
    96  }