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 }