diff --git a/swarm/storage/memstore.go b/swarm/storage/memstore.go deleted file mode 100644 index edaa3d217f..0000000000 --- a/swarm/storage/memstore.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -// memory storage layer for the package blockhash - -package storage - -import ( - "bytes" - "fmt" - "sync" - - "github.com/ethereum/go-ethereum/metrics" -) - -//metrics variables -var ( - memstorePutCounter = metrics.NewRegisteredCounter("storage.db.memstore.put.count", nil) - memstoreRemoveCounter = metrics.NewRegisteredCounter("storage.db.memstore.rm.count", nil) -) - -const ( - memTreeLW = 2 // log2(subtree count) of the subtrees - memTreeFLW = 14 // log2(subtree count) of the root layer - dbForceUpdateAccessCnt = 1000 - defaultCacheCapacity = 5000 -) - -//type MemStore struct { -//memtree *memTree -//entryCnt, capacity uint // stored entries -//accessCnt uint64 // access counter; oldest is thrown away when full -//dbAccessCnt uint64 -//ldbStore *LDBStore -//lock sync.Mutex -//} - -/* -a hash prefix subtree containing subtrees or one storage entry (but never both) - -- access[0] stores the smallest (oldest) access count value in this subtree -- if it contains more subtrees and its subtree count is at least 4, access[1:2] - stores the smallest access count in the first and second halves of subtrees - (so that access[0] = min(access[1], access[2]) -- likewise, if subtree count is at least 8, - access[1] = min(access[3], access[4]) - access[2] = min(access[5], access[6]) - (access[] is a binary tree inside the multi-bit leveled hash tree) -*/ - -//func NewMemStore(d *LDBStore, capacity uint) (m *MemStore) { -//m = &MemStore{} -//m.memtree = newMemTree(memTreeFLW, nil, 0) -//m.ldbStore = d -//m.setCapacity(capacity) -//return -//} - -//type memTree struct { -//subtree []*memTree -//parent *memTree -//parentIdx uint - -//bits uint // log2(subtree count) -//width uint // subtree count - -//entry *Chunk // if subtrees are present, entry should be nil -//lastDBaccess uint64 -//access []uint64 -//} - -//func newMemTree(b uint, parent *memTree, pidx uint) (node *memTree) { -//node = new(memTree) -//node.bits = b -//node.width = 1 << b -//node.subtree = make([]*memTree, node.width) -//node.access = make([]uint64, node.width-1) -//node.parent = parent -//node.parentIdx = pidx -//if parent != nil { -//parent.subtree[pidx] = node -//} - -//return node -//} - -//func (node *memTree) updateAccess(a uint64) { -//aidx := uint(0) -//var aa uint64 -//oa := node.access[0] -//for node.access[aidx] == oa { -//node.access[aidx] = a -//if aidx > 0 { -//aa = node.access[((aidx-1)^1)+1] -//aidx = (aidx - 1) >> 1 -//} else { -//pidx := node.parentIdx -//node = node.parent -//if node == nil { -//return -//} -//nn := node.subtree[pidx^1] -//if nn != nil { -//aa = nn.access[0] -//} else { -//aa = 0 -//} -//aidx = (node.width + pidx - 2) >> 1 -//} - -//if (aa != 0) && (aa < a) { -//a = aa -//} -//} -//} - -//func (s *MemStore) setCapacity(c uint) { -//s.lock.Lock() -//defer s.lock.Unlock() - -//for c < s.entryCnt { -//s.removeOldest() -//} -//s.capacity = c -//} - -//func (s *MemStore) Counter() uint { -//return s.entryCnt -//} - -//// entry (not its copy) is going to be in MemStore -//func (s *MemStore) Put(entry *Chunk) { -//log.Trace("memstore.put", "key", entry.Key) -//if s.capacity == 0 { -//return -//} - -//s.lock.Lock() -//defer s.lock.Unlock() - -//if s.entryCnt >= s.capacity { -//s.removeOldest() -//} - -//s.accessCnt++ - -//memstorePutCounter.Inc(1) - -//node := s.memtree -//bitpos := uint(0) -//for node.entry == nil { -//l := entry.Key.bits(bitpos, node.bits) -//st := node.subtree[l] -//if st == nil { -//st = newMemTree(memTreeLW, node, l) -//bitpos += node.bits -//node = st -//break -//} -//bitpos += node.bits -//node = st -//} - -//if node.entry != nil { - -//if node.entry.Key.isEqual(entry.Key) { -//node.updateAccess(s.accessCnt) -//if entry.SData == nil { -//entry.Size = node.entry.Size -//entry.SData = node.entry.SData -//} -//if entry.ReqC == nil { -//entry.ReqC = node.entry.ReqC -//} -//entry.C = node.entry.C -//node.entry = entry -//return -//} - -//for node.entry != nil { - -//l := node.entry.Key.bits(bitpos, node.bits) -//st := node.subtree[l] -//if st == nil { -//st = newMemTree(memTreeLW, node, l) -//} -//st.entry = node.entry -//node.entry = nil -//st.updateAccess(node.access[0]) - -//l = entry.Key.bits(bitpos, node.bits) -//st = node.subtree[l] -//if st == nil { -//st = newMemTree(memTreeLW, node, l) -//} -//bitpos += node.bits -//node = st - -//} -//} - -//node.entry = entry -//node.lastDBaccess = s.dbAccessCnt -//node.updateAccess(s.accessCnt) -//s.entryCnt++ -//} - -//func (s *MemStore) Get(hash Key) (chunk *Chunk, err error) { -//log.Trace("memstore.get", "key", hash) -//s.lock.Lock() -//defer s.lock.Unlock() - -//node := s.memtree -//bitpos := uint(0) -//for node.entry == nil { -//l := hash.bits(bitpos, node.bits) -//st := node.subtree[l] -//if st == nil { -//log.Trace("memstore.get ErrChunkNotFound", "key", hash) -//return nil, ErrChunkNotFound -//} -//bitpos += node.bits -//node = st -//} - -//if node.entry.Key.isEqual(hash) { -//s.accessCnt++ -//node.updateAccess(s.accessCnt) -//chunk = node.entry -//if s.dbAccessCnt-node.lastDBaccess > dbForceUpdateAccessCnt { -//s.dbAccessCnt++ -//node.lastDBaccess = s.dbAccessCnt -//if s.ldbStore != nil { -//s.ldbStore.updateAccessCnt(hash) -//} -//} -//} else { -//err = ErrChunkNotFound -//} - -//log.Trace("memstore.get return", "key", hash, "chunk", chunk, "err", err) -//return -//} - -//func (s *MemStore) removeOldest() { -//defer metrics.GetOrRegisterResettingTimer("memstore.purge", metrics.DefaultRegistry).UpdateSince(time.Now()) - -//node := s.memtree -//log.Warn("purge memstore") -//for node.entry == nil { - -//aidx := uint(0) -//av := node.access[aidx] - -//for aidx < node.width/2-1 { -//if av == node.access[aidx*2+1] { -//node.access[aidx] = node.access[aidx*2+2] -//aidx = aidx*2 + 1 -//} else if av == node.access[aidx*2+2] { -//node.access[aidx] = node.access[aidx*2+1] -//aidx = aidx*2 + 2 -//} else { -//panic(nil) -//} -//} -//pidx := aidx*2 + 2 - node.width -//if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) { -//if node.subtree[pidx+1] != nil { -//node.access[aidx] = node.subtree[pidx+1].access[0] -//} else { -//node.access[aidx] = 0 -//} -//} else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) { -//if node.subtree[pidx] != nil { -//node.access[aidx] = node.subtree[pidx].access[0] -//} else { -//node.access[aidx] = 0 -//} -//pidx++ -//} else { -//panic(nil) -//} - -////fmt.Println(pidx) -//node = node.subtree[pidx] - -//} - -//if node.entry.ReqC == nil { -//log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log())) -//<-node.entry.dbStoredC -//log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log())) - -//memstoreRemoveCounter.Inc(1) -//node.entry = nil -//s.entryCnt-- -//} else { -//return -//} - -//node.access[0] = 0 - -////--- - -//aidx := uint(0) -//for { -//aa := node.access[aidx] -//if aidx > 0 { -//aidx = (aidx - 1) >> 1 -//} else { -//pidx := node.parentIdx -//node = node.parent -//if node == nil { -//return -//} -//aidx = (node.width + pidx - 2) >> 1 -//} -//if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) { -//node.access[aidx] = aa -//} -//} -//} - -type MemStore struct { - m map[string]*Chunk - mu sync.RWMutex -} - -func NewMemStore(d *LDBStore, capacity uint) (m *MemStore) { - return &MemStore{ - m: make(map[string]*Chunk), - } -} - -func (m *MemStore) Get(key Key) (*Chunk, error) { - m.mu.RLock() - defer m.mu.RUnlock() - c, ok := m.m[string(key[:])] - if !ok { - return nil, ErrChunkNotFound - } - if !bytes.Equal(c.Key, key) { - panic(fmt.Errorf("MemStore.Get: chunk key %s != req key %s", c.Key.Hex(), key.Hex())) - } - return c, nil -} - -func (m *MemStore) Put(c *Chunk) { - m.mu.Lock() - defer m.mu.Unlock() - m.m[string(c.Key[:])] = c -} - -func (m *MemStore) setCapacity(n int) { - -} - -// Close memstore -func (s *MemStore) Close() {} diff --git a/swarm/storage/memstore_lrucache.go b/swarm/storage/memstore_lrucache.go new file mode 100644 index 0000000000..74b6376571 --- /dev/null +++ b/swarm/storage/memstore_lrucache.go @@ -0,0 +1,74 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// memory storage layer for the package blockhash + +package storage + +import ( + "bytes" + "fmt" + + lru "github.com/hashicorp/golang-lru" +) + +const ( + defaultCacheCapacity = 5000 +) + +type MemStore struct { + //cache *lru.ARCCache + cache *lru.Cache +} + +func NewMemStore(_ *LDBStore, capacity uint) (m *MemStore) { + onEvicted := func(key interface{}, value interface{}) { + v := value.(*Chunk) + <-v.dbStoredC + } + c, err := lru.NewWithEvict(int(capacity), onEvicted) + if err != nil { + panic(err) + } + + return &MemStore{ + //cache: lru.NewARC(capacity), + cache: c, + } +} + +func (m *MemStore) Get(key Key) (*Chunk, error) { + c, ok := m.cache.Get(string(key)) + if !ok { + return nil, ErrChunkNotFound + } + chunk := c.(*Chunk) + if !bytes.Equal(chunk.Key, key) { + panic(fmt.Errorf("MemStore.Get: chunk key %s != req key %s", chunk.Key.Hex(), key.Hex())) + } + return chunk, nil +} + +func (m *MemStore) Put(c *Chunk) { + m.cache.Add(string(c.Key), c) +} + +func (m *MemStore) setCapacity(n int) { + //no-op +} + +// Close memstore +func (s *MemStore) Close() {} diff --git a/swarm/storage/memstore2_test.go b/swarm/storage/memstore_lrucache_test.go similarity index 100% rename from swarm/storage/memstore2_test.go rename to swarm/storage/memstore_lrucache_test.go diff --git a/swarm/storage/memstore_map.god b/swarm/storage/memstore_map.god new file mode 100644 index 0000000000..c2f2855268 --- /dev/null +++ b/swarm/storage/memstore_map.god @@ -0,0 +1,77 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// memory storage layer for the package blockhash + +package storage + +import ( + "bytes" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/metrics" +) + +//metrics variables +var ( + memstorePutCounter = metrics.NewRegisteredCounter("storage.db.memstore.put.count", nil) + memstoreRemoveCounter = metrics.NewRegisteredCounter("storage.db.memstore.rm.count", nil) +) + +const ( + memTreeLW = 2 // log2(subtree count) of the subtrees + memTreeFLW = 14 // log2(subtree count) of the root layer + dbForceUpdateAccessCnt = 1000 + defaultCacheCapacity = 5000 +) + +type MemStore struct { + m map[string]*Chunk + mu sync.RWMutex +} + +func NewMemStore(d *LDBStore, capacity uint) (m *MemStore) { + return &MemStore{ + m: make(map[string]*Chunk), + } +} + +func (m *MemStore) Get(key Key) (*Chunk, error) { + m.mu.RLock() + defer m.mu.RUnlock() + c, ok := m.m[string(key[:])] + if !ok { + return nil, ErrChunkNotFound + } + if !bytes.Equal(c.Key, key) { + panic(fmt.Errorf("MemStore.Get: chunk key %s != req key %s", c.Key.Hex(), key.Hex())) + } + return c, nil +} + +func (m *MemStore) Put(c *Chunk) { + m.mu.Lock() + defer m.mu.Unlock() + m.m[string(c.Key[:])] = c +} + +func (m *MemStore) setCapacity(n int) { + +} + +// Close memstore +func (s *MemStore) Close() {} diff --git a/swarm/storage/memstore_tree.god b/swarm/storage/memstore_tree.god new file mode 100644 index 0000000000..3e5c025daa --- /dev/null +++ b/swarm/storage/memstore_tree.god @@ -0,0 +1,373 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// memory storage layer for the package blockhash + +package storage + +import ( + "fmt" + "sync" + "time" + + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/metrics" +) + +//metrics variables +var ( + memstorePutCounter = metrics.NewRegisteredCounter("storage.db.memstore.put.count", nil) + memstoreRemoveCounter = metrics.NewRegisteredCounter("storage.db.memstore.rm.count", nil) +) + +const ( + memTreeLW = 2 // log2(subtree count) of the subtrees + memTreeFLW = 14 // log2(subtree count) of the root layer + dbForceUpdateAccessCnt = 1000 + defaultCacheCapacity = 5000 +) + +type MemStore struct { + memtree *memTree + entryCnt, capacity uint // stored entries + accessCnt uint64 // access counter; oldest is thrown away when full + dbAccessCnt uint64 + ldbStore *LDBStore + lock sync.Mutex +} + +/* +a hash prefix subtree containing subtrees or one storage entry (but never both) + +- access[0] stores the smallest (oldest) access count value in this subtree +- if it contains more subtrees and its subtree count is at least 4, access[1:2] + stores the smallest access count in the first and second halves of subtrees + (so that access[0] = min(access[1], access[2]) +- likewise, if subtree count is at least 8, + access[1] = min(access[3], access[4]) + access[2] = min(access[5], access[6]) + (access[] is a binary tree inside the multi-bit leveled hash tree) +*/ + +func NewMemStore(d *LDBStore, capacity uint) (m *MemStore) { + m = &MemStore{} + m.memtree = newMemTree(memTreeFLW, nil, 0) + m.ldbStore = d + m.setCapacity(capacity) + return +} + +type memTree struct { + subtree []*memTree + parent *memTree + parentIdx uint + + bits uint // log2(subtree count) + width uint // subtree count + + entry *Chunk // if subtrees are present, entry should be nil + lastDBaccess uint64 + access []uint64 +} + +func newMemTree(b uint, parent *memTree, pidx uint) (node *memTree) { + node = new(memTree) + node.bits = b + node.width = 1 << b + node.subtree = make([]*memTree, node.width) + node.access = make([]uint64, node.width-1) + node.parent = parent + node.parentIdx = pidx + if parent != nil { + parent.subtree[pidx] = node + } + + return node +} + +func (node *memTree) updateAccess(a uint64) { + aidx := uint(0) + var aa uint64 + oa := node.access[0] + for node.access[aidx] == oa { + node.access[aidx] = a + if aidx > 0 { + aa = node.access[((aidx-1)^1)+1] + aidx = (aidx - 1) >> 1 + } else { + pidx := node.parentIdx + node = node.parent + if node == nil { + return + } + nn := node.subtree[pidx^1] + if nn != nil { + aa = nn.access[0] + } else { + aa = 0 + } + aidx = (node.width + pidx - 2) >> 1 + } + + if (aa != 0) && (aa < a) { + a = aa + } + } +} + +func (s *MemStore) setCapacity(c uint) { + s.lock.Lock() + defer s.lock.Unlock() + + for c < s.entryCnt { + s.removeOldest() + } + s.capacity = c +} + +func (s *MemStore) Counter() uint { + return s.entryCnt +} + +// entry (not its copy) is going to be in MemStore +func (s *MemStore) Put(entry *Chunk) { + log.Trace("memstore.put", "key", entry.Key) + if s.capacity == 0 { + return + } + + s.lock.Lock() + defer s.lock.Unlock() + + if s.entryCnt >= s.capacity { + s.removeOldest() + } + + s.accessCnt++ + + memstorePutCounter.Inc(1) + + node := s.memtree + bitpos := uint(0) + for node.entry == nil { + l := entry.Key.bits(bitpos, node.bits) + st := node.subtree[l] + if st == nil { + st = newMemTree(memTreeLW, node, l) + bitpos += node.bits + node = st + break + } + bitpos += node.bits + node = st + } + + if node.entry != nil { + + if node.entry.Key.isEqual(entry.Key) { + node.updateAccess(s.accessCnt) + if entry.SData == nil { + entry.Size = node.entry.Size + entry.SData = node.entry.SData + } + if entry.ReqC == nil { + entry.ReqC = node.entry.ReqC + } + entry.C = node.entry.C + node.entry = entry + return + } + + for node.entry != nil { + + l := node.entry.Key.bits(bitpos, node.bits) + st := node.subtree[l] + if st == nil { + st = newMemTree(memTreeLW, node, l) + } + st.entry = node.entry + node.entry = nil + st.updateAccess(node.access[0]) + + l = entry.Key.bits(bitpos, node.bits) + st = node.subtree[l] + if st == nil { + st = newMemTree(memTreeLW, node, l) + } + bitpos += node.bits + node = st + + } + } + + node.entry = entry + node.lastDBaccess = s.dbAccessCnt + node.updateAccess(s.accessCnt) + s.entryCnt++ +} + +func (s *MemStore) Get(hash Key) (chunk *Chunk, err error) { + log.Trace("memstore.get", "key", hash) + s.lock.Lock() + defer s.lock.Unlock() + + node := s.memtree + bitpos := uint(0) + for node.entry == nil { + l := hash.bits(bitpos, node.bits) + st := node.subtree[l] + if st == nil { + log.Trace("memstore.get ErrChunkNotFound", "key", hash) + return nil, ErrChunkNotFound + } + bitpos += node.bits + node = st + } + + if node.entry.Key.isEqual(hash) { + s.accessCnt++ + node.updateAccess(s.accessCnt) + chunk = node.entry + if s.dbAccessCnt-node.lastDBaccess > dbForceUpdateAccessCnt { + s.dbAccessCnt++ + node.lastDBaccess = s.dbAccessCnt + if s.ldbStore != nil { + s.ldbStore.updateAccessCnt(hash) + } + } + } else { + err = ErrChunkNotFound + } + + log.Trace("memstore.get return", "key", hash, "chunk", chunk, "err", err) + return +} + +func (s *MemStore) removeOldest() { + defer metrics.GetOrRegisterResettingTimer("memstore.purge", metrics.DefaultRegistry).UpdateSince(time.Now()) + + node := s.memtree + log.Warn("purge memstore") + for node.entry == nil { + + aidx := uint(0) + av := node.access[aidx] + + for aidx < node.width/2-1 { + if av == node.access[aidx*2+1] { + node.access[aidx] = node.access[aidx*2+2] + aidx = aidx*2 + 1 + } else if av == node.access[aidx*2+2] { + node.access[aidx] = node.access[aidx*2+1] + aidx = aidx*2 + 2 + } else { + panic(nil) + } + } + pidx := aidx*2 + 2 - node.width + if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) { + if node.subtree[pidx+1] != nil { + node.access[aidx] = node.subtree[pidx+1].access[0] + } else { + node.access[aidx] = 0 + } + } else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) { + if node.subtree[pidx] != nil { + node.access[aidx] = node.subtree[pidx].access[0] + } else { + node.access[aidx] = 0 + } + pidx++ + } else { + panic(nil) + } + + //fmt.Println(pidx) + node = node.subtree[pidx] + + } + + if node.entry.ReqC == nil { + log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log())) + <-node.entry.dbStoredC + log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log())) + + memstoreRemoveCounter.Inc(1) + node.entry = nil + s.entryCnt-- + } else { + return + } + + node.access[0] = 0 + + //--- + + aidx := uint(0) + for { + aa := node.access[aidx] + if aidx > 0 { + aidx = (aidx - 1) >> 1 + } else { + pidx := node.parentIdx + node = node.parent + if node == nil { + return + } + aidx = (node.width + pidx - 2) >> 1 + } + if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) { + node.access[aidx] = aa + } + } +} + +// type MemStore struct { +// m map[string]*Chunk +// mu sync.RWMutex +// } + +// func NewMemStore(d *DbStore, capacity uint) (m *MemStore) { +// return &MemStore{ +// m: make(map[string]*Chunk), +// } +// } + +// func (m *MemStore) Get(key Key) (*Chunk, error) { +// m.mu.RLock() +// defer m.mu.RUnlock() +// c, ok := m.m[string(key[:])] +// if !ok { +// return nil, ErrNotFound +// } +// if !bytes.Equal(c.Key, key) { +// panic(fmt.Errorf("MemStore.Get: chunk key %s != req key %s", c.Key.Hex(), key.Hex())) +// } +// return c, nil +// } + +// func (m *MemStore) Put(c *Chunk) { +// m.mu.Lock() +// defer m.mu.Unlock() +// m.m[string(c.Key[:])] = c +// } + +// func (m *MemStore) setCapacity(n int) { + +// } + +// Close memstore +func (s *MemStore) Close() {}