github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/swarm/storage/memstore.go (about)

     1  // Copyright 2016 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  	"fmt"
    23  	"sync"
    24  
    25  	"github.com/ethereum/go-ethereum/log"
    26  )
    27  
    28  const (
    29  	memTreeLW              = 2  // log2(subtree count) of the subtrees
    30  	memTreeFLW             = 14 // log2(subtree count) of the root layer
    31  	dbForceUpdateAccessCnt = 1000
    32  	defaultCacheCapacity   = 5000
    33  )
    34  
    35  type MemStore struct {
    36  	memtree            *memTree
    37  	entryCnt, capacity uint   // stored entries
    38  	accessCnt          uint64 // access counter; oldest is thrown away when full
    39  	dbAccessCnt        uint64
    40  	dbStore            *DbStore
    41  	lock               sync.Mutex
    42  }
    43  
    44  /*
    45  a hash prefix subtree containing subtrees or one storage entry (but never both)
    46  
    47  - access[0] stores the smallest (oldest) access count value in this subtree
    48  - if it contains more subtrees and its subtree count is at least 4, access[1:2]
    49    stores the smallest access count in the first and second halves of subtrees
    50    (so that access[0] = min(access[1], access[2])
    51  - likewise, if subtree count is at least 8,
    52    access[1] = min(access[3], access[4])
    53    access[2] = min(access[5], access[6])
    54    (access[] is a binary tree inside the multi-bit leveled hash tree)
    55  */
    56  
    57  func NewMemStore(d *DbStore, capacity uint) (m *MemStore) {
    58  	m = &MemStore{}
    59  	m.memtree = newMemTree(memTreeFLW, nil, 0)
    60  	m.dbStore = d
    61  	m.setCapacity(capacity)
    62  	return
    63  }
    64  
    65  type memTree struct {
    66  	subtree   []*memTree
    67  	parent    *memTree
    68  	parentIdx uint
    69  
    70  	bits  uint // log2(subtree count)
    71  	width uint // subtree count
    72  
    73  	entry        *Chunk // if subtrees are present, entry should be nil
    74  	lastDBaccess uint64
    75  	access       []uint64
    76  }
    77  
    78  func newMemTree(b uint, parent *memTree, pidx uint) (node *memTree) {
    79  	node = new(memTree)
    80  	node.bits = b
    81  	node.width = 1 << uint(b)
    82  	node.subtree = make([]*memTree, node.width)
    83  	node.access = make([]uint64, node.width-1)
    84  	node.parent = parent
    85  	node.parentIdx = pidx
    86  	if parent != nil {
    87  		parent.subtree[pidx] = node
    88  	}
    89  
    90  	return node
    91  }
    92  
    93  func (node *memTree) updateAccess(a uint64) {
    94  	aidx := uint(0)
    95  	var aa uint64
    96  	oa := node.access[0]
    97  	for node.access[aidx] == oa {
    98  		node.access[aidx] = a
    99  		if aidx > 0 {
   100  			aa = node.access[((aidx-1)^1)+1]
   101  			aidx = (aidx - 1) >> 1
   102  		} else {
   103  			pidx := node.parentIdx
   104  			node = node.parent
   105  			if node == nil {
   106  				return
   107  			}
   108  			nn := node.subtree[pidx^1]
   109  			if nn != nil {
   110  				aa = nn.access[0]
   111  			} else {
   112  				aa = 0
   113  			}
   114  			aidx = (node.width + pidx - 2) >> 1
   115  		}
   116  
   117  		if (aa != 0) && (aa < a) {
   118  			a = aa
   119  		}
   120  	}
   121  }
   122  
   123  func (s *MemStore) setCapacity(c uint) {
   124  	s.lock.Lock()
   125  	defer s.lock.Unlock()
   126  
   127  	for c < s.entryCnt {
   128  		s.removeOldest()
   129  	}
   130  	s.capacity = c
   131  }
   132  
   133  func (s *MemStore) getEntryCnt() uint {
   134  	return s.entryCnt
   135  }
   136  
   137  // entry (not its copy) is going to be in MemStore
   138  func (s *MemStore) Put(entry *Chunk) {
   139  	if s.capacity == 0 {
   140  		return
   141  	}
   142  
   143  	s.lock.Lock()
   144  	defer s.lock.Unlock()
   145  
   146  	if s.entryCnt >= s.capacity {
   147  		s.removeOldest()
   148  	}
   149  
   150  	s.accessCnt++
   151  
   152  	node := s.memtree
   153  	bitpos := uint(0)
   154  	for node.entry == nil {
   155  		l := entry.Key.bits(bitpos, node.bits)
   156  		st := node.subtree[l]
   157  		if st == nil {
   158  			st = newMemTree(memTreeLW, node, l)
   159  			bitpos += node.bits
   160  			node = st
   161  			break
   162  		}
   163  		bitpos += node.bits
   164  		node = st
   165  	}
   166  
   167  	if node.entry != nil {
   168  
   169  		if node.entry.Key.isEqual(entry.Key) {
   170  			node.updateAccess(s.accessCnt)
   171  			if entry.SData == nil {
   172  				entry.Size = node.entry.Size
   173  				entry.SData = node.entry.SData
   174  			}
   175  			if entry.Req == nil {
   176  				entry.Req = node.entry.Req
   177  			}
   178  			entry.C = node.entry.C
   179  			node.entry = entry
   180  			return
   181  		}
   182  
   183  		for node.entry != nil {
   184  
   185  			l := node.entry.Key.bits(bitpos, node.bits)
   186  			st := node.subtree[l]
   187  			if st == nil {
   188  				st = newMemTree(memTreeLW, node, l)
   189  			}
   190  			st.entry = node.entry
   191  			node.entry = nil
   192  			st.updateAccess(node.access[0])
   193  
   194  			l = entry.Key.bits(bitpos, node.bits)
   195  			st = node.subtree[l]
   196  			if st == nil {
   197  				st = newMemTree(memTreeLW, node, l)
   198  			}
   199  			bitpos += node.bits
   200  			node = st
   201  
   202  		}
   203  	}
   204  
   205  	node.entry = entry
   206  	node.lastDBaccess = s.dbAccessCnt
   207  	node.updateAccess(s.accessCnt)
   208  	s.entryCnt++
   209  
   210  	return
   211  }
   212  
   213  func (s *MemStore) Get(hash Key) (chunk *Chunk, err error) {
   214  	s.lock.Lock()
   215  	defer s.lock.Unlock()
   216  
   217  	node := s.memtree
   218  	bitpos := uint(0)
   219  	for node.entry == nil {
   220  		l := hash.bits(bitpos, node.bits)
   221  		st := node.subtree[l]
   222  		if st == nil {
   223  			return nil, notFound
   224  		}
   225  		bitpos += node.bits
   226  		node = st
   227  	}
   228  
   229  	if node.entry.Key.isEqual(hash) {
   230  		s.accessCnt++
   231  		node.updateAccess(s.accessCnt)
   232  		chunk = node.entry
   233  		if s.dbAccessCnt-node.lastDBaccess > dbForceUpdateAccessCnt {
   234  			s.dbAccessCnt++
   235  			node.lastDBaccess = s.dbAccessCnt
   236  			if s.dbStore != nil {
   237  				s.dbStore.updateAccessCnt(hash)
   238  			}
   239  		}
   240  	} else {
   241  		err = notFound
   242  	}
   243  
   244  	return
   245  }
   246  
   247  func (s *MemStore) removeOldest() {
   248  	node := s.memtree
   249  
   250  	for node.entry == nil {
   251  
   252  		aidx := uint(0)
   253  		av := node.access[aidx]
   254  
   255  		for aidx < node.width/2-1 {
   256  			if av == node.access[aidx*2+1] {
   257  				node.access[aidx] = node.access[aidx*2+2]
   258  				aidx = aidx*2 + 1
   259  			} else if av == node.access[aidx*2+2] {
   260  				node.access[aidx] = node.access[aidx*2+1]
   261  				aidx = aidx*2 + 2
   262  			} else {
   263  				panic(nil)
   264  			}
   265  		}
   266  		pidx := aidx*2 + 2 - node.width
   267  		if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) {
   268  			if node.subtree[pidx+1] != nil {
   269  				node.access[aidx] = node.subtree[pidx+1].access[0]
   270  			} else {
   271  				node.access[aidx] = 0
   272  			}
   273  		} else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) {
   274  			if node.subtree[pidx] != nil {
   275  				node.access[aidx] = node.subtree[pidx].access[0]
   276  			} else {
   277  				node.access[aidx] = 0
   278  			}
   279  			pidx++
   280  		} else {
   281  			panic(nil)
   282  		}
   283  
   284  		//fmt.Println(pidx)
   285  		node = node.subtree[pidx]
   286  
   287  	}
   288  
   289  	if node.entry.dbStored != nil {
   290  		log.Trace(fmt.Sprintf("Memstore Clean: Waiting for chunk %v to be saved", node.entry.Key.Log()))
   291  		<-node.entry.dbStored
   292  		log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v saved to DBStore. Ready to clear from mem.", node.entry.Key.Log()))
   293  	} else {
   294  		log.Trace(fmt.Sprintf("Memstore Clean: Chunk %v already in DB. Ready to delete.", node.entry.Key.Log()))
   295  	}
   296  
   297  	if node.entry.SData != nil {
   298  		node.entry = nil
   299  		s.entryCnt--
   300  	}
   301  
   302  	node.access[0] = 0
   303  
   304  	//---
   305  
   306  	aidx := uint(0)
   307  	for {
   308  		aa := node.access[aidx]
   309  		if aidx > 0 {
   310  			aidx = (aidx - 1) >> 1
   311  		} else {
   312  			pidx := node.parentIdx
   313  			node = node.parent
   314  			if node == nil {
   315  				return
   316  			}
   317  			aidx = (node.width + pidx - 2) >> 1
   318  		}
   319  		if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) {
   320  			node.access[aidx] = aa
   321  		}
   322  	}
   323  }
   324  
   325  // Close memstore
   326  func (s *MemStore) Close() {
   327  	return
   328  }