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  }