mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
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:
parent
4d3af2ca33
commit
2c464282cd
1 changed files with 296 additions and 301 deletions
597
bzz/memstore.go
597
bzz/memstore.go
|
|
@ -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)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue