github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/constraint/analyzer.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package constraint 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 17 "github.com/cockroachdb/cockroach/pkg/roachpb" 18 ) 19 20 // AnalyzedConstraints represents the result or AnalyzeConstraints(). It 21 // combines a zone's constraints with information about which stores satisfy 22 // what term of the constraints disjunction. 23 type AnalyzedConstraints struct { 24 Constraints []zonepb.ConstraintsConjunction 25 // True if the per-replica constraints don't fully cover all the desired 26 // replicas in the range (sum(constraints.NumReplicas) < zone.NumReplicas). 27 // In such cases, we allow replicas that don't match any of the per-replica 28 // constraints, but never mark them as necessary. 29 UnconstrainedReplicas bool 30 // For each conjunction of constraints in the above slice, track which 31 // StoreIDs satisfy them. This field is unused if there are no constraints. 32 SatisfiedBy [][]roachpb.StoreID 33 // Maps from StoreID to the indices in the constraints slice of which 34 // constraints the store satisfies. This field is unused if there are no 35 // constraints. 36 Satisfies map[roachpb.StoreID][]int 37 } 38 39 // AnalyzeConstraints processes the zone config constraints that apply to a 40 // range along with the current replicas for a range, spitting back out 41 // information about which constraints are satisfied by which replicas and 42 // which replicas satisfy which constraints, aiding in allocation decisions. 43 func AnalyzeConstraints( 44 ctx context.Context, 45 getStoreDescFn func(roachpb.StoreID) (roachpb.StoreDescriptor, bool), 46 existing []roachpb.ReplicaDescriptor, 47 zone *zonepb.ZoneConfig, 48 ) AnalyzedConstraints { 49 result := AnalyzedConstraints{ 50 Constraints: zone.Constraints, 51 } 52 53 if len(zone.Constraints) > 0 { 54 result.SatisfiedBy = make([][]roachpb.StoreID, len(zone.Constraints)) 55 result.Satisfies = make(map[roachpb.StoreID][]int) 56 } 57 58 var constrainedReplicas int32 59 for i, subConstraints := range zone.Constraints { 60 constrainedReplicas += subConstraints.NumReplicas 61 for _, repl := range existing { 62 // If for some reason we don't have the store descriptor (which shouldn't 63 // happen once a node is hooked into gossip), trust that it's valid. This 64 // is a much more stable failure state than frantically moving everything 65 // off such a node. 66 store, ok := getStoreDescFn(repl.StoreID) 67 if !ok || ConjunctionsCheck(store, subConstraints.Constraints) { 68 result.SatisfiedBy[i] = append(result.SatisfiedBy[i], store.StoreID) 69 result.Satisfies[store.StoreID] = append(result.Satisfies[store.StoreID], i) 70 } 71 } 72 } 73 if constrainedReplicas > 0 && constrainedReplicas < *zone.NumReplicas { 74 result.UnconstrainedReplicas = true 75 } 76 return result 77 } 78 79 // ConjunctionsCheck checks a store against a single set of constraints (out of 80 // the possibly numerous sets that apply to a range), returning true iff the 81 // store matches the constraints. The contraints are AND'ed together; a store 82 // matches the conjunction if it matches all of them. 83 func ConjunctionsCheck(store roachpb.StoreDescriptor, constraints []zonepb.Constraint) bool { 84 for _, constraint := range constraints { 85 // StoreSatisfiesConstraint returns whether a store matches the given constraint. 86 hasConstraint := zonepb.StoreMatchesConstraint(store, constraint) 87 if (constraint.Type == zonepb.Constraint_REQUIRED && !hasConstraint) || 88 (constraint.Type == zonepb.Constraint_PROHIBITED && hasConstraint) { 89 return false 90 } 91 } 92 return true 93 }