81 lines
2.1 KiB
Go
81 lines
2.1 KiB
Go
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))
|
|
}
|