github.com/gobitfly/go-ethereum@v1.8.12/swarm/storage/memstore.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // memory storage layer for the package blockhash 18 19 package storage 20 21 import ( 22 "sync" 23 24 lru "github.com/hashicorp/golang-lru" 25 ) 26 27 type MemStore struct { 28 cache *lru.Cache 29 requests *lru.Cache 30 mu sync.RWMutex 31 disabled bool 32 } 33 34 //NewMemStore is instantiating a MemStore cache. We are keeping a record of all outgoing requests for chunks, that 35 //should later be delivered by peer nodes, in the `requests` LRU cache. We are also keeping all frequently requested 36 //chunks in the `cache` LRU cache. 37 // 38 //`requests` LRU cache capacity should ideally never be reached, this is why for the time being it should be initialised 39 //with the same value as the LDBStore capacity. 40 func NewMemStore(params *StoreParams, _ *LDBStore) (m *MemStore) { 41 if params.CacheCapacity == 0 { 42 return &MemStore{ 43 disabled: true, 44 } 45 } 46 47 onEvicted := func(key interface{}, value interface{}) { 48 v := value.(*Chunk) 49 <-v.dbStoredC 50 } 51 c, err := lru.NewWithEvict(int(params.CacheCapacity), onEvicted) 52 if err != nil { 53 panic(err) 54 } 55 56 requestEvicted := func(key interface{}, value interface{}) { 57 // temporary remove of the error log, until we figure out the problem, as it is too spamy 58 //log.Error("evict called on outgoing request") 59 } 60 r, err := lru.NewWithEvict(int(params.ChunkRequestsCacheCapacity), requestEvicted) 61 if err != nil { 62 panic(err) 63 } 64 65 return &MemStore{ 66 cache: c, 67 requests: r, 68 } 69 } 70 71 func (m *MemStore) Get(addr Address) (*Chunk, error) { 72 if m.disabled { 73 return nil, ErrChunkNotFound 74 } 75 76 m.mu.RLock() 77 defer m.mu.RUnlock() 78 79 r, ok := m.requests.Get(string(addr)) 80 // it is a request 81 if ok { 82 return r.(*Chunk), nil 83 } 84 85 // it is not a request 86 c, ok := m.cache.Get(string(addr)) 87 if !ok { 88 return nil, ErrChunkNotFound 89 } 90 return c.(*Chunk), nil 91 } 92 93 func (m *MemStore) Put(c *Chunk) { 94 if m.disabled { 95 return 96 } 97 98 m.mu.Lock() 99 defer m.mu.Unlock() 100 101 // it is a request 102 if c.ReqC != nil { 103 select { 104 case <-c.ReqC: 105 if c.GetErrored() != nil { 106 m.requests.Remove(string(c.Addr)) 107 return 108 } 109 m.cache.Add(string(c.Addr), c) 110 m.requests.Remove(string(c.Addr)) 111 default: 112 m.requests.Add(string(c.Addr), c) 113 } 114 return 115 } 116 117 // it is not a request 118 m.cache.Add(string(c.Addr), c) 119 m.requests.Remove(string(c.Addr)) 120 } 121 122 func (m *MemStore) setCapacity(n int) { 123 if n <= 0 { 124 m.disabled = true 125 } else { 126 onEvicted := func(key interface{}, value interface{}) { 127 v := value.(*Chunk) 128 <-v.dbStoredC 129 } 130 c, err := lru.NewWithEvict(n, onEvicted) 131 if err != nil { 132 panic(err) 133 } 134 135 r, err := lru.New(defaultChunkRequestsCacheCapacity) 136 if err != nil { 137 panic(err) 138 } 139 140 m = &MemStore{ 141 cache: c, 142 requests: r, 143 } 144 } 145 } 146 147 func (s *MemStore) Close() {}