mirror of https://github.com/hak5/bolt.git
first part
parent
4b56f820bc
commit
b9899d09ab
43
bucket.go
43
bucket.go
|
@ -129,16 +129,23 @@ func (b *Bucket) Bucket(name []byte) *Bucket {
|
|||
}
|
||||
|
||||
// Otherwise create a bucket and cache it.
|
||||
var child = newBucket(b.tx)
|
||||
child.bucket = &bucket{}
|
||||
*child.bucket = *(*bucket)(unsafe.Pointer(&v[0]))
|
||||
b.buckets[string(name)] = &child
|
||||
var child = b.openBucket(v)
|
||||
b.buckets[string(name)] = child
|
||||
|
||||
// Save a reference to the inline page if the bucket is inline.
|
||||
if child.root == 0 {
|
||||
child.page = (*page)(unsafe.Pointer(&v[bucketHeaderSize]))
|
||||
}
|
||||
|
||||
return child
|
||||
}
|
||||
|
||||
// Helper method that re-interprets a sub-bucket value
|
||||
// from a parent into a Bucket
|
||||
func (b *Bucket) openBucket(value []byte) *Bucket {
|
||||
var child = newBucket(b.tx)
|
||||
child.bucket = &bucket{}
|
||||
*child.bucket = *(*bucket)(unsafe.Pointer(&value[0]))
|
||||
return &child
|
||||
}
|
||||
|
||||
|
@ -354,7 +361,7 @@ func (b *Bucket) ForEach(fn func(k, v []byte) error) error {
|
|||
|
||||
// Stat returns stats on a bucket.
|
||||
func (b *Bucket) Stats() BucketStats {
|
||||
var s BucketStats
|
||||
var s, subStats BucketStats
|
||||
pageSize := b.tx.db.pageSize
|
||||
b.forEachPage(func(p *page, depth int) {
|
||||
if (p.flags & leafPageFlag) != 0 {
|
||||
|
@ -365,6 +372,13 @@ func (b *Bucket) Stats() BucketStats {
|
|||
used += int(lastElement.pos + lastElement.ksize + lastElement.vsize)
|
||||
s.LeafInuse += used
|
||||
s.LeafOverflowN += int(p.overflow)
|
||||
|
||||
// Recurse into sub-buckets
|
||||
for _, e := range p.leafPageElements() {
|
||||
if e.flags&bucketLeafFlag != 0 {
|
||||
subStats.Add(b.openBucket(e.value()).Stats())
|
||||
}
|
||||
}
|
||||
} else if (p.flags & branchPageFlag) != 0 {
|
||||
s.BranchPageN++
|
||||
lastElement := p.branchPageElement(p.count - 1)
|
||||
|
@ -380,6 +394,10 @@ func (b *Bucket) Stats() BucketStats {
|
|||
})
|
||||
s.BranchAlloc = (s.BranchPageN + s.BranchOverflowN) * pageSize
|
||||
s.LeafAlloc = (s.LeafPageN + s.LeafOverflowN) * pageSize
|
||||
|
||||
// add the max depth of sub-buckets to get total nested depth
|
||||
s.Depth += subStats.Depth
|
||||
s.Add(subStats)
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -643,6 +661,21 @@ type BucketStats struct {
|
|||
LeafInuse int // bytes actually used for leaf data
|
||||
}
|
||||
|
||||
func (s *BucketStats) Add(other BucketStats) {
|
||||
s.BranchPageN += other.BranchPageN
|
||||
s.BranchOverflowN += other.BranchOverflowN
|
||||
s.LeafPageN += other.LeafPageN
|
||||
s.LeafOverflowN += other.LeafOverflowN
|
||||
s.KeyN += s.KeyN
|
||||
if s.Depth < other.Depth {
|
||||
s.Depth = other.Depth
|
||||
}
|
||||
s.BranchAlloc += other.BranchAlloc
|
||||
s.BranchInuse += other.BranchInuse
|
||||
s.LeafAlloc += other.LeafAlloc
|
||||
s.LeafInuse += other.LeafInuse
|
||||
}
|
||||
|
||||
// cloneBytes returns a copy of a given slice.
|
||||
func cloneBytes(v []byte) []byte {
|
||||
var clone = make([]byte, len(v))
|
||||
|
|
|
@ -91,6 +91,14 @@ func NewApp() *cli.App {
|
|||
Check(path)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "stats",
|
||||
Usage: "Retrieve statistics for a bucket (aggregated recursively)",
|
||||
Action: func(c *cli.Context) {
|
||||
path, name := c.Args().Get(0), c.Args().Get(1)
|
||||
Stats(path, name)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "bench",
|
||||
Usage: "Performs a synthetic benchmark",
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// Keys retrieves a list of keys for a given bucket.
|
||||
func Stats(path, name string) {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
db, err := bolt.Open(path, 0600)
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
err = db.View(func(tx *bolt.Tx) error {
|
||||
// Find bucket.
|
||||
b := tx.Bucket([]byte(name))
|
||||
if b == nil {
|
||||
fatalf("bucket not found: %s", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Iterate over each key.
|
||||
s := b.Stats()
|
||||
println("Page count statistics")
|
||||
printf("\tNumber of logical branch pages: %d\n", s.BranchPageN)
|
||||
printf("\tNumber of physical branch overflow pages: %d\n", s.BranchOverflowN)
|
||||
printf("\tNumber of logical leaf pages: %d\n", s.LeafPageN)
|
||||
printf("\tNumber of physical leaf overflow pages: %d\n", s.LeafOverflowN)
|
||||
|
||||
println("Tree statistics")
|
||||
printf("\tNumber of keys/value pairs: %d\n", s.KeyN)
|
||||
printf("\tNumber of levels in B+tree: %d\n", s.Depth)
|
||||
|
||||
println("Page size utilization")
|
||||
printf("\tBytes allocated for physical branch pages: %d\n", s.BranchAlloc)
|
||||
printf("\tBytes actually used for branch data: %d\n", s.BranchInuse)
|
||||
printf("\tBytes allocated for physical leaf pages: %d\n", s.LeafAlloc)
|
||||
printf("\tBytes actually used for leaf data: %d\n", s.LeafInuse)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
fatal(err)
|
||||
return
|
||||
}
|
||||
}
|
4
page.go
4
page.go
|
@ -63,7 +63,7 @@ func (p *page) leafPageElement(index uint16) *leafPageElement {
|
|||
|
||||
// leafPageElements retrieves a list of leaf nodes.
|
||||
func (p *page) leafPageElements() []leafPageElement {
|
||||
return ((*[maxNodesPerPage]leafPageElement)(unsafe.Pointer(&p.ptr)))[:]
|
||||
return ((*[maxNodesPerPage]leafPageElement)(unsafe.Pointer(&p.ptr)))[:p.count]
|
||||
}
|
||||
|
||||
// branchPageElement retrieves the branch node by index
|
||||
|
@ -73,7 +73,7 @@ func (p *page) branchPageElement(index uint16) *branchPageElement {
|
|||
|
||||
// branchPageElements retrieves a list of branch nodes.
|
||||
func (p *page) branchPageElements() []branchPageElement {
|
||||
return ((*[maxNodesPerPage]branchPageElement)(unsafe.Pointer(&p.ptr)))[:]
|
||||
return ((*[maxNodesPerPage]branchPageElement)(unsafe.Pointer(&p.ptr)))[:p.count]
|
||||
}
|
||||
|
||||
// dump writes n bytes of the page to STDERR as hex output.
|
||||
|
|
Loading…
Reference in New Issue