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() {}