78 lines
2.3 KiB
Go
78 lines
2.3 KiB
Go
|
package graviton
|
||
|
|
||
|
import "fmt"
|
||
|
import "math"
|
||
|
import "crypto/rand"
|
||
|
|
||
|
|
||
|
// 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))
|
||
|
}
|