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