github.com/klaytn/klaytn@v1.12.1/storage/statedb/cache_hybrid.go (about) 1 // Copyright 2020 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package statedb 18 19 import "github.com/go-redis/redis/v7" 20 21 func newHybridCache(config *TrieNodeCacheConfig) (TrieNodeCache, error) { 22 redis, err := newRedisCache(config) 23 if err != nil { 24 return nil, err 25 } 26 27 return &HybridCache{ 28 local: newFastCache(config), 29 remote: redis, 30 }, nil 31 } 32 33 // HybridCache integrates two kinds of caches: local, remote. 34 // Local cache uses memory of the local machine and remote cache uses memory of the remote machine. 35 // When it sets data to both caches, only remote cache is set asynchronously 36 type HybridCache struct { 37 local TrieNodeCache 38 remote *RedisCache 39 } 40 41 func (cache *HybridCache) Local() TrieNodeCache { 42 return cache.local 43 } 44 45 func (cache *HybridCache) Remote() *RedisCache { 46 return cache.remote 47 } 48 49 // Set writes data to local cache synchronously and to remote cache asynchronously. 50 func (cache *HybridCache) Set(k, v []byte) { 51 cache.local.Set(k, v) 52 cache.remote.SetAsync(k, v) 53 } 54 55 func (cache *HybridCache) Get(k []byte) []byte { 56 ret := cache.local.Get(k) 57 if ret != nil { 58 return ret 59 } 60 ret = cache.remote.Get(k) 61 if ret != nil { 62 cache.local.Set(k, ret) 63 } 64 return ret 65 } 66 67 func (cache *HybridCache) Has(k []byte) ([]byte, bool) { 68 ret, has := cache.local.Has(k) 69 if has { 70 return ret, has 71 } 72 return cache.remote.Has(k) 73 } 74 75 func (cache *HybridCache) UpdateStats() interface{} { 76 type stats struct { 77 local interface{} 78 remote interface{} 79 } 80 return stats{cache.local.UpdateStats(), cache.remote.UpdateStats()} 81 } 82 83 func (cache *HybridCache) SaveToFile(filePath string, concurrency int) error { 84 if err := cache.local.SaveToFile(filePath, concurrency); err != nil { 85 logger.Error("failed to save local cache to file", 86 "filePath", filePath, "concurrency", concurrency, "err", err) 87 return err 88 } 89 return nil 90 } 91 92 func (cache *HybridCache) PublishBlock(msg string) error { 93 return cache.remote.PublishBlock(msg) 94 } 95 96 func (cache *HybridCache) SubscribeBlockCh() <-chan *redis.Message { 97 return cache.remote.SubscribeBlockCh() 98 } 99 100 func (cache *HybridCache) UnsubscribeBlock() error { 101 return cache.remote.UnsubscribeBlock() 102 } 103 104 func (cache *HybridCache) Close() error { 105 err := cache.local.Close() 106 if err != nil { 107 return err 108 } 109 return cache.remote.Close() 110 }