github.com/m3db/m3@v1.5.0/src/cluster/kv/mem/store.go (about) 1 // Copyright (c) 2016 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 mem 22 23 import ( 24 "errors" 25 "sync" 26 27 "github.com/m3db/m3/src/cluster/kv" 28 29 "github.com/golang/protobuf/proto" 30 ) 31 32 // NewStore returns a new in-process store that can be used for testing 33 func NewStore() kv.TxnStore { 34 return &store{ 35 values: make(map[string][]*value), 36 watchables: make(map[string]kv.ValueWatchable), 37 } 38 } 39 40 // NewValue returns a new fake Value around the given proto 41 func NewValue(vers int, msg proto.Message) kv.Value { 42 data, _ := proto.Marshal(msg) 43 return &value{ 44 version: vers, 45 data: data, 46 } 47 } 48 49 // NewValueWithData returns a new fake Value around the given data 50 func NewValueWithData(vers int, data []byte) kv.Value { 51 return &value{ 52 version: vers, 53 data: data, 54 } 55 } 56 57 type value struct { 58 version int 59 revision int 60 data []byte 61 } 62 63 func (v value) Version() int { return v.version } 64 func (v value) Unmarshal(msg proto.Message) error { return proto.Unmarshal(v.data, msg) } 65 func (v value) IsNewer(other kv.Value) bool { 66 otherValue, ok := other.(*value) 67 if !ok { 68 return v.version > other.Version() 69 } 70 if v.revision == otherValue.revision { 71 return v.version > other.Version() 72 } 73 return v.revision > otherValue.revision 74 } 75 76 type store struct { 77 sync.RWMutex 78 79 revision int 80 values map[string][]*value 81 watchables map[string]kv.ValueWatchable 82 } 83 84 // IsMem lets asserting if given store is an in memory one. 85 func IsMem(s kv.Store) bool { 86 _, ok := s.(*store) 87 return ok 88 } 89 90 func (s *store) Get(key string) (kv.Value, error) { 91 s.RLock() 92 defer s.RUnlock() 93 94 return s.getWithLock(key) 95 } 96 97 func (s *store) getWithLock(key string) (kv.Value, error) { 98 val, ok := s.values[key] 99 if !ok { 100 return nil, kv.ErrNotFound 101 } 102 103 if len(val) == 0 { 104 return nil, kv.ErrNotFound 105 } 106 107 return val[len(val)-1], nil 108 } 109 110 func (s *store) Watch(key string) (kv.ValueWatch, error) { 111 s.Lock() 112 val := s.values[key] 113 114 watchable, ok := s.watchables[key] 115 if !ok { 116 watchable = kv.NewValueWatchable() 117 s.watchables[key] = watchable 118 } 119 s.Unlock() 120 121 if !ok && len(val) != 0 { 122 watchable.Update(val[len(val)-1]) 123 } 124 125 _, watch, _ := watchable.Watch() 126 return watch, nil 127 } 128 129 func (s *store) Set(key string, val proto.Message) (int, error) { 130 s.Lock() 131 defer s.Unlock() 132 133 return s.setWithLock(key, val) 134 } 135 136 func (s *store) setWithLock(key string, val proto.Message) (int, error) { 137 data, err := proto.Marshal(val) 138 if err != nil { 139 return 0, err 140 } 141 142 lastVersion := 0 143 vals := s.values[key] 144 145 if len(vals) != 0 { 146 lastVersion = vals[len(vals)-1].version 147 } 148 newVersion := lastVersion + 1 149 s.updateInternalWithLock(key, newVersion, data) 150 return newVersion, nil 151 } 152 153 func (s *store) SetIfNotExists(key string, val proto.Message) (int, error) { 154 data, err := proto.Marshal(val) 155 if err != nil { 156 return 0, err 157 } 158 159 s.Lock() 160 defer s.Unlock() 161 162 if _, exists := s.values[key]; exists { 163 return 0, kv.ErrAlreadyExists 164 } 165 166 s.updateInternalWithLock(key, 1, data) 167 return 1, nil 168 } 169 170 func (s *store) CheckAndSet(key string, version int, val proto.Message) (int, error) { 171 data, err := proto.Marshal(val) 172 if err != nil { 173 return 0, err 174 } 175 176 s.Lock() 177 defer s.Unlock() 178 179 lastVersion := 0 180 vals, exists := s.values[key] 181 if exists && len(vals) != 0 { 182 lastVersion = vals[len(vals)-1].version 183 } 184 185 if version != lastVersion { 186 return 0, kv.ErrVersionMismatch 187 } 188 189 newVersion := version + 1 190 s.updateInternalWithLock(key, newVersion, data) 191 return newVersion, nil 192 } 193 194 func (s *store) updateInternalWithLock(key string, newVersion int, data []byte) { 195 s.revision++ 196 fv := &value{ 197 version: newVersion, 198 revision: s.revision, 199 data: data, 200 } 201 s.values[key] = append(s.values[key], fv) 202 s.updateWatchable(key, fv) 203 } 204 205 func (s *store) Delete(key string) (kv.Value, error) { 206 s.Lock() 207 defer s.Unlock() 208 209 val, ok := s.values[key] 210 if !ok { 211 return nil, kv.ErrNotFound 212 } 213 214 prev := val[len(val)-1] 215 s.updateWatchable(key, nil) 216 delete(s.values, key) 217 return prev, nil 218 } 219 220 func (s *store) History(key string, from, to int) ([]kv.Value, error) { 221 if from <= 0 || to <= 0 || from > to { 222 return nil, errors.New("bad request") 223 } 224 225 if from == to { 226 return nil, nil 227 } 228 229 s.RLock() 230 defer s.RUnlock() 231 232 vals, ok := s.values[key] 233 if !ok { 234 return nil, kv.ErrNotFound 235 } 236 237 l := len(vals) 238 if l == 0 { 239 return nil, kv.ErrNotFound 240 } 241 242 var res []kv.Value 243 for i := from; i < to; i++ { 244 idx := i - 1 245 if idx >= 0 && idx < l { 246 res = append(res, vals[idx]) 247 } 248 } 249 250 return res, nil 251 } 252 253 // NB(cw) When there is an error in one of the ops, the finished ops will not be rolled back 254 func (s *store) Commit(conditions []kv.Condition, ops []kv.Op) (kv.Response, error) { 255 s.Lock() 256 defer s.Unlock() 257 258 for _, condition := range conditions { 259 if condition.CompareType() != kv.CompareEqual || condition.TargetType() != kv.TargetVersion { 260 return nil, errors.New("invalid condition") 261 } 262 263 v, err := s.getWithLock(condition.Key()) 264 expectedVersion := condition.Value().(int) 265 if err != nil { 266 if err == kv.ErrNotFound && expectedVersion == 0 { 267 continue 268 } 269 return nil, err 270 } 271 272 if expectedVersion != v.Version() { 273 return nil, kv.ErrConditionCheckFailed 274 } 275 } 276 277 oprs := make([]kv.OpResponse, len(ops)) 278 for i, op := range ops { 279 if op.Type() != kv.OpSet { 280 return nil, errors.New("invalid op") 281 } 282 opSet := op.(kv.SetOp) 283 284 v, err := s.setWithLock(opSet.Key(), opSet.Value) 285 if err != nil { 286 return nil, err 287 } 288 289 oprs[i] = kv.NewOpResponse(op).SetValue(v) 290 } 291 292 return kv.NewResponse().SetResponses(oprs), nil 293 } 294 295 // updateWatchable updates all subscriptions for the given key. It assumes 296 // the fakeStore write lock is acquired outside of this call 297 func (s *store) updateWatchable(key string, newVal kv.Value) { 298 if watchable, ok := s.watchables[key]; ok { 299 watchable.Update(newVal) 300 } 301 }