From d279ea44cedc355c5dc574d2fd6edfb5e2088410 Mon Sep 17 00:00:00 2001 From: Martin Kobetic Date: Fri, 9 May 2014 13:35:00 +0000 Subject: [PATCH 1/2] add asserts for detecting pgid high watermark overflow --- bucket.go | 1 + cmd/bolt/stats.go | 54 +++++++++++++++++++++++++++++++++++++++++++++++ db.go | 4 ++++ node.go | 4 ++++ 4 files changed, 63 insertions(+) create mode 100644 cmd/bolt/stats.go diff --git a/bucket.go b/bucket.go index 25ad1ba..a57f456 100644 --- a/bucket.go +++ b/bucket.go @@ -476,6 +476,7 @@ func (b *Bucket) spill() error { b.rootNode = b.rootNode.root() // Update the root node for this bucket. + _assert(b.rootNode.pgid < b.tx.meta.pgid, "pgid (%d) above high water mark (%d)", b.rootNode.pgid, b.tx.meta.pgid) b.root = b.rootNode.pgid return nil diff --git a/cmd/bolt/stats.go b/cmd/bolt/stats.go new file mode 100644 index 0000000..da344d0 --- /dev/null +++ b/cmd/bolt/stats.go @@ -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 + } +} diff --git a/db.go b/db.go index d96a161..0b74621 100644 --- a/db.go +++ b/db.go @@ -705,6 +705,10 @@ func (m *meta) copy(dest *meta) { // write writes the meta onto a page. func (m *meta) write(p *page) { + + _assert(m.root.root < m.pgid, "root bucket pgid (%d) above high water mark (%d)", m.root.root, m.pgid) + _assert(m.freelist < m.pgid, "freelist pgid (%d) above high water mark (%d)", m.freelist, m.pgid) + // Page id is either going to be 0 or 1 which we can determine by the transaction ID. p.id = pgid(m.txid % 2) p.flags |= metaPageFlag diff --git a/node.go b/node.go index 1bc889d..14bf136 100644 --- a/node.go +++ b/node.go @@ -98,6 +98,8 @@ func (n *node) prevSibling() *node { // put inserts a key/value. func (n *node) put(oldKey, newKey, value []byte, pgid pgid, flags uint32) { + _assert(pgid < n.bucket.tx.meta.pgid, "pgid (%d) above high water mark (%d)", pgid, n.bucket.tx.meta.pgid) + // Find insertion index. index := sort.Search(len(n.inodes), func(i int) bool { return bytes.Compare(n.inodes[i].key, oldKey) != -1 }) @@ -278,6 +280,7 @@ func (n *node) spill() error { } // Write the node. + _assert(p.id < tx.meta.pgid, "pgid (%d) above high water mark (%d)", p.id, tx.meta.pgid) node.pgid = p.id node.write(p) @@ -307,6 +310,7 @@ func (n *node) spill() error { } // Write the new root. + _assert(p.id < tx.meta.pgid, "pgid (%d) above high water mark (%d)", p.id, tx.meta.pgid) parent.pgid = p.id parent.write(p) } From 3ffcee742c104f84321cd6c08eaa449c65114395 Mon Sep 17 00:00:00 2001 From: Martin Kobetic Date: Fri, 9 May 2014 13:38:11 +0000 Subject: [PATCH 2/2] remove stray file --- cmd/bolt/stats.go | 54 ----------------------------------------------- 1 file changed, 54 deletions(-) delete mode 100644 cmd/bolt/stats.go diff --git a/cmd/bolt/stats.go b/cmd/bolt/stats.go deleted file mode 100644 index da344d0..0000000 --- a/cmd/bolt/stats.go +++ /dev/null @@ -1,54 +0,0 @@ -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 - } -}