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  }