github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/gossip/util.go (about) 1 // Copyright 2018 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 gossip 12 13 import ( 14 "bytes" 15 "sort" 16 17 "github.com/cockroachdb/cockroach/pkg/config" 18 "github.com/cockroachdb/cockroach/pkg/config/zonepb" 19 "github.com/cockroachdb/cockroach/pkg/roachpb" 20 ) 21 22 // SystemConfigDeltaFilter keeps track of SystemConfig values so that unmodified 23 // values can be filtered out from a SystemConfig update. This can prevent 24 // repeatedly unmarshaling and processing the same SystemConfig values. 25 // 26 // A SystemConfigDeltaFilter is not safe for concurrent use by multiple 27 // goroutines. 28 type SystemConfigDeltaFilter struct { 29 keyPrefix roachpb.Key 30 lastCfg *config.SystemConfig 31 } 32 33 // MakeSystemConfigDeltaFilter creates a new SystemConfigDeltaFilter. The filter 34 // will ignore all key-values without the specified key prefix, if one is 35 // provided. 36 func MakeSystemConfigDeltaFilter(keyPrefix roachpb.Key) SystemConfigDeltaFilter { 37 return SystemConfigDeltaFilter{ 38 keyPrefix: keyPrefix, 39 lastCfg: config.NewSystemConfig(zonepb.DefaultZoneConfigRef()), 40 } 41 } 42 43 // ForModified calls the provided function for all SystemConfig kvs that were modified 44 // since the last call to this method. 45 func (df *SystemConfigDeltaFilter) ForModified( 46 newCfg *config.SystemConfig, fn func(kv roachpb.KeyValue), 47 ) { 48 // Save newCfg in the filter. 49 lastCfg := df.lastCfg 50 df.lastCfg = config.NewSystemConfig(newCfg.DefaultZoneConfig) 51 df.lastCfg.Values = newCfg.Values 52 53 // SystemConfig values are always sorted by key, so scan over new and old 54 // configs in order to find new keys and modified values. Before doing so, 55 // skip all keys in each list of values that are less than the keyPrefix. 56 lastIdx, newIdx := 0, 0 57 if df.keyPrefix != nil { 58 lastIdx = sort.Search(len(lastCfg.Values), func(i int) bool { 59 return bytes.Compare(lastCfg.Values[i].Key, df.keyPrefix) >= 0 60 }) 61 newIdx = sort.Search(len(newCfg.Values), func(i int) bool { 62 return bytes.Compare(newCfg.Values[i].Key, df.keyPrefix) >= 0 63 }) 64 } 65 66 for { 67 if newIdx == len(newCfg.Values) { 68 // All out of new keys. 69 break 70 } 71 72 newKV := newCfg.Values[newIdx] 73 if df.keyPrefix != nil && !bytes.HasPrefix(newKV.Key, df.keyPrefix) { 74 // All out of new keys matching prefix. 75 break 76 } 77 78 if lastIdx < len(lastCfg.Values) { 79 oldKV := lastCfg.Values[lastIdx] 80 switch oldKV.Key.Compare(newKV.Key) { 81 case -1: 82 // Deleted key. 83 lastIdx++ 84 case 0: 85 if !newKV.Value.EqualData(oldKV.Value) { 86 // Modified value. 87 fn(newKV) 88 } 89 lastIdx++ 90 newIdx++ 91 case 1: 92 // New key. 93 fn(newKV) 94 newIdx++ 95 } 96 } else { 97 // New key. 98 fn(newKV) 99 newIdx++ 100 } 101 } 102 }