123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- package storage
- import (
- "fmt"
- "sync"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/metrics"
- )
- var (
- memstorePutCounter = metrics.NewRegisteredCounter("storage.db.memstore.put.count", nil)
- memstoreRemoveCounter = metrics.NewRegisteredCounter("storage.db.memstore.rm.count", nil)
- )
- const (
- memTreeLW = 2
- memTreeFLW = 14
- dbForceUpdateAccessCnt = 1000
- defaultCacheCapacity = 5000
- )
- type MemStore struct {
- memtree *memTree
- entryCnt, capacity uint
- accessCnt uint64
- dbAccessCnt uint64
- dbStore *DbStore
- lock sync.Mutex
- }
- func NewMemStore(d *DbStore, capacity uint) (m *MemStore) {
- m = &MemStore{}
- m.memtree = newMemTree(memTreeFLW, nil, 0)
- m.dbStore = d
- m.setCapacity(capacity)
- return
- }
- type memTree struct {
- subtree []*memTree
- parent *memTree
- parentIdx uint
- bits uint
- width uint
- entry *Chunk
- 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
- }
- func (s *MemStore) Put(entry *Chunk) {
- 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.Req == nil {
- entry.Req = node.entry.Req
- }
- 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) {
- 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 {
- return nil, notFound
- }
- 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.dbStore != nil {
- s.dbStore.updateAccessCnt(hash)
- }
- }
- } else {
- err = notFound
- }
- return
- }
- func (s *MemStore) removeOldest() {
- node := s.memtree
- 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)
- }
-
- node = node.subtree[pidx]
- }
- if node.entry.dbStored != nil {
- log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log()))
- <-node.entry.dbStored
- log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log()))
- } else {
- log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v already in DB. Ready to delete.", node.entry.Key.Log()))
- }
- if node.entry.SData != nil {
- memstoreRemoveCounter.Inc(1)
- node.entry = nil
- s.entryCnt--
- }
- 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
- }
- }
- }
- func (s *MemStore) Close() {}
|