github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/forensics/storage/kvcache.go (about)

     1  package storage
     2  
     3  import (
     4  	"bytes"
     5  	"sort"
     6  	"sync"
     7  
     8  	"github.com/hyperledger/burrow/storage"
     9  )
    10  
    11  type KVCache struct {
    12  	sync.RWMutex
    13  	cache map[string]valueInfo
    14  	// Store a sortable slice of keys to avoid always hitting
    15  	keys byteSlices
    16  }
    17  
    18  type byteSlices [][]byte
    19  
    20  func (bss byteSlices) Len() int {
    21  	return len(bss)
    22  }
    23  
    24  func (bss byteSlices) Less(i, j int) bool {
    25  	return bytes.Compare(bss[i], bss[j]) == -1
    26  }
    27  
    28  func (bss byteSlices) Swap(i, j int) {
    29  	bss[i], bss[j] = bss[j], bss[i]
    30  }
    31  
    32  type valueInfo struct {
    33  	value   []byte
    34  	deleted bool
    35  }
    36  
    37  // Creates an in-memory cache wrapping a map that stores the provided tombstone value for deleted keys
    38  func NewKVCache() *KVCache {
    39  	return &KVCache{
    40  		cache: make(map[string]valueInfo),
    41  	}
    42  }
    43  
    44  func (kvc *KVCache) Info(key []byte) (value []byte, deleted bool) {
    45  	kvc.RLock()
    46  	defer kvc.RUnlock()
    47  	vi := kvc.cache[string(key)]
    48  	return vi.value, vi.deleted
    49  }
    50  
    51  func (kvc *KVCache) Get(key []byte) []byte {
    52  	kvc.RLock()
    53  	defer kvc.RUnlock()
    54  	return kvc.cache[string(key)].value
    55  }
    56  
    57  func (kvc *KVCache) Has(key []byte) bool {
    58  	kvc.RLock()
    59  	defer kvc.RUnlock()
    60  	vi, ok := kvc.cache[string(key)]
    61  	return ok && !vi.deleted
    62  }
    63  
    64  func (kvc *KVCache) Set(key, value []byte) {
    65  	kvc.Lock()
    66  	defer kvc.Unlock()
    67  	skey := string(key)
    68  	vi, ok := kvc.cache[skey]
    69  	if !ok {
    70  		// first Set/Delete
    71  		kvc.keys = append(kvc.keys, key)
    72  		// This slows down write quite a lot but does give faster repeated iterations
    73  		// kvc.keys = insertKey(kvc.keys, key)
    74  	}
    75  	vi.deleted = false
    76  	vi.value = value
    77  	kvc.cache[skey] = vi
    78  }
    79  
    80  func (kvc *KVCache) Delete(key []byte) {
    81  	kvc.Lock()
    82  	defer kvc.Unlock()
    83  	skey := string(key)
    84  	vi, ok := kvc.cache[skey]
    85  	if !ok {
    86  		// first Set/Delete
    87  		kvc.keys = append(kvc.keys, key)
    88  		// This slows down write quite a lot but does give faster repeated iterations
    89  		// kvc.keys = insertKey(kvc.keys, key)
    90  	}
    91  	vi.deleted = true
    92  	vi.value = nil
    93  	kvc.cache[skey] = vi
    94  }
    95  
    96  func (kvc *KVCache) Iterator(low, high []byte) storage.KVIterator {
    97  	kvc.RLock()
    98  	defer kvc.RUnlock()
    99  	low, high = storage.NormaliseDomain(low, high)
   100  	return kvc.newIterator(low, high, false)
   101  }
   102  
   103  func (kvc *KVCache) ReverseIterator(low, high []byte) storage.KVIterator {
   104  	kvc.RLock()
   105  	defer kvc.RUnlock()
   106  	low, high = storage.NormaliseDomain(low, high)
   107  	return kvc.newIterator(low, high, true)
   108  }
   109  
   110  // Writes contents of cache to backend without flushing the cache
   111  func (kvc *KVCache) WriteTo(writer storage.KVWriter) {
   112  	kvc.Lock()
   113  	defer kvc.Unlock()
   114  	for k, vi := range kvc.cache {
   115  		kb := []byte(k)
   116  		if vi.deleted {
   117  			writer.Delete(kb)
   118  		} else {
   119  			writer.Set(kb, vi.value)
   120  		}
   121  	}
   122  }
   123  
   124  func (kvc *KVCache) Reset() {
   125  	kvc.Lock()
   126  	defer kvc.Unlock()
   127  	kvc.cache = make(map[string]valueInfo)
   128  }
   129  
   130  func (kvc *KVCache) sortedKeysInDomain(low, high []byte) [][]byte {
   131  	// Sort keys (which may be partially sorted if we have iterated before)
   132  	sort.Sort(kvc.keys)
   133  	sortedKeys := kvc.keys
   134  	// Attempt to seek to the first key in the range
   135  	startIndex := len(kvc.keys)
   136  	for i, key := range sortedKeys {
   137  		// !(key < start) => key >= start then include (inclusive start)
   138  		if storage.CompareKeys(key, low) != -1 {
   139  			startIndex = i
   140  			break
   141  		}
   142  	}
   143  	// Reslice to beginning of range or end if not found
   144  	sortedKeys = sortedKeys[startIndex:]
   145  	for i, key := range sortedKeys {
   146  		// !(key < end) => key >= end then exclude (exclusive end)
   147  		if storage.CompareKeys(key, high) != -1 {
   148  			sortedKeys = sortedKeys[:i]
   149  			break
   150  		}
   151  	}
   152  	return sortedKeys
   153  }
   154  
   155  func (kvc *KVCache) newIterator(start, end []byte, reverse bool) *KVCacheIterator {
   156  	keys := kvc.sortedKeysInDomain(start, end)
   157  	kvi := &KVCacheIterator{
   158  		start:   start,
   159  		end:     end,
   160  		keys:    keys,
   161  		cache:   kvc.cache,
   162  		reverse: reverse,
   163  	}
   164  	return kvi
   165  }
   166  
   167  type KVCacheIterator struct {
   168  	cache    map[string]valueInfo
   169  	start    []byte
   170  	end      []byte
   171  	keys     [][]byte
   172  	keyIndex int
   173  	reverse  bool
   174  }
   175  
   176  func (kvi *KVCacheIterator) Domain() ([]byte, []byte) {
   177  	return kvi.start, kvi.end
   178  }
   179  
   180  func (kvi *KVCacheIterator) Info() (key, value []byte, deleted bool) {
   181  	key = kvi.keys[kvi.sliceIndex()]
   182  	vi := kvi.cache[string(key)]
   183  	return key, vi.value, vi.deleted
   184  }
   185  
   186  func (kvi *KVCacheIterator) Key() []byte {
   187  	return []byte(kvi.keys[kvi.sliceIndex()])
   188  }
   189  
   190  func (kvi *KVCacheIterator) Value() []byte {
   191  	return kvi.cache[string(kvi.keys[kvi.sliceIndex()])].value
   192  }
   193  
   194  func (kvi *KVCacheIterator) Next() {
   195  	if !kvi.Valid() {
   196  		panic("KVCacheIterator.Next() called on invalid iterator")
   197  	}
   198  	kvi.keyIndex++
   199  }
   200  
   201  func (kvi *KVCacheIterator) Valid() bool {
   202  	return kvi.keyIndex < len(kvi.keys)
   203  }
   204  
   205  func (kvi *KVCacheIterator) Close() error {
   206  	return nil
   207  }
   208  
   209  func (kvi *KVCacheIterator) Error() error { return nil }
   210  
   211  func (kvi *KVCacheIterator) sliceIndex() int {
   212  	if kvi.reverse {
   213  		//reflect
   214  		return len(kvi.keys) - 1 - kvi.keyIndex
   215  	}
   216  	return kvi.keyIndex
   217  }