github.com/iotexproject/iotex-core@v1.14.1-rc1/db/kvstore_impl.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package db
     7  
     8  import (
     9  	"context"
    10  
    11  	"github.com/pkg/errors"
    12  
    13  	"github.com/iotexproject/go-pkgs/cache"
    14  	"github.com/iotexproject/iotex-core/db/batch"
    15  	"github.com/iotexproject/iotex-core/pkg/util/byteutil"
    16  )
    17  
    18  var (
    19  	// ErrBucketNotExist indicates certain bucket does not exist in db
    20  	ErrBucketNotExist = errors.New("bucket not exist in DB")
    21  	// ErrNotExist indicates certain item does not exist in Blockchain database
    22  	ErrNotExist = errors.New("not exist in DB")
    23  	// ErrIO indicates the generic error of DB I/O operation
    24  	ErrIO = errors.New("DB I/O operation error")
    25  	// ErrNotSupported indicates that api is not supported
    26  	ErrNotSupported = errors.New("not supported")
    27  )
    28  
    29  const (
    30  	_keyDelimiter = "."
    31  )
    32  
    33  // memKVStore is the in-memory implementation of KVStore for testing purpose
    34  type memKVStore struct {
    35  	data   cache.LRUCache
    36  	bucket cache.LRUCache
    37  }
    38  
    39  // NewMemKVStore instantiates an in-memory KV store
    40  func NewMemKVStore() KVStoreForRangeIndex {
    41  	return &memKVStore{
    42  		bucket: cache.NewThreadSafeLruCache(0),
    43  		data:   cache.NewThreadSafeLruCache(0),
    44  	}
    45  }
    46  
    47  func (m *memKVStore) Start(_ context.Context) error { return nil }
    48  
    49  func (m *memKVStore) Stop(_ context.Context) error { return nil }
    50  
    51  // Put inserts a <key, value> record
    52  func (m *memKVStore) Put(namespace string, key, value []byte) error {
    53  	if _, ok := m.bucket.Get(namespace); !ok {
    54  		m.bucket.Add(namespace, struct{}{})
    55  	}
    56  	m.data.Add(namespace+_keyDelimiter+string(key), value)
    57  	return nil
    58  }
    59  
    60  func (m *memKVStore) Insert(name []byte, key uint64, value []byte) error {
    61  	return ErrNotSupported
    62  }
    63  
    64  func (m *memKVStore) Purge(name []byte, key uint64) error {
    65  	return ErrNotSupported
    66  }
    67  
    68  func (m *memKVStore) Remove(name []byte, key uint64) error {
    69  	return ErrNotSupported
    70  }
    71  
    72  func (m *memKVStore) SeekPrev(name []byte, key uint64) ([]byte, error) {
    73  	return nil, ErrNotSupported
    74  }
    75  
    76  func (m *memKVStore) SeekNext(name []byte, key uint64) ([]byte, error) {
    77  	return nil, ErrNotSupported
    78  }
    79  
    80  // Get retrieves a record
    81  func (m *memKVStore) Get(namespace string, key []byte) ([]byte, error) {
    82  	if _, ok := m.bucket.Get(namespace); !ok {
    83  		return nil, errors.Wrapf(ErrNotExist, "namespace = %x doesn't exist", []byte(namespace))
    84  	}
    85  	value, _ := m.data.Get(namespace + _keyDelimiter + string(key))
    86  	if value != nil {
    87  		return value.([]byte), nil
    88  	}
    89  	return nil, errors.Wrapf(ErrNotExist, "key = %x doesn't exist", key)
    90  }
    91  
    92  // Get retrieves a record
    93  func (m *memKVStore) Range(namespace string, key []byte, count uint64) ([][]byte, error) {
    94  	if _, ok := m.bucket.Get(namespace); !ok {
    95  		return nil, errors.Wrapf(ErrNotExist, "namespace = %s doesn't exist", namespace)
    96  	}
    97  	value := make([][]byte, count)
    98  	start := byteutil.BytesToUint64BigEndian(key)
    99  	for i := uint64(0); i < count; i++ {
   100  		key = byteutil.Uint64ToBytesBigEndian(start + i)
   101  		v, _ := m.data.Get(namespace + _keyDelimiter + string(key))
   102  		if v == nil {
   103  			return nil, errors.Wrapf(ErrNotExist, "key = %x doesn't exist", key)
   104  		}
   105  		value[i] = make([]byte, len(v.([]byte)))
   106  		copy(value[i], v.([]byte))
   107  	}
   108  	return value, nil
   109  }
   110  
   111  // Delete deletes a record
   112  func (m *memKVStore) Delete(namespace string, key []byte) error {
   113  	m.data.Remove(namespace + _keyDelimiter + string(key))
   114  	return nil
   115  }
   116  
   117  // Filter returns <k, v> pair in a bucket that meet the condition
   118  func (m *memKVStore) Filter(namespace string, c Condition, minKey, maxKey []byte) ([][]byte, [][]byte, error) {
   119  	// TODO: implement filter for memKVStore
   120  	return nil, nil, errors.New("in-memory KVStore does not support Filter()")
   121  }
   122  
   123  // WriteBatch commits a batch
   124  func (m *memKVStore) WriteBatch(b batch.KVStoreBatch) (e error) {
   125  	succeed := false
   126  	b.Lock()
   127  	defer func() {
   128  		if succeed {
   129  			// clear the batch if commit succeeds
   130  			b.ClearAndUnlock()
   131  		} else {
   132  			b.Unlock()
   133  		}
   134  	}()
   135  	for i := 0; i < b.Size(); i++ {
   136  		write, err := b.Entry(i)
   137  		if err != nil {
   138  			return err
   139  		}
   140  		switch write.WriteType() {
   141  		case batch.Put:
   142  			if err := m.Put(write.Namespace(), write.Key(), write.Value()); err != nil {
   143  				e = err
   144  			}
   145  		case batch.Delete:
   146  			if err := m.Delete(write.Namespace(), write.Key()); err != nil {
   147  				e = err
   148  			}
   149  		}
   150  		if e != nil {
   151  			break
   152  		}
   153  	}
   154  	if e == nil {
   155  		succeed = true
   156  	}
   157  
   158  	return e
   159  }
   160  
   161  // GetBucketByPrefix retrieves all bucket those with const namespace prefix
   162  func (m *memKVStore) GetBucketByPrefix(namespace []byte) ([][]byte, error) {
   163  	return nil, ErrNotSupported
   164  }
   165  
   166  // GetKeyByPrefix retrieves all keys those with const prefix
   167  func (m *memKVStore) GetKeyByPrefix(namespace, prefix []byte) ([][]byte, error) {
   168  	return nil, ErrNotSupported
   169  }