github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/txmgmt/statedb/statecouchdb/cache.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package statecouchdb 8 9 import ( 10 "github.com/VictoriaMetrics/fastcache" 11 "github.com/golang/protobuf/proto" 12 ) 13 14 var keySep = []byte{0x00} 15 16 // cache holds both the system and user cache 17 type cache struct { 18 sysCache *fastcache.Cache 19 usrCache *fastcache.Cache 20 sysNamespaces []string 21 } 22 23 // newCache creates a Cache. The cache consists of both system state cache (for lscc, _lifecycle) 24 // and user state cache (for all user deployed chaincodes). The size of the 25 // system state cache is 64 MB, by default. The size of the user state cache, in terms of MB, is 26 // specified via usrCacheSize parameter. Note that the maximum memory consumption of fastcache 27 // would be in the multiples of 32 MB (due to 512 buckets & an equal number of 64 KB chunks per bucket). 28 // If the usrCacheSizeMBs is not a multiple of 32 MB, the fastcache would round the size 29 // to the next multiple of 32 MB. 30 func newCache(usrCacheSizeMBs int, sysNamespaces []string) *cache { 31 cache := &cache{} 32 // By default, 64 MB is allocated for the system cache 33 cache.sysCache = fastcache.New(64 * 1024 * 1024) 34 cache.sysNamespaces = sysNamespaces 35 36 // User passed size is used to allocate memory for the user cache 37 if usrCacheSizeMBs <= 0 { 38 return cache 39 } 40 cache.usrCache = fastcache.New(usrCacheSizeMBs * 1024 * 1024) 41 return cache 42 } 43 44 // enabled returns true if the cache is enabled for a given namespace. 45 // Namespace can be of two types: system namespace (such as lscc) and user 46 // namespace (all user's chaincode states). 47 func (c *cache) enabled(namespace string) bool { 48 for _, ns := range c.sysNamespaces { 49 if namespace == ns { 50 return true 51 } 52 } 53 return c.usrCache != nil 54 } 55 56 // getState returns the value for a given namespace and key from 57 // a cache associated with the chainID. 58 func (c *cache) getState(chainID, namespace, key string) (*CacheValue, error) { 59 cache := c.getCache(namespace) 60 if cache == nil { 61 return nil, nil 62 } 63 64 cacheKey := constructCacheKey(chainID, namespace, key) 65 66 if !cache.Has(cacheKey) { 67 return nil, nil 68 } 69 cacheValue := &CacheValue{} 70 valBytes := cache.Get(nil, cacheKey) 71 if err := proto.Unmarshal(valBytes, cacheValue); err != nil { 72 return nil, err 73 } 74 return cacheValue, nil 75 } 76 77 // PutState stores a given value in a cache associated with the chainID. 78 func (c *cache) putState(chainID, namespace, key string, cacheValue *CacheValue) error { 79 cache := c.getCache(namespace) 80 if cache == nil { 81 return nil 82 } 83 84 cacheKey := constructCacheKey(chainID, namespace, key) 85 valBytes, err := proto.Marshal(cacheValue) 86 if err != nil { 87 return err 88 } 89 90 if cache.Has(cacheKey) { 91 cache.Del(cacheKey) 92 } 93 94 cache.Set(cacheKey, valBytes) 95 return nil 96 } 97 98 // CacheUpdates is a map from a namespace to a set of cache KV updates 99 type cacheUpdates map[string]cacheKVs 100 101 // CacheKVs is a map from a key to a cache value 102 type cacheKVs map[string]*CacheValue 103 104 // Add adds the given cacheKVs to the CacheUpdates 105 func (u cacheUpdates) add(namespace string, ckvs cacheKVs) { 106 nsu, ok := u[namespace] 107 if !ok { 108 nsu = cacheKVs{} 109 u[namespace] = nsu 110 } 111 112 for k, v := range ckvs { 113 nsu[k] = v 114 } 115 } 116 117 // UpdateStates updates only the existing entries in the cache associated with 118 // the chainID. 119 func (c *cache) UpdateStates(chainID string, updates cacheUpdates) error { 120 for ns, kvs := range updates { 121 cache := c.getCache(ns) 122 if cache == nil { 123 continue 124 } 125 126 for key, newVal := range kvs { 127 cacheKey := constructCacheKey(chainID, ns, key) 128 if newVal == nil { 129 cache.Del(cacheKey) 130 continue 131 } 132 if cache.Has(cacheKey) { 133 newValBytes, err := proto.Marshal(newVal) 134 if err != nil { 135 return err 136 } 137 cache.Del(cacheKey) 138 cache.Set(cacheKey, newValBytes) 139 } 140 } 141 } 142 return nil 143 } 144 145 // Reset removes all the items from the cache. 146 func (c *cache) Reset() { 147 c.sysCache.Reset() 148 if c.usrCache != nil { 149 c.usrCache.Reset() 150 } 151 } 152 153 func (c *cache) getCache(namespace string) *fastcache.Cache { 154 for _, ns := range c.sysNamespaces { 155 if namespace == ns { 156 return c.sysCache 157 } 158 } 159 return c.usrCache 160 } 161 162 func constructCacheKey(chainID, namespace, key string) []byte { 163 var cacheKey []byte 164 cacheKey = append(cacheKey, []byte(chainID)...) 165 cacheKey = append(cacheKey, keySep...) 166 cacheKey = append(cacheKey, []byte(namespace)...) 167 cacheKey = append(cacheKey, keySep...) 168 return append(cacheKey, []byte(key)...) 169 }