Minor stats fixes.

pull/34/head
Ben Johnson 2014-05-14 12:06:31 -06:00
parent 6eaeb31424
commit e728eb90da
2 changed files with 42 additions and 12 deletions

View File

@ -371,11 +371,14 @@ func (b *Bucket) Stats() BucketStats {
b.forEachPage(func(p *page, depth int) { b.forEachPage(func(p *page, depth int) {
if (p.flags & leafPageFlag) != 0 { if (p.flags & leafPageFlag) != 0 {
s.KeyN += int(p.count) s.KeyN += int(p.count)
// used totals the used bytes for the page // used totals the used bytes for the page
used := pageHeaderSize used := pageHeaderSize
if p.count != 0 { if p.count != 0 {
// If page has any elements, add all element headers. // If page has any elements, add all element headers.
used += leafPageElementSize * int(p.count-1) used += leafPageElementSize * int(p.count-1)
// Add all element key, value sizes. // Add all element key, value sizes.
// The computation takes advantage of the fact that the position // The computation takes advantage of the fact that the position
// of the last element's key/value equals to the total of the sizes // of the last element's key/value equals to the total of the sizes
@ -384,6 +387,7 @@ func (b *Bucket) Stats() BucketStats {
lastElement := p.leafPageElement(p.count - 1) lastElement := p.leafPageElement(p.count - 1)
used += int(lastElement.pos + lastElement.ksize + lastElement.vsize) used += int(lastElement.pos + lastElement.ksize + lastElement.vsize)
} }
if b.root == 0 { if b.root == 0 {
// For inlined bucket just update the inline stats // For inlined bucket just update the inline stats
s.InlineBucketInuse += used s.InlineBucketInuse += used
@ -408,9 +412,11 @@ func (b *Bucket) Stats() BucketStats {
} else if (p.flags & branchPageFlag) != 0 { } else if (p.flags & branchPageFlag) != 0 {
s.BranchPageN++ s.BranchPageN++
lastElement := p.branchPageElement(p.count - 1) lastElement := p.branchPageElement(p.count - 1)
// used totals the used bytes for the page // used totals the used bytes for the page
// Add header and all element headers. // Add header and all element headers.
used := pageHeaderSize + (branchPageElementSize * int(p.count-1)) used := pageHeaderSize + (branchPageElementSize * int(p.count-1))
// Add size of all keys and values. // Add size of all keys and values.
// Again, use the fact that last element's position equals to // Again, use the fact that last element's position equals to
// the total of key, value sizes of all previous elements. // the total of key, value sizes of all previous elements.
@ -418,11 +424,13 @@ func (b *Bucket) Stats() BucketStats {
s.BranchInuse += used s.BranchInuse += used
s.BranchOverflowN += int(p.overflow) s.BranchOverflowN += int(p.overflow)
} }
// Keep track of maximum page depth. // Keep track of maximum page depth.
if depth+1 > s.Depth { if depth+1 > s.Depth {
s.Depth = (depth + 1) s.Depth = (depth + 1)
} }
}) })
// Alloc stats can be computed from page counts and pageSize. // Alloc stats can be computed from page counts and pageSize.
s.BranchAlloc = (s.BranchPageN + s.BranchOverflowN) * pageSize s.BranchAlloc = (s.BranchPageN + s.BranchOverflowN) * pageSize
s.LeafAlloc = (s.LeafPageN + s.LeafOverflowN) * pageSize s.LeafAlloc = (s.LeafPageN + s.LeafOverflowN) * pageSize
@ -568,7 +576,7 @@ func (b *Bucket) maxInlineBucketSize() int {
func (b *Bucket) write() []byte { func (b *Bucket) write() []byte {
// Allocate the appropriate size. // Allocate the appropriate size.
var n = b.rootNode var n = b.rootNode
var value = make([]byte, bucketHeaderSize+pageHeaderSize+n.size()) var value = make([]byte, bucketHeaderSize+n.size())
// Write a bucket header. // Write a bucket header.
var bucket = (*bucket)(unsafe.Pointer(&value[0])) var bucket = (*bucket)(unsafe.Pointer(&value[0]))

View File

@ -566,7 +566,7 @@ func TestBucket_Stats(t *testing.T) {
b, err := tx.CreateBucket([]byte("woojits")) b, err := tx.CreateBucket([]byte("woojits"))
assert.NoError(t, err) assert.NoError(t, err)
for i := 0; i < 500; i++ { for i := 0; i < 500; i++ {
b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))) b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i)))
} }
b.Put(big_key, []byte(strings.Repeat("*", 10000))) b.Put(big_key, []byte(strings.Repeat("*", 10000)))
@ -582,15 +582,24 @@ func TestBucket_Stats(t *testing.T) {
assert.Equal(t, 2, stats.LeafOverflowN, "LeafOverflowN") assert.Equal(t, 2, stats.LeafOverflowN, "LeafOverflowN")
assert.Equal(t, 501, stats.KeyN, "KeyN") assert.Equal(t, 501, stats.KeyN, "KeyN")
assert.Equal(t, 2, stats.Depth, "Depth") assert.Equal(t, 2, stats.Depth, "Depth")
assert.Equal(t, 125, stats.BranchInuse, "BranchInuse")
used := pageHeaderSize + 501*leafPageElementSize branchInuse := pageHeaderSize // branch page header
used += 10*2 + 90*4 + 400*6 + len(big_key) + 10000 branchInuse += 6 * branchPageElementSize // branch elements
assert.Equal(t, used, stats.LeafInuse, "LeafInuse") branchInuse += 6 * 3 // branch keys (6 3-byte keys)
assert.Equal(t, branchInuse, stats.BranchInuse, "BranchInuse")
leafInuse := 6 * pageHeaderSize // leaf page header
leafInuse += 501 * leafPageElementSize // leaf elements
leafInuse += 500*3 + len(big_key) // leaf keys
leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values
assert.Equal(t, leafInuse, stats.LeafInuse, "LeafInuse")
if os.Getpagesize() == 4096 { if os.Getpagesize() == 4096 {
// Incompatible page size // Incompatible page size
assert.Equal(t, 4096, stats.BranchAlloc, "BranchAlloc") assert.Equal(t, 4096, stats.BranchAlloc, "BranchAlloc")
assert.Equal(t, 32768, stats.LeafAlloc, "LeafAlloc") assert.Equal(t, 32768, stats.LeafAlloc, "LeafAlloc")
} }
assert.Equal(t, 1, stats.BucketN, "BucketN") assert.Equal(t, 1, stats.BucketN, "BucketN")
assert.Equal(t, 0, stats.InlineBucketN, "InlineBucketN") assert.Equal(t, 0, stats.InlineBucketN, "InlineBucketN")
assert.Equal(t, 0, stats.InlineBucketInuse, "InlineBucketInuse") assert.Equal(t, 0, stats.InlineBucketInuse, "InlineBucketInuse")
@ -672,13 +681,12 @@ func TestBucket_Stats_EmptyBucket(t *testing.T) {
// Ensure a bucket can calculate stats. // Ensure a bucket can calculate stats.
func TestBucket_Stats_Nested(t *testing.T) { func TestBucket_Stats_Nested(t *testing.T) {
withOpenDB(func(db *DB, path string) { withOpenDB(func(db *DB, path string) {
db.Update(func(tx *Tx) error { db.Update(func(tx *Tx) error {
b, err := tx.CreateBucket([]byte("foo")) b, err := tx.CreateBucket([]byte("foo"))
assert.NoError(t, err) assert.NoError(t, err)
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))) b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i)))
} }
bar, err := b.CreateBucket([]byte("bar")) bar, err := b.CreateBucket([]byte("bar"))
assert.NoError(t, err) assert.NoError(t, err)
@ -692,7 +700,9 @@ func TestBucket_Stats_Nested(t *testing.T) {
} }
return nil return nil
}) })
mustCheck(db) mustCheck(db)
db.View(func(tx *Tx) error { db.View(func(tx *Tx) error {
b := tx.Bucket([]byte("foo")) b := tx.Bucket([]byte("foo"))
stats := b.Stats() stats := b.Stats()
@ -703,10 +713,22 @@ func TestBucket_Stats_Nested(t *testing.T) {
assert.Equal(t, 122, stats.KeyN, "KeyN") assert.Equal(t, 122, stats.KeyN, "KeyN")
assert.Equal(t, 3, stats.Depth, "Depth") assert.Equal(t, 3, stats.Depth, "Depth")
assert.Equal(t, 0, stats.BranchInuse, "BranchInuse") assert.Equal(t, 0, stats.BranchInuse, "BranchInuse")
baz := pageHeaderSize + 10*leafPageElementSize + 10*2
foo := pageHeaderSize + 101*leafPageElementSize + 10*2 + 90*4 + 3 + bucketHeaderSize foo := pageHeaderSize // foo
bar := pageHeaderSize + 11*leafPageElementSize + 10*2 + 3 + bucketHeaderSize + baz foo += 101 * leafPageElementSize // foo leaf elements
assert.Equal(t, foo+bar, stats.LeafInuse, "LeafInuse") foo += 100*2 + 100*2 // foo leaf key/values
foo += 3 + bucketHeaderSize // foo -> bar key/value
bar := pageHeaderSize // bar
bar += 11 * leafPageElementSize // bar leaf elements
bar += 10 + 10 // bar leaf key/values
bar += 3 + bucketHeaderSize // bar -> baz key/value
baz := pageHeaderSize // baz (inline)
baz += 10 * leafPageElementSize // baz leaf elements
baz += 10 + 10 // baz leaf key/values
assert.Equal(t, foo+bar+baz, stats.LeafInuse, "LeafInuse")
if os.Getpagesize() == 4096 { if os.Getpagesize() == 4096 {
// Incompatible page size // Incompatible page size
assert.Equal(t, 0, stats.BranchAlloc, "BranchAlloc") assert.Equal(t, 0, stats.BranchAlloc, "BranchAlloc")