github.com/zhyoulun/cilium@v1.6.12/pkg/kvstore/backend.go (about)

     1  // Copyright 2017-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package kvstore
    16  
    17  import (
    18  	"context"
    19  	"time"
    20  
    21  	"google.golang.org/grpc"
    22  )
    23  
    24  type backendOption struct {
    25  	// description is the description of the option
    26  	description string
    27  
    28  	// value is the value the option has been configured to
    29  	value string
    30  
    31  	// validate, if set, is called to validate the value before assignment
    32  	validate func(value string) error
    33  }
    34  
    35  type backendOptions map[string]*backendOption
    36  
    37  // ExtraOptions represents any options that can not be represented in a textual
    38  // format and need to be set programmatically.
    39  type ExtraOptions struct {
    40  	DialOption []grpc.DialOption
    41  
    42  	// ClusterSizeDependantInterval defines the function to calculate
    43  	// intervals based on cluster size
    44  	ClusterSizeDependantInterval func(baseInterval time.Duration) time.Duration
    45  }
    46  
    47  // StatusCheckInterval returns the interval of status checks depending on the
    48  // cluster size and the current connectivity state
    49  //
    50  // nodes      OK  Failing
    51  // 1         20s       3s
    52  // 4         45s       7s
    53  // 8       1m05s      11s
    54  // 32      1m45s      18s
    55  // 128     2m25s      24s
    56  // 512     3m07s      32s
    57  // 2048    3m46s      38s
    58  // 8192    4m30s      45s
    59  func (e *ExtraOptions) StatusCheckInterval(allConnected bool) time.Duration {
    60  	interval := 30 * time.Second
    61  
    62  	// Reduce the interval while connectivity issues are being detected
    63  	if !allConnected {
    64  		interval = 5 * time.Second
    65  	}
    66  
    67  	if e != nil && e.ClusterSizeDependantInterval != nil {
    68  		interval = e.ClusterSizeDependantInterval(interval)
    69  	}
    70  	return interval
    71  }
    72  
    73  // backendModule is the interface that each kvstore backend has to implement.
    74  type backendModule interface {
    75  	// getName must return the name of the backend
    76  	getName() string
    77  
    78  	// setConfig must configure the backend with the specified options.
    79  	// This function is called once before newClient().
    80  	setConfig(opts map[string]string) error
    81  
    82  	// setExtraConfig sets more options in the kvstore that are not able to
    83  	// be set by strings.
    84  	setExtraConfig(opts *ExtraOptions) error
    85  
    86  	// setConfigDummy must configure the backend with dummy configuration
    87  	// for testing purposes. This is a replacement for setConfig().
    88  	setConfigDummy()
    89  
    90  	// getConfig must return the backend configuration.
    91  	getConfig() map[string]string
    92  
    93  	// newClient must initializes the backend and create a new kvstore
    94  	// client which implements the BackendOperations interface
    95  	newClient(opts *ExtraOptions) (BackendOperations, chan error)
    96  
    97  	// createInstance creates a new instance of the module
    98  	createInstance() backendModule
    99  }
   100  
   101  var (
   102  	// registeredBackends is a slice of all backends that have registered
   103  	// itself via registerBackend()
   104  	registeredBackends = map[string]backendModule{}
   105  )
   106  
   107  // registerBackend must be called by kvstore backends to register themselves
   108  func registerBackend(name string, module backendModule) {
   109  	if _, ok := registeredBackends[name]; ok {
   110  		log.Panicf("backend with name '%s' already registered", name)
   111  	}
   112  
   113  	registeredBackends[name] = module
   114  }
   115  
   116  // getBackend finds a registered backend by name
   117  func getBackend(name string) backendModule {
   118  	if backend, ok := registeredBackends[name]; ok {
   119  		return backend.createInstance()
   120  	}
   121  
   122  	return nil
   123  }
   124  
   125  // BackendOperations are the individual kvstore operations that each backend
   126  // must implement. Direct use of this interface is possible but will bypass the
   127  // tracing layer.
   128  type BackendOperations interface {
   129  	// Connected returns a channel which is closed whenever the kvstore client
   130  	// is connected to the kvstore server. (Only implemented for etcd)
   131  	Connected() <-chan struct{}
   132  
   133  	// Disconnected returns a channel which is closed whenever the kvstore
   134  	// client is not connected to the kvstore server. (Only implemented for etcd)
   135  	Disconnected() <-chan struct{}
   136  
   137  	// Status returns the status of the kvstore client including an
   138  	// eventual error
   139  	Status() (string, error)
   140  
   141  	// LockPath locks the provided path
   142  	LockPath(ctx context.Context, path string) (KVLocker, error)
   143  
   144  	// Get returns value of key
   145  	Get(key string) ([]byte, error)
   146  
   147  	// GetIfLocked returns value of key if the client is still holding the given lock.
   148  	GetIfLocked(key string, lock KVLocker) ([]byte, error)
   149  
   150  	// GetPrefix returns the first key which matches the prefix and its value
   151  	GetPrefix(ctx context.Context, prefix string) (string, []byte, error)
   152  
   153  	// GetPrefixIfLocked returns the first key which matches the prefix and its value if the client is still holding the given lock.
   154  	GetPrefixIfLocked(ctx context.Context, prefix string, lock KVLocker) (string, []byte, error)
   155  
   156  	// Set sets value of key
   157  	Set(key string, value []byte) error
   158  
   159  	// Delete deletes a key
   160  	Delete(key string) error
   161  
   162  	// DeleteIfLocked deletes a key if the client is still holding the given lock.
   163  	DeleteIfLocked(key string, lock KVLocker) error
   164  
   165  	DeletePrefix(path string) error
   166  
   167  	// Update atomically creates a key or fails if it already exists
   168  	Update(ctx context.Context, key string, value []byte, lease bool) error
   169  
   170  	// UpdateIfLocked atomically creates a key or fails if it already exists if the client is still holding the given lock.
   171  	UpdateIfLocked(ctx context.Context, key string, value []byte, lease bool, lock KVLocker) error
   172  
   173  	// UpdateIfDifferent updates a key if the value is different
   174  	UpdateIfDifferent(ctx context.Context, key string, value []byte, lease bool) (bool, error)
   175  
   176  	// UpdateIfDifferentIfLocked updates a key if the value is different and if the client is still holding the given lock.
   177  	UpdateIfDifferentIfLocked(ctx context.Context, key string, value []byte, lease bool, lock KVLocker) (bool, error)
   178  
   179  	// CreateOnly atomically creates a key or fails if it already exists
   180  	CreateOnly(ctx context.Context, key string, value []byte, lease bool) (bool, error)
   181  
   182  	// CreateOnlyIfLocked atomically creates a key if the client is still holding the given lock or fails if it already exists
   183  	CreateOnlyIfLocked(ctx context.Context, key string, value []byte, lease bool, lock KVLocker) (bool, error)
   184  
   185  	// CreateIfExists creates a key with the value only if key condKey exists
   186  	CreateIfExists(condKey, key string, value []byte, lease bool) error
   187  
   188  	// ListPrefix returns a list of keys matching the prefix
   189  	ListPrefix(prefix string) (KeyValuePairs, error)
   190  
   191  	// ListPrefixIfLocked returns a list of keys matching the prefix only if the client is still holding the given lock.
   192  	ListPrefixIfLocked(prefix string, lock KVLocker) (KeyValuePairs, error)
   193  
   194  	// Watch starts watching for changes in a prefix. If list is true, the
   195  	// current keys matching the prefix will be listed and reported as new
   196  	// keys first.
   197  	Watch(w *Watcher)
   198  
   199  	// Close closes the kvstore client
   200  	Close()
   201  
   202  	// GetCapabilities returns the capabilities of the backend
   203  	GetCapabilities() Capabilities
   204  
   205  	// Encodes a binary slice into a character set that the backend
   206  	// supports
   207  	Encode(in []byte) string
   208  
   209  	// Decodes a key previously encoded back into the original binary slice
   210  	Decode(in string) ([]byte, error)
   211  
   212  	// ListAndWatch creates a new watcher which will watch the specified
   213  	// prefix for changes. Before doing this, it will list the current keys
   214  	// matching the prefix and report them as new keys. Name can be set to
   215  	// anything and is used for logging messages. The Events channel is
   216  	// created with the specified sizes. Upon every change observed, a
   217  	// KeyValueEvent will be sent to the Events channel
   218  	ListAndWatch(name, prefix string, chanSize int) *Watcher
   219  }