aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Johnson <benbjohnson@yahoo.com>2014-05-09 09:38:08 -0600
committerBen Johnson <benbjohnson@yahoo.com>2014-05-09 09:38:08 -0600
commitd1b21e619d11001e069ba793bb023951cd6f15fd (patch)
tree058209a444636914495eaa47621d7811a11156c0
parentFix deletion reclamation. (diff)
parentFix node unit tests. (diff)
downloaddedo-d1b21e619d11001e069ba793bb023951cd6f15fd.tar.gz
dedo-d1b21e619d11001e069ba793bb023951cd6f15fd.tar.xz
Merge branch 'master' of https://github.com/boltdb/bolt into fix-deletion
Conflicts: node.go
-rw-r--r--bucket.go1
-rw-r--r--cmd/bolt/info.go26
-rw-r--r--cmd/bolt/info_test.go32
-rw-r--r--cmd/bolt/main.go8
-rw-r--r--db.go4
-rw-r--r--node.go3
-rw-r--r--node_test.go10
7 files changed, 79 insertions, 5 deletions
diff --git a/bucket.go b/bucket.go
index 37dba0f..43204f7 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/info.go b/cmd/bolt/info.go
new file mode 100644
index 0000000..1e9e0d8
--- /dev/null
+++ b/cmd/bolt/info.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ "os"
+
+ "github.com/boltdb/bolt"
+)
+
+// Info prints basic information about a database.
+func Info(path 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()
+
+ // Print basic database info.
+ var info = db.Info()
+ printf("Page Size: %d", info.PageSize)
+}
diff --git a/cmd/bolt/info_test.go b/cmd/bolt/info_test.go
new file mode 100644
index 0000000..668cc61
--- /dev/null
+++ b/cmd/bolt/info_test.go
@@ -0,0 +1,32 @@
+package main_test
+
+import (
+ "testing"
+
+ "github.com/boltdb/bolt"
+ . "github.com/boltdb/bolt/cmd/bolt"
+ "github.com/stretchr/testify/assert"
+)
+
+// Ensure that a database info can be printed.
+func TestInfo(t *testing.T) {
+ SetTestMode(true)
+ open(func(db *bolt.DB, path string) {
+ db.Update(func(tx *bolt.Tx) error {
+ tx.CreateBucket([]byte("widgets"))
+ b := tx.Bucket([]byte("widgets"))
+ b.Put([]byte("foo"), []byte("0000"))
+ return nil
+ })
+ db.Close()
+ output := run("info", path)
+ assert.Equal(t, `Page Size: 4096`, output)
+ })
+}
+
+// Ensure that an error is reported if the database is not found.
+func TestInfo_NotFound(t *testing.T) {
+ SetTestMode(true)
+ output := run("info", "no/such/db")
+ assert.Equal(t, "stat no/such/db: no such file or directory", output)
+}
diff --git a/cmd/bolt/main.go b/cmd/bolt/main.go
index 1af2636..3397042 100644
--- a/cmd/bolt/main.go
+++ b/cmd/bolt/main.go
@@ -26,6 +26,14 @@ func NewApp() *cli.App {
app.Version = fmt.Sprintf("0.1.0 (%s %s)", branch, commit)
app.Commands = []cli.Command{
{
+ Name: "info",
+ Usage: "Print basic information about a database",
+ Action: func(c *cli.Context) {
+ path := c.Args().Get(0)
+ Info(path)
+ },
+ },
+ {
Name: "get",
Usage: "Retrieve a value for given key in a bucket",
Action: func(c *cli.Context) {
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 d9ab1ad..5ad581e 100644
--- a/node.go
+++ b/node.go
@@ -96,6 +96,7 @@ 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)
_assert(len(oldKey) > 0, "put: zero-length old key")
_assert(len(newKey) > 0, "put: zero-length new key")
@@ -284,6 +285,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)
@@ -314,6 +316,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)
}
diff --git a/node_test.go b/node_test.go
index f639376..1393e2a 100644
--- a/node_test.go
+++ b/node_test.go
@@ -9,7 +9,7 @@ import (
// Ensure that a node can insert a key/value.
func TestNode_put(t *testing.T) {
- n := &node{inodes: make(inodes, 0)}
+ n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
n.put([]byte("baz"), []byte("baz"), []byte("2"), 0, 0)
n.put([]byte("foo"), []byte("foo"), []byte("0"), 0, 0)
n.put([]byte("bar"), []byte("bar"), []byte("1"), 0, 0)
@@ -58,7 +58,7 @@ func TestNode_read_LeafPage(t *testing.T) {
// Ensure that a node can serialize into a leaf page.
func TestNode_write_LeafPage(t *testing.T) {
// Create a node.
- n := &node{isLeaf: true, inodes: make(inodes, 0)}
+ n := &node{isLeaf: true, inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
n.put([]byte("susy"), []byte("susy"), []byte("que"), 0, 0)
n.put([]byte("ricki"), []byte("ricki"), []byte("lake"), 0, 0)
n.put([]byte("john"), []byte("john"), []byte("johnson"), 0, 0)
@@ -85,7 +85,7 @@ func TestNode_write_LeafPage(t *testing.T) {
// Ensure that a node can split into appropriate subgroups.
func TestNode_split(t *testing.T) {
// Create a node.
- n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{}}}
+ n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)
@@ -104,7 +104,7 @@ func TestNode_split(t *testing.T) {
// Ensure that a page with the minimum number of inodes just returns a single node.
func TestNode_split_MinKeys(t *testing.T) {
// Create a node.
- n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{}}}
+ n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
@@ -116,7 +116,7 @@ func TestNode_split_MinKeys(t *testing.T) {
// Ensure that a node that has keys that all fit on a page just returns one leaf.
func TestNode_split_SinglePage(t *testing.T) {
// Create a node.
- n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{}}}
+ n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
n.put([]byte("00000001"), []byte("00000001"), []byte("0123456701234567"), 0, 0)
n.put([]byte("00000002"), []byte("00000002"), []byte("0123456701234567"), 0, 0)
n.put([]byte("00000003"), []byte("00000003"), []byte("0123456701234567"), 0, 0)