memstore changes

- inttegrate changes related to db + access count
- simplify API , only Get/Put no add/find
- signal need to retrieve from db with chunk.update = true
- consistent naming
- unix line endings
This commit is contained in:
zelig 2015-02-01 19:41:27 +01:00
parent 4d3af2ca33
commit 2c464282cd

View file

@ -1,301 +1,296 @@
// memory storage layer for the package blockhash // memory storage layer for the package blockhash
package bzz package bzz
import ( import (
"bytes" "bytes"
) )
const ( const (
maxEntries = 500 // max number of stored (cached) blocks maxEntries = 500 // max number of stored (cached) blocks
memTreeLW = 2 // log2(subtree count) of the subtrees memTreeLW = 2 // log2(subtree count) of the subtrees
memTreeFLW = 14 // log2(subtree count) of the root layer memTreeFLW = 14 // log2(subtree count) of the root layer
dbForceUpdateAccessCnt = 1000 dbForceUpdateAccessCnt = 1000
) )
type dpaMemStorage struct { type memStore struct {
memtree *dpaMemTree memtree *memTree
entry_cnt uint // stored entries entryCnt uint // stored entries
access_cnt uint64 // access counter; oldest is thrown away when full accessCnt uint64 // access counter; oldest is thrown away when full
dbAccessCnt uint64 dbAccessCnt uint64
} }
/* /*
a hash prefix subtree containing subtrees or one storage entry (but never both) 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 - 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] - 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 stores the smallest access count in the first and second halves of subtrees
(so that access[0] = min(access[1], access[2]) (so that access[0] = min(access[1], access[2])
- likewise, if subtree count is at least 8, - likewise, if subtree count is at least 8,
access[1] = min(access[3], access[4]) access[1] = min(access[3], access[4])
access[2] = min(access[5], access[6]) access[2] = min(access[5], access[6])
(access[] is a binary tree inside the multi-bit leveled hash tree) (access[] is a binary tree inside the multi-bit leveled hash tree)
*/ */
func (x Key) Size() uint { func (x Key) Size() uint {
return uint(len(x)) return uint(len(x))
} }
func (x Key) isEqual(y Key) bool { func (x Key) isEqual(y Key) bool {
return bytes.Compare(x, y) == 0 return bytes.Compare(x, y) == 0
} }
func (h Key) bits(i, j uint) uint { func (h Key) bits(i, j uint) uint {
ii := i >> 3 ii := i >> 3
jj := i & 7 jj := i & 7
if ii >= h.Size() { if ii >= h.Size() {
return 0 return 0
} }
if jj+j <= 8 { if jj+j <= 8 {
return uint((h[ii] >> jj) & ((1 << j) - 1)) return uint((h[ii] >> jj) & ((1 << j) - 1))
} }
res := uint(h[ii] >> jj) res := uint(h[ii] >> jj)
jj = 8 - jj jj = 8 - jj
j -= jj j -= jj
for j != 0 { for j != 0 {
ii++ ii++
if j < 8 { if j < 8 {
res += uint(h[ii]&((1<<j)-1)) << jj res += uint(h[ii]&((1<<j)-1)) << jj
return res return res
} }
res += uint(h[ii]) << jj res += uint(h[ii]) << jj
jj += 8 jj += 8
j -= 8 j -= 8
} }
return res return res
} }
type dpaMemTree struct { type memTree struct {
subtree []*dpaMemTree subtree []*memTree
parent *dpaMemTree parent *memTree
parent_idx uint parentIdx uint
bits uint // log2(subtree count) bits uint // log2(subtree count)
width uint // subtree count width uint // subtree count
entry *Chunk // if subtrees are present, entry should be nil entry *Chunk // if subtrees are present, entry should be nil
lastDBaccess uint64 lastDBaccess uint64
access []uint64 access []uint64
} }
func newTreeNode(b uint, parent *dpaMemTree, pidx uint) (node *dpaMemTree) { func newMemTree(b uint, parent *memTree, pidx uint) (node *memTree) {
node = new(dpaMemTree) node = new(memTree)
node.bits = b node.bits = b
node.width = 1 << uint(b) node.width = 1 << uint(b)
node.subtree = make([]*dpaMemTree, node.width) node.subtree = make([]*memTree, node.width)
node.access = make([]uint64, node.width-1) node.access = make([]uint64, node.width-1)
node.parent = parent node.parent = parent
node.parent_idx = pidx node.parentIdx = pidx
if parent != nil { if parent != nil {
parent.subtree[pidx] = node parent.subtree[pidx] = node
} }
return node return node
} }
func (node *dpaMemTree) update_access(a uint64) { func (node *memTree) updateAccess(a uint64) {
aidx := uint(0) aidx := uint(0)
var aa uint64 var aa uint64
oa := node.access[0] oa := node.access[0]
for node.access[aidx] == oa { for node.access[aidx] == oa {
node.access[aidx] = a node.access[aidx] = a
if aidx > 0 { if aidx > 0 {
aa = node.access[((aidx-1)^1)+1] aa = node.access[((aidx-1)^1)+1]
aidx = (aidx - 1) >> 1 aidx = (aidx - 1) >> 1
} else { } else {
pidx := node.parent_idx pidx := node.parentIdx
node = node.parent node = node.parent
if node == nil { if node == nil {
return return
} }
nn := node.subtree[pidx^1] nn := node.subtree[pidx^1]
if nn != nil { if nn != nil {
aa = nn.access[0] aa = nn.access[0]
} else { } else {
aa = 0 aa = 0
} }
aidx = (node.width + pidx - 2) >> 1 aidx = (node.width + pidx - 2) >> 1
} }
if (aa != 0) && (aa < a) { if (aa != 0) && (aa < a) {
a = aa a = aa
} }
} }
} }
func (s *dpaMemStorage) add(entry *Chunk) { func (s *memStore) Put(entry *Chunk) (err error) {
if s.entryCnt >= maxEntries {
s.access_cnt++ s.removeOldest()
}
node := s.memtree
bitpos := uint(0) s.accessCnt++
for node.entry == nil {
l := entry.Key.bits(bitpos, node.bits) node := s.memtree
st := node.subtree[l] bitpos := uint(0)
if st == nil { for node.entry == nil {
st = newTreeNode(memTreeLW, node, l) l := entry.Key.bits(bitpos, node.bits)
bitpos += node.bits st := node.subtree[l]
node = st if st == nil {
break st = newMemTree(memTreeLW, node, l)
} bitpos += node.bits
bitpos += node.bits node = st
node = st break
} }
bitpos += node.bits
if node.entry != nil { node = st
}
if node.entry.Key.isEqual(entry.Key) {
node.update_access(s.access_cnt) if node.entry != nil {
return
} if node.entry.Key.isEqual(entry.Key) {
node.updateAccess(s.accessCnt)
for node.entry != nil { return
}
l := node.entry.Key.bits(bitpos, node.bits)
st := node.subtree[l] for node.entry != nil {
if st == nil {
st = newTreeNode(memTreeLW, node, l) l := node.entry.Key.bits(bitpos, node.bits)
} st := node.subtree[l]
st.entry = node.entry if st == nil {
node.entry = nil st = newMemTree(memTreeLW, node, l)
st.update_access(node.access[0]) }
st.entry = node.entry
l = entry.Key.bits(bitpos, node.bits) node.entry = nil
st = node.subtree[l] st.updateAccess(node.access[0])
if st == nil {
st = newTreeNode(memTreeLW, node, l) l = entry.Key.bits(bitpos, node.bits)
} st = node.subtree[l]
bitpos += node.bits if st == nil {
node = st st = newMemTree(memTreeLW, node, l)
}
} bitpos += node.bits
} node = st
node.entry = entry }
node.lastDBaccess = s.dbAccessCnt }
node.update_access(s.access_cnt)
s.entry_cnt++ node.entry = entry
node.lastDBaccess = s.dbAccessCnt
} node.updateAccess(s.accessCnt)
s.entryCnt++
func (s *dpaMemStorage) find(hash Key) (entry *Chunk) {
return
node := s.memtree }
bitpos := uint(0)
for node.entry == nil { func (s *memStore) Get(chunk *Chunk) (err error) {
l := hash.bits(bitpos, node.bits) hash := chunk.Key
st := node.subtree[l] node := s.memtree
if st == nil { bitpos := uint(0)
return nil for node.entry == nil {
} l := hash.bits(bitpos, node.bits)
bitpos += node.bits st := node.subtree[l]
node = st if st == nil {
} return nil
}
if node.entry.Key.isEqual(hash) { bitpos += node.bits
s.access_cnt++ node = st
node.update_access(s.access_cnt) }
return node.entry
} else { if node.entry.Key.isEqual(hash) {
return nil s.accessCnt++
} node.updateAccess(s.accessCnt)
} if s.dbAccessCnt-node.lastDBaccess > dbForceUpdateAccessCnt {
s.dbAccessCnt++
func (s *dpaMemStorage) remove_oldest() { node.lastDBaccess = s.dbAccessCnt
chunk.update = true
node := s.memtree }
chunk.Data = node.entry.Data
for node.entry == nil { chunk.Size = node.entry.Size
} else {
aidx := uint(0) err = notFound
av := node.access[aidx] }
return
for aidx < node.width/2-1 { }
if av == node.access[aidx*2+1] {
node.access[aidx] = node.access[aidx*2+2] func (s *memStore) removeOldest() {
aidx = aidx*2 + 1
} else if av == node.access[aidx*2+2] { node := s.memtree
node.access[aidx] = node.access[aidx*2+1]
aidx = aidx*2 + 2 for node.entry == nil {
} else {
panic(nil) aidx := uint(0)
} av := node.access[aidx]
}
pidx := aidx*2 + 2 - node.width for aidx < node.width/2-1 {
if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) { if av == node.access[aidx*2+1] {
if node.subtree[pidx+1] != nil { node.access[aidx] = node.access[aidx*2+2]
node.access[aidx] = node.subtree[pidx+1].access[0] aidx = aidx*2 + 1
} else { } else if av == node.access[aidx*2+2] {
node.access[aidx] = 0 node.access[aidx] = node.access[aidx*2+1]
} aidx = aidx*2 + 2
} else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) { } else {
if node.subtree[pidx] != nil { panic(nil)
node.access[aidx] = node.subtree[pidx].access[0] }
} else { }
node.access[aidx] = 0 pidx := aidx*2 + 2 - node.width
} if (node.subtree[pidx] != nil) && (av == node.subtree[pidx].access[0]) {
pidx++ if node.subtree[pidx+1] != nil {
} else { node.access[aidx] = node.subtree[pidx+1].access[0]
panic(nil) } else {
} node.access[aidx] = 0
}
//fmt.Println(pidx) } else if (node.subtree[pidx+1] != nil) && (av == node.subtree[pidx+1].access[0]) {
node = node.subtree[pidx] if node.subtree[pidx] != nil {
node.access[aidx] = node.subtree[pidx].access[0]
} } else {
node.access[aidx] = 0
node.entry = nil }
s.entry_cnt-- pidx++
node.access[0] = 0 } else {
panic(nil)
//--- }
aidx := uint(0) //fmt.Println(pidx)
for { node = node.subtree[pidx]
aa := node.access[aidx]
if aidx > 0 { }
aidx = (aidx - 1) >> 1
} else { node.entry = nil
pidx := node.parent_idx s.entryCnt--
node = node.parent node.access[0] = 0
if node == nil {
return //---
}
aidx = (node.width + pidx - 2) >> 1 aidx := uint(0)
} for {
if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) { aa := node.access[aidx]
node.access[aidx] = aa if aidx > 0 {
} aidx = (aidx - 1) >> 1
} } else {
pidx := node.parentIdx
} node = node.parent
if node == nil {
func (s *dpaMemStorage) Put(req *Chunk) error { return
if s.entry_cnt >= maxEntries { }
s.remove_oldest() aidx = (node.width + pidx - 2) >> 1
} }
s.add(req) if (aa != 0) && ((aa < node.access[aidx]) || (node.access[aidx] == 0)) {
return nil node.access[aidx] = aa
} }
}
func (s *dpaMemStorage) Get(req *Chunk) {
}
entry := s.find(req.Key)
if entry == nil { func (s *memStore) Init() {
}
s.memtree = newMemTree(memTreeFLW, nil, 0)
}
}
func (s *dpaMemStorage) Init() {
s.memtree = newTreeNode(memTreeFLW, nil, 0)
}