github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/cachekit/cache_example.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package cachekit 7 8 import ( 9 "github.com/insolar/vanilla/throw" 10 ) 11 12 type Key = uint64 13 type Value = string 14 15 const zeroValue = "" 16 17 /* 18 UintCache is an example/template implementation of a cache that uses the Core. 19 20 To create a new cache type - copy this file, rename struct, set Key and Value type aliases accordingly, then 21 set zeroValue constant in accordance with Value type. 22 23 24 */ 25 26 func NewUintCache(cs Strategy) *UintCache { 27 c := &UintCache{ 28 keys: map[Key]Index{}, 29 values: [][]uintEntry { make([]uintEntry, cs.AllocationPageSize()) }, 30 } 31 c.core = NewCore(cs, c.trimBatch) 32 33 return c 34 } 35 36 // UintCache is an example/template implementation of a cache that uses the Core. 37 type UintCache struct { 38 values [][]uintEntry 39 keys map[Key]Index 40 41 core Core 42 } 43 44 type uintEntry struct { 45 key Key 46 value Value 47 } 48 49 // Allocated returns a total number of cache entries allocated, but some of them may be unused. 50 // NB! Cache can only grow. 51 func (p *UintCache) Allocated() int { 52 return len(p.values) * cap(p.values[0]) 53 } 54 55 // Occupied returns a number of added / available cache entries. 56 func (p *UintCache) Occupied() int { 57 return len(p.keys) 58 } 59 60 // Put adds value with the given key. 61 // If key was already added, then cached value remains unchanged and the function returns (false). 62 // Access to the key is always updated. 63 func (p *UintCache) Put(key Key, value Value) bool { 64 idx, ok := p.keys[key] 65 if ok { 66 p.core.Touch(idx) 67 return false 68 } 69 idx, _ = p.core.Add() 70 p.keys[key] = idx 71 p.putEntry(idx, uintEntry{key, value}) 72 return true 73 } 74 75 // Replace adds or replaces value with the given key. If key was already added, then cached value is updated and the function returns (false). 76 // Access to the key is always updated. 77 func (p *UintCache) Replace(key Key, value Value) bool { 78 idx, ok := p.keys[key] 79 if ok { 80 p.core.Touch(idx) 81 p.putEntry(idx, uintEntry{key, value}) 82 return false 83 } 84 idx, _ = p.core.Add() 85 p.keys[key] = idx 86 p.putEntry(idx, uintEntry{key, value}) 87 return true 88 } 89 90 // Get returns value and presence flag for the given key. 91 // Access to the key is updated when key exists. 92 func (p *UintCache) Get(key Key) (Value, bool) { 93 idx, ok := p.keys[key] 94 if !ok { 95 return zeroValue, false 96 } 97 p.core.Touch(idx) 98 ce := p.getEntry(idx) 99 return ce.value, true 100 } 101 102 // Peek returns value and presence flag for the given key. 103 // Access to the key is not updated. 104 func (p *UintCache) Peek(key Key) (Value, bool) { 105 idx, ok := p.keys[key] 106 if !ok { 107 return zeroValue, false 108 } 109 ce := p.getEntry(idx) 110 return ce.value, true 111 } 112 113 // Contains returns (true) when the key is present. 114 // Access to the key is not updated. 115 func (p *UintCache) Contains(key Key) bool { 116 _, ok := p.keys[key] 117 return ok 118 } 119 120 // Delete removes key and zero out relevant value. Returns (false) when key wasn't present. 121 // Access to the key is not updated. Cache entry will become unavailable, but will only be freed after relevant expiry / eviction. 122 func (p *UintCache) Delete(key Key) bool { 123 idx, ok := p.keys[key] 124 if !ok { 125 return false 126 } 127 ce := p.getEntry(idx) 128 if ce.key != key { 129 panic(throw.IllegalState()) 130 } 131 p.core.Delete(idx) 132 delete(p.keys, ce.key) 133 *ce = uintEntry{} 134 return true 135 } 136 137 func (p *UintCache) putEntry(idx Index, entry uintEntry) { 138 pgSize := cap(p.values[0]) 139 pgN := idx / pgSize 140 141 if pgN == len(p.values) { 142 p.values = append(p.values, make([]uintEntry, pgSize)) 143 } 144 p.values[pgN][idx % pgSize] = entry 145 } 146 147 func (p *UintCache) getEntry(idx Index) *uintEntry { 148 pgSize := cap(p.values[0]) 149 return &p.values[idx / pgSize][idx % pgSize] 150 } 151 152 func (p *UintCache) trimBatch(trimmed []uint32) { 153 for _, idx := range trimmed { 154 ce := p.getEntry(Index(idx)) 155 delete(p.keys, ce.key) 156 *ce = uintEntry{} 157 } 158 } 159