github.com/iotexproject/iotex-core@v1.14.1-rc1/db/batch/kv_cache.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 batch
     7  
     8  type (
     9  	// KVStoreCache is a local cache of batched <k, v> for fast query
    10  	KVStoreCache interface {
    11  		// Read retrieves a record
    12  		Read(*kvCacheKey) ([]byte, error)
    13  		// Write puts a record into cache
    14  		Write(*kvCacheKey, []byte)
    15  		// WriteIfNotExist puts a record into cache only if it doesn't exist, otherwise return ErrAlreadyExist
    16  		WriteIfNotExist(*kvCacheKey, []byte) error
    17  		// Evict deletes a record from cache
    18  		Evict(*kvCacheKey)
    19  		// Clear clear the cache
    20  		Clear()
    21  		// Append appends caches
    22  		Append(...KVStoreCache) error
    23  	}
    24  
    25  	// kvCacheKey is the key for 2D Map cache
    26  	kvCacheKey struct {
    27  		key1 string
    28  		key2 string
    29  	}
    30  	kvCacheValue []int
    31  
    32  	node struct {
    33  		value   []byte
    34  		deleted bool
    35  	}
    36  
    37  	// kvCache implements KVStoreCache interface
    38  	kvCache struct {
    39  		cache map[string]map[string]*node // local cache of batched <k, v> for fast query
    40  	}
    41  )
    42  
    43  func newkvCacheValue(v []int) *kvCacheValue {
    44  	return (*kvCacheValue)(&v)
    45  }
    46  
    47  func (kv *kvCacheValue) reset() {
    48  	([]int)(*kv)[0] = 0
    49  	*kv = (*kv)[:1]
    50  }
    51  
    52  func (kv *kvCacheValue) pop() {
    53  	*kv = (*kv)[:kv.len()-1]
    54  }
    55  func (kv *kvCacheValue) get() []int {
    56  	return ([]int)(*kv)
    57  }
    58  
    59  func (kv *kvCacheValue) getAt(i int) int {
    60  	return ([]int)(*kv)[i]
    61  }
    62  
    63  func (kv *kvCacheValue) append(v int) {
    64  	*kv = append(*kv, v)
    65  }
    66  
    67  func (kv *kvCacheValue) len() int {
    68  	return len(*kv)
    69  }
    70  
    71  func (kv *kvCacheValue) last() int {
    72  	return (*kv)[len(*kv)-1]
    73  }
    74  
    75  // NewKVCache returns a KVCache
    76  func NewKVCache() KVStoreCache {
    77  	return &kvCache{
    78  		cache: make(map[string]map[string]*node),
    79  	}
    80  }
    81  
    82  // Read retrieves a record
    83  func (c *kvCache) Read(key *kvCacheKey) ([]byte, error) {
    84  	if ns, ok := c.cache[key.key1]; ok {
    85  		if node, ok := ns[key.key2]; ok {
    86  			if node.deleted {
    87  				return nil, ErrAlreadyDeleted
    88  			}
    89  			return node.value, nil
    90  		}
    91  	}
    92  	return nil, ErrNotExist
    93  }
    94  
    95  // Write puts a record into cache
    96  func (c *kvCache) Write(key *kvCacheKey, v []byte) {
    97  	if _, ok := c.cache[key.key1]; !ok {
    98  		c.cache[key.key1] = make(map[string]*node)
    99  	}
   100  	c.cache[key.key1][key.key2] = &node{
   101  		value:   v,
   102  		deleted: false,
   103  	}
   104  }
   105  
   106  // WriteIfNotExist puts a record into cache only if it doesn't exist, otherwise return ErrAlreadyExist
   107  func (c *kvCache) WriteIfNotExist(key *kvCacheKey, v []byte) error {
   108  	if _, ok := c.cache[key.key1]; !ok {
   109  		c.cache[key.key1] = make(map[string]*node)
   110  	}
   111  	if node, ok := c.cache[key.key1][key.key2]; ok && !node.deleted {
   112  		return ErrAlreadyExist
   113  	}
   114  	c.cache[key.key1][key.key2] = &node{
   115  		value:   v,
   116  		deleted: false,
   117  	}
   118  	return nil
   119  }
   120  
   121  // Evict deletes a record from cache
   122  func (c *kvCache) Evict(key *kvCacheKey) {
   123  	if _, ok := c.cache[key.key1]; !ok {
   124  		c.cache[key.key1] = make(map[string]*node)
   125  	}
   126  	c.cache[key.key1][key.key2] = &node{
   127  		value:   nil,
   128  		deleted: true,
   129  	}
   130  }
   131  
   132  // Clear clear the cache
   133  func (c *kvCache) Clear() {
   134  	c.cache = make(map[string]map[string]*node)
   135  }
   136  
   137  func (c *kvCache) Append(caches ...KVStoreCache) error {
   138  	// c should be written in order
   139  	for _, cc := range caches {
   140  		cc, ok := cc.(*kvCache)
   141  		if !ok {
   142  			return ErrUnexpectedType
   143  		}
   144  		for key1, ns := range cc.cache {
   145  			if _, ok := c.cache[key1]; !ok {
   146  				c.cache[key1] = make(map[string]*node)
   147  			}
   148  			for key2, node := range ns {
   149  				c.cache[key1][key2] = node
   150  			}
   151  		}
   152  	}
   153  	return nil
   154  }