aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Johnson <benbjohnson@yahoo.com>2014-05-15 14:25:29 -0600
committerBen Johnson <benbjohnson@yahoo.com>2014-05-15 14:25:29 -0600
commitcc6302194b6134806669cbeafcaf799fa0ea040c (patch)
tree7ca8faaae8099222c0c7964eee3e0a95dea5bd51
parentMerge pull request #165 from benbjohnson/strict-mode (diff)
parentChange verbiage, fix node test. (diff)
downloaddedo-cc6302194b6134806669cbeafcaf799fa0ea040c.tar.gz
dedo-cc6302194b6134806669cbeafcaf799fa0ea040c.tar.xz
Merge pull request #166 from benbjohnson/fill-percent
Add option to adjust fill percentage.
-rw-r--r--cmd/bolt/bench.go2
-rw-r--r--cmd/bolt/main.go3
-rw-r--r--db.go16
-rw-r--r--node.go10
-rw-r--r--node_test.go8
5 files changed, 32 insertions, 7 deletions
diff --git a/cmd/bolt/bench.go b/cmd/bolt/bench.go
index e8bf376..6379144 100644
--- a/cmd/bolt/bench.go
+++ b/cmd/bolt/bench.go
@@ -46,6 +46,7 @@ func Bench(options *BenchOptions) {
fatal(err)
return
}
+ db.FillPercent = options.FillPercent
defer db.Close()
// Enable streaming stats.
@@ -280,6 +281,7 @@ type BenchOptions struct {
MemProfile string
BlockProfile string
StatsInterval time.Duration
+ FillPercent float64
Clean bool
}
diff --git a/cmd/bolt/main.go b/cmd/bolt/main.go
index 66c33d2..44ba5a1 100644
--- a/cmd/bolt/main.go
+++ b/cmd/bolt/main.go
@@ -8,6 +8,7 @@ import (
"os"
"time"
+ "github.com/boltdb/bolt"
"github.com/codegangsta/cli"
)
@@ -114,6 +115,7 @@ func NewApp() *cli.App {
&cli.StringFlag{Name: "memprofile", Usage: "Memory profile output path"},
&cli.StringFlag{Name: "blockprofile", Usage: "Block profile output path"},
&cli.StringFlag{Name: "stats-interval", Value: "0s", Usage: "Continuous stats interval"},
+ &cli.Float64Flag{Name: "fill-percent", Value: bolt.DefaultFillPercent, Usage: "Fill percentage"},
&cli.BoolFlag{Name: "work", Usage: "Print the temp db and do not delete on exit"},
},
Action: func(c *cli.Context) {
@@ -134,6 +136,7 @@ func NewApp() *cli.App {
MemProfile: c.String("memprofile"),
BlockProfile: c.String("blockprofile"),
StatsInterval: statsInterval,
+ FillPercent: c.Float64("fill-percent"),
Clean: !c.Bool("work"),
})
},
diff --git a/db.go b/db.go
index 758c911..c768ce3 100644
--- a/db.go
+++ b/db.go
@@ -24,6 +24,15 @@ const version = 2
// Represents a marker value to indicate that a file is a Bolt DB.
const magic uint32 = 0xED0CDAED
+const (
+ minFillPercent = 0.1
+ maxFillPercent = 1.0
+)
+
+// DefaultFillPercent is the percentage that split pages are filled.
+// This value can be changed by setting DB.FillPercent.
+const DefaultFillPercent = 0.5
+
var (
// ErrDatabaseNotOpen is returned when a DB instance is accessed before it
// is opened or after it is closed.
@@ -54,6 +63,11 @@ type DB struct {
// debugging purposes.
StrictMode bool
+ // Sets the threshold for filling nodes when they split. By default,
+ // the database will fill to 50% but it can be useful to increase this
+ // amount if you know that your write workloads are mostly append-only.
+ FillPercent float64
+
path string
file *os.File
data []byte
@@ -94,7 +108,7 @@ func (db *DB) String() string {
// Open creates and opens a database at the given path.
// If the file does not exist then it will be created automatically.
func Open(path string, mode os.FileMode) (*DB, error) {
- var db = &DB{opened: true}
+ var db = &DB{opened: true, FillPercent: DefaultFillPercent}
// Open data file and separate sync handler for metadata writes.
db.path = path
diff --git a/node.go b/node.go
index 5ad581e..e345d7f 100644
--- a/node.go
+++ b/node.go
@@ -215,8 +215,14 @@ func (n *node) split(pageSize int) []*node {
return nodes
}
- // Set fill threshold to 50%.
- threshold := pageSize / 2
+ // Determine the threshold before starting a new node.
+ var fillPercent = n.bucket.tx.db.FillPercent
+ if fillPercent < minFillPercent {
+ fillPercent = minFillPercent
+ } else if fillPercent > maxFillPercent {
+ fillPercent = maxFillPercent
+ }
+ threshold := int(float64(pageSize) * fillPercent)
// Group into smaller pages and target a given fill size.
size := pageHeaderSize
diff --git a/node_test.go b/node_test.go
index 1393e2a..b85e18f 100644
--- a/node_test.go
+++ b/node_test.go
@@ -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), bucket: &Bucket{tx: &Tx{meta: &meta{pgid: 1}}}}
+ n := &node{isLeaf: true, inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, 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{meta: &meta{pgid: 1}}}}
+ n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, 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{meta: &meta{pgid: 1}}}}
+ n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, 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{meta: &meta{pgid: 1}}}}
+ n := &node{inodes: make(inodes, 0), bucket: &Bucket{tx: &Tx{db: &DB{}, 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)