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  }