github.com/m3db/m3@v1.5.0/src/cluster/kv/util/runtime/value.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package runtime 22 23 import ( 24 "fmt" 25 26 "github.com/m3db/m3/src/cluster/kv" 27 "github.com/m3db/m3/src/x/watch" 28 29 "go.uber.org/zap" 30 ) 31 32 // Value is a value that can be updated during runtime. 33 type Value interface { 34 watch.Value 35 36 // Key is the key associated with value. 37 Key() string 38 } 39 40 // UnmarshalFn unmarshals a kv value and extracts its payload. 41 type UnmarshalFn func(value kv.Value) (interface{}, error) 42 43 // ProcessFn processes a value. 44 type ProcessFn func(value interface{}) error 45 46 type value struct { 47 watch.Value 48 49 key string 50 store kv.Store 51 opts Options 52 log *zap.Logger 53 unmarshalFn UnmarshalFn 54 processFn ProcessFn 55 updateFn watch.ProcessFn 56 57 currValue kv.Value 58 } 59 60 // NewValue creates a new value. 61 func NewValue( 62 key string, 63 opts Options, 64 ) Value { 65 v := &value{ 66 key: key, 67 store: opts.KVStore(), 68 opts: opts, 69 log: opts.InstrumentOptions().Logger(), 70 unmarshalFn: opts.UnmarshalFn(), 71 processFn: opts.ProcessFn(), 72 } 73 v.updateFn = v.update 74 v.initValue() 75 return v 76 } 77 78 func (v *value) initValue() { 79 valueOpts := watch.NewOptions(). 80 SetInstrumentOptions(v.opts.InstrumentOptions()). 81 SetInitWatchTimeout(v.opts.InitWatchTimeout()). 82 SetNewUpdatableFn(v.newUpdatableFn). 83 SetGetUpdateFn(v.getUpdateFn). 84 SetProcessFn(v.updateFn). 85 SetKey(v.key). 86 SetInterruptedCh(v.opts.InterruptedCh()) 87 v.Value = watch.NewValue(valueOpts) 88 } 89 90 func (v *value) Key() string { return v.key } 91 92 func (v *value) newUpdatableFn() (watch.Updatable, error) { 93 return v.store.Watch(v.key) 94 } 95 96 func (v *value) getUpdateFn(updatable watch.Updatable) (interface{}, error) { 97 return updatable.(kv.ValueWatch).Get(), nil 98 } 99 100 func (v *value) update(value interface{}) error { 101 update := value.(kv.Value) 102 if v.currValue != nil && !update.IsNewer(v.currValue) { 103 v.log.Warn("ignore kv update with version which is not newer than the version of the current value", 104 zap.Int("new version", update.Version()), 105 zap.Int("current version", v.currValue.Version())) 106 return nil 107 } 108 v.log.Info("received kv update", 109 zap.Int("version", update.Version()), 110 zap.String("key", v.key)) 111 latest, err := v.unmarshalFn(update) 112 if err != nil { 113 return fmt.Errorf("error unmarshalling value for version %d: %v", update.Version(), err) 114 } 115 if err := v.processFn(latest); err != nil { 116 return err 117 } 118 v.currValue = update 119 return nil 120 }