forked from deroproject/graviton
-
Notifications
You must be signed in to change notification settings - Fork 0
/
extra.go
80 lines (72 loc) · 2.13 KB
/
extra.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package graviton
import "fmt"
import "math"
import "crypto/rand"
func (t *Tree) GetName() (string) {
return t.treename
}
// Random returns a random key,value from the tree, provided a tree has keys
// the following are limitations
// a tree containing 0 key, value pairs will return err
// randomness depends on number of keys, if tree contains only 1 value, it will be ported etc
func (t *Tree) Random() (k, v []byte, err error) {
return t.random(t.root)
}
func (t *Tree) random(cnode node) (k, v []byte, err error) {
switch node := cnode.(type) {
case *inner:
if node.loaded_partial { // if node is loaded partially, load it fully now
if err = node.loadinnerfromstore(t.store); err != nil {
return
}
}
left, right := node.left, node.right
if left != nil && right != nil { // we have an option to choose from left or right randomly
var rbyte [1]byte
if _, err = rand.Read(rbyte[:]); err != nil {
return
}
if rbyte[0]&1 == 1 {
return t.random(right) // descend further
}
return t.random(left) // descend further
}
if right != nil {
return t.random(right) // descend further without any option
}
if left != nil {
return t.random(left) // descend further without any option
}
// we can only reach here if a tree has both left,right nil, ie an empty tree
err = ErrNoMoreKeys
return
case *leaf:
if node.loaded_partial { // if leaf is loaded partially, load it fully now
if err = node.loadfullleaffromstore(t.store); err != nil {
return
}
}
return node.key, node.value, nil
default:
return k, v, fmt.Errorf("unknown node type, corruption")
}
}
// estimate number of keys that exist in the tree
// very crude but only used for use display
func (t *Tree) KeyCountEstimate() (count int64) {
c := t.Cursor()
var depth_array []int
var floatsum float64
for _, _, err := c.First(); err == nil; _, _, err = c.Next() {
floatsum += float64(len(c.node_path))
depth_array = append(depth_array, len(c.node_path))
if len(depth_array) >= 20 {
break
}
}
if len(depth_array) <= 4 {
return int64(count)
}
avg := floatsum / float64(len(depth_array)+1)
return int64(math.Exp2(avg))
}