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

     1  /*
     2  Copyright 2022 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  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    21  	"vitess.io/vitess/go/vt/topo/topoproto"
    22  	"vitess.io/vitess/go/vt/vtctl/reparentutil/promotionrule"
    23  )
    24  
    25  // SemiSyncAckersForPrimary returns the list of tablets which are capable of sending Semi-Sync Acks for the given primary tablet
    26  func SemiSyncAckersForPrimary(durability Durabler, primary *topodatapb.Tablet, allTablets []*topodatapb.Tablet) (semiSyncAckers []*topodatapb.Tablet) {
    27  	for _, tablet := range allTablets {
    28  		if topoproto.TabletAliasEqual(primary.Alias, tablet.Alias) {
    29  			continue
    30  		}
    31  		if IsReplicaSemiSync(durability, primary, tablet) {
    32  			semiSyncAckers = append(semiSyncAckers, tablet)
    33  		}
    34  	}
    35  	return
    36  }
    37  
    38  // haveRevokedForTablet checks whether we have reached enough tablets such that the given primary eligible tablet cannot accept any new writes
    39  // The tablets reached should have their replication stopped and must be set to read only.
    40  func haveRevokedForTablet(durability Durabler, primaryEligible *topodatapb.Tablet, tabletsReached []*topodatapb.Tablet, allTablets []*topodatapb.Tablet) bool {
    41  	// if we have reached the primaryEligible tablet and stopped its replication and marked it read only, then it will not
    42  	// accept any new writes
    43  	if topoproto.IsTabletInList(primaryEligible, tabletsReached) {
    44  		return true
    45  	}
    46  
    47  	// semiSyncAckersReached is the list of reachable tablets capable of sending semi sync Acks for the given primaryEligible tablet
    48  	semiSyncAckersReached := SemiSyncAckersForPrimary(durability, primaryEligible, tabletsReached)
    49  
    50  	// allSemiSyncAckers is the list of reachable tablets capable of sending semi sync Acks for the given primaryEligible tablet
    51  	allSemiSyncAckers := SemiSyncAckersForPrimary(durability, primaryEligible, allTablets)
    52  
    53  	// numOfSemiSyncAcksRequired is the number of semi sync Acks that the primaryEligible tablet requires
    54  	numOfSemiSyncAcksRequired := SemiSyncAckers(durability, primaryEligible)
    55  
    56  	// if we have reached enough semi-sync Acking tablets such that the primaryEligible cannot accept a write
    57  	// we have revoked from the tablet
    58  	return len(allSemiSyncAckers)-len(semiSyncAckersReached) < numOfSemiSyncAcksRequired
    59  }
    60  
    61  // haveRevoked checks whether we have reached enough tablets to guarantee that no tablet eligible to become a primary can accept any write
    62  // All the tablets reached must have their replication stopped and set to read only for us to guarantee that we have revoked access
    63  // from all the primary eligible tablets (prevent them from accepting any new writes)
    64  func haveRevoked(durability Durabler, tabletsReached []*topodatapb.Tablet, allTablets []*topodatapb.Tablet) bool {
    65  	for _, tablet := range allTablets {
    66  		if PromotionRule(durability, tablet) == promotionrule.MustNot {
    67  			continue
    68  		}
    69  		if !haveRevokedForTablet(durability, tablet, tabletsReached, allTablets) {
    70  			return false
    71  		}
    72  	}
    73  	return true
    74  }
    75  
    76  // canEstablishForTablet checks whether we have reached enough tablets to say that the given primary eligible tablet will be able to accept new writes
    77  func canEstablishForTablet(durability Durabler, primaryEligible *topodatapb.Tablet, tabletsReached []*topodatapb.Tablet) bool {
    78  	// if we have not reached the primaryEligible tablet, then it cannot be considered eligible to accept writes
    79  	// since it might have been stopped
    80  	if !topoproto.IsTabletInList(primaryEligible, tabletsReached) {
    81  		return false
    82  	}
    83  
    84  	// semiSyncAckersReached is the list of reachable tablets capable of sending semi sync Acks for the given primaryEligible tablet
    85  	semiSyncAckersReached := SemiSyncAckersForPrimary(durability, primaryEligible, tabletsReached)
    86  
    87  	// numOfSemiSyncAcksRequired is the number of semi sync Acks that the primaryEligible tablet requires
    88  	numOfSemiSyncAcksRequired := SemiSyncAckers(durability, primaryEligible)
    89  
    90  	// if we have reached enough semi-sync Acking tablets such that the primaryEligible can accept a write
    91  	// we can safely promote this tablet
    92  	return len(semiSyncAckersReached) >= numOfSemiSyncAcksRequired
    93  }