Browse Source

godep: update bolt

Xiang Li 10 years ago
parent
commit
8156a58ba3
23 changed files with 356 additions and 4779 deletions
  1. 2 2
      Godeps/Godeps.json
  2. 7 43
      Godeps/_workspace/src/github.com/boltdb/bolt/Makefile
  3. 135 19
      Godeps/_workspace/src/github.com/boltdb/bolt/README.md
  4. 0 138
      Godeps/_workspace/src/github.com/boltdb/bolt/batch.go
  5. 0 170
      Godeps/_workspace/src/github.com/boltdb/bolt/batch_benchmark_test.go
  6. 0 148
      Godeps/_workspace/src/github.com/boltdb/bolt/batch_example_test.go
  7. 0 167
      Godeps/_workspace/src/github.com/boltdb/bolt/batch_test.go
  8. 0 36
      Godeps/_workspace/src/github.com/boltdb/bolt/bolt_test.go
  9. 0 11
      Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix.go
  10. 0 11
      Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix_solaris.go
  11. 0 1169
      Godeps/_workspace/src/github.com/boltdb/bolt/bucket_test.go
  12. 4 1
      Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main.go
  13. 0 145
      Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main_test.go
  14. 0 554
      Godeps/_workspace/src/github.com/boltdb/bolt/cursor_test.go
  15. 195 9
      Godeps/_workspace/src/github.com/boltdb/bolt/db.go
  16. 0 907
      Godeps/_workspace/src/github.com/boltdb/bolt/db_test.go
  17. 0 156
      Godeps/_workspace/src/github.com/boltdb/bolt/freelist_test.go
  18. 0 156
      Godeps/_workspace/src/github.com/boltdb/bolt/node_test.go
  19. 0 72
      Godeps/_workspace/src/github.com/boltdb/bolt/page_test.go
  20. 0 79
      Godeps/_workspace/src/github.com/boltdb/bolt/quick_test.go
  21. 0 327
      Godeps/_workspace/src/github.com/boltdb/bolt/simulation_test.go
  22. 13 3
      Godeps/_workspace/src/github.com/boltdb/bolt/tx.go
  23. 0 456
      Godeps/_workspace/src/github.com/boltdb/bolt/tx_test.go

+ 2 - 2
Godeps/Godeps.json

@@ -24,8 +24,8 @@
 		},
 		{
 			"ImportPath": "github.com/boltdb/bolt",
-			"Comment": "v1.1.0-19-g0b00eff",
-			"Rev": "0b00effdd7a8270ebd91c24297e51643e370dd52"
+			"Comment": "v1.1.0-65-gee4a088",
+			"Rev": "ee4a0888a9abe7eefe5a0992ca4cb06864839873"
 		},
 		{
 			"ImportPath": "github.com/cheggaaa/pb",

+ 7 - 43
Godeps/_workspace/src/github.com/boltdb/bolt/Makefile

@@ -1,54 +1,18 @@
-TEST=.
-BENCH=.
-COVERPROFILE=/tmp/c.out
 BRANCH=`git rev-parse --abbrev-ref HEAD`
 COMMIT=`git rev-parse --short HEAD`
 GOLDFLAGS="-X main.branch $(BRANCH) -X main.commit $(COMMIT)"
 
 default: build
 
-bench:
-	go test -v -test.run=NOTHINCONTAINSTHIS -test.bench=$(BENCH)
-
-# http://cloc.sourceforge.net/
-cloc:
-	@cloc --not-match-f='Makefile|_test.go' .
-
-cover: fmt
-	go test -coverprofile=$(COVERPROFILE) -test.run=$(TEST) $(COVERFLAG) .
-	go tool cover -html=$(COVERPROFILE)
-	rm $(COVERPROFILE)
-
-cpuprofile: fmt
-	@go test -c
-	@./bolt.test -test.v -test.run=$(TEST) -test.cpuprofile cpu.prof
+race:
+	@go test -v -race -test.run="TestSimulate_(100op|1000op)"
 
 # go get github.com/kisielk/errcheck
 errcheck:
-	@echo "=== errcheck ==="
-	@errcheck github.com/boltdb/bolt
+	@errcheck -ignorepkg=bytes -ignore=os:Remove github.com/boltdb/bolt
 
-fmt:
-	@go fmt ./...
-
-get:
-	@go get -d ./...
-
-build: get
-	@mkdir -p bin
-	@go build -ldflags=$(GOLDFLAGS) -a -o bin/bolt ./cmd/bolt
-
-test: fmt
-	@go get github.com/stretchr/testify/assert
-	@echo "=== TESTS ==="
-	@go test -v -cover -test.run=$(TEST)
-	@echo ""
-	@echo ""
-	@echo "=== CLI ==="
-	@go test -v -test.run=$(TEST) ./cmd/bolt
-	@echo ""
-	@echo ""
-	@echo "=== RACE DETECTOR ==="
-	@go test -v -race -test.run="TestSimulate_(100op|1000op)"
+test: 
+	@go test -v -cover .
+	@go test -v ./cmd/bolt
 
-.PHONY: bench cloc cover cpuprofile fmt memprofile test
+.PHONY: fmt test

+ 135 - 19
Godeps/_workspace/src/github.com/boltdb/bolt/README.md

@@ -1,7 +1,7 @@
-Bolt [![Build Status](https://drone.io/github.com/boltdb/bolt/status.png)](https://drone.io/github.com/boltdb/bolt/latest) [![Coverage Status](https://coveralls.io/repos/boltdb/bolt/badge.png?branch=master)](https://coveralls.io/r/boltdb/bolt?branch=master) [![GoDoc](https://godoc.org/github.com/boltdb/bolt?status.png)](https://godoc.org/github.com/boltdb/bolt) ![Version](http://img.shields.io/badge/version-1.0-green.png)
+Bolt [![Build Status](https://drone.io/github.com/boltdb/bolt/status.png)](https://drone.io/github.com/boltdb/bolt/latest) [![Coverage Status](https://coveralls.io/repos/boltdb/bolt/badge.svg?branch=master)](https://coveralls.io/r/boltdb/bolt?branch=master) [![GoDoc](https://godoc.org/github.com/boltdb/bolt?status.svg)](https://godoc.org/github.com/boltdb/bolt) ![Version](https://img.shields.io/badge/version-1.0-green.svg)
 ====
 
-Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas] 
+Bolt is a pure Go key/value store inspired by [Howard Chu's][hyc_symas]
 [LMDB project][lmdb]. The goal of the project is to provide a simple,
 fast, and reliable database for projects that don't require a full database
 server such as Postgres or MySQL.
@@ -13,7 +13,6 @@ and setting values. That's it.
 [hyc_symas]: https://twitter.com/hyc_symas
 [lmdb]: http://symas.com/mdb/
 
-
 ## Project Status
 
 Bolt is stable and the API is fixed. Full unit test coverage and randomized
@@ -22,6 +21,36 @@ Bolt is currently in high-load production environments serving databases as
 large as 1TB. Many companies such as Shopify and Heroku use Bolt-backed
 services every day.
 
+## Table of Contents
+
+- [Getting Started](#getting-started)
+  - [Installing](#installing)
+  - [Opening a database](#opening-a-database)
+  - [Transactions](#transactions)
+    - [Read-write transactions](#read-write-transactions)
+    - [Read-only transactions](#read-only-transactions)
+    - [Batch read-write transactions](#batch-read-write-transactions)
+    - [Managing transactions manually](#managing-transactions-manually)
+  - [Using buckets](#using-buckets)
+  - [Using key/value pairs](#using-keyvalue-pairs)
+  - [Autoincrementing integer for the bucket](#autoincrementing-integer-for-the-bucket)
+  - [Iterating over keys](#iterating-over-keys)
+    - [Prefix scans](#prefix-scans)
+    - [Range scans](#range-scans)
+    - [ForEach()](#foreach)
+  - [Nested buckets](#nested-buckets)
+  - [Database backups](#database-backups)
+  - [Statistics](#statistics)
+  - [Read-Only Mode](#read-only-mode)
+  - [Mobile Use (iOS/Android)](#mobile-use-iosandroid)
+- [Resources](#resources)
+- [Comparison with other databases](#comparison-with-other-databases)
+  - [Postgres, MySQL, & other relational databases](#postgres-mysql--other-relational-databases)
+  - [LevelDB, RocksDB](#leveldb-rocksdb)
+  - [LMDB](#lmdb)
+- [Caveats & Limitations](#caveats--limitations)
+- [Reading the Source](#reading-the-source)
+- [Other Projects Using Bolt](#other-projects-using-bolt)
 
 ## Getting Started
 
@@ -269,7 +298,7 @@ then you must use `copy()` to copy it to another byte slice.
 
 
 ### Autoincrementing integer for the bucket
-By using the NextSequence() function, you can let Bolt determine a sequence
+By using the `NextSequence()` function, you can let Bolt determine a sequence
 which can be used as the unique identifier for your key/value pairs. See the
 example below.
 
@@ -309,7 +338,6 @@ type User struct {
     ID int
     ...
 }
-
 ```
 
 ### Iterating over keys
@@ -320,7 +348,9 @@ iteration over these keys extremely fast. To iterate over keys we'll use a
 
 ```go
 db.View(func(tx *bolt.Tx) error {
+	// Assume bucket exists and has keys
 	b := tx.Bucket([]byte("MyBucket"))
+
 	c := b.Cursor()
 
 	for k, v := c.First(); k != nil; k, v = c.Next() {
@@ -344,10 +374,15 @@ Next()   Move to the next key.
 Prev()   Move to the previous key.
 ```
 
-When you have iterated to the end of the cursor then `Next()` will return `nil`.
-You must seek to a position using `First()`, `Last()`, or `Seek()` before
-calling `Next()` or `Prev()`. If you do not seek to a position then these
-functions will return `nil`.
+Each of those functions has a return signature of `(key []byte, value []byte)`.
+When you have iterated to the end of the cursor then `Next()` will return a
+`nil` key.  You must seek to a position using `First()`, `Last()`, or `Seek()`
+before calling `Next()` or `Prev()`. If you do not seek to a position then
+these functions will return a `nil` key.
+
+During iteration, if the key is non-`nil` but the value is `nil`, that means
+the key refers to a bucket rather than a value.  Use `Bucket.Bucket()` to
+access the sub-bucket.
 
 
 #### Prefix scans
@@ -356,6 +391,7 @@ To iterate over a key prefix, you can combine `Seek()` and `bytes.HasPrefix()`:
 
 ```go
 db.View(func(tx *bolt.Tx) error {
+	// Assume bucket exists and has keys
 	c := tx.Bucket([]byte("MyBucket")).Cursor()
 
 	prefix := []byte("1234")
@@ -375,7 +411,7 @@ date range like this:
 
 ```go
 db.View(func(tx *bolt.Tx) error {
-	// Assume our events bucket has RFC3339 encoded time keys.
+	// Assume our events bucket exists and has RFC3339 encoded time keys.
 	c := tx.Bucket([]byte("Events")).Cursor()
 
 	// Our time range spans the 90's decade.
@@ -399,7 +435,9 @@ all the keys in a bucket:
 
 ```go
 db.View(func(tx *bolt.Tx) error {
+	// Assume bucket exists and has keys
 	b := tx.Bucket([]byte("MyBucket"))
+	
 	b.ForEach(func(k, v []byte) error {
 		fmt.Printf("key=%s, value=%s\n", k, v)
 		return nil
@@ -430,7 +468,7 @@ your other database reads and writes.
 
 By default, it will use a regular file handle which will utilize the operating
 system's page cache. See the [`Tx`](https://godoc.org/github.com/boltdb/bolt#Tx)
-documentation for information about optimizing for larger-than-RAM datasets. 
+documentation for information about optimizing for larger-than-RAM datasets.
 
 One common use case is to backup over HTTP so you can use tools like `cURL` to
 do database backups:
@@ -512,6 +550,84 @@ if err != nil {
 }
 ```
 
+### Mobile Use (iOS/Android)
+
+Bolt is able to run on mobile devices by leveraging the binding feature of the
+[gomobile](https://github.com/golang/mobile) tool. Create a struct that will
+contain your database logic and a reference to a `*bolt.DB` with a initializing
+contstructor that takes in a filepath where the database file will be stored.
+Neither Android nor iOS require extra permissions or cleanup from using this method.
+
+```go
+func NewBoltDB(filepath string) *BoltDB {
+	db, err := bolt.Open(filepath+"/demo.db", 0600, nil)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	return &BoltDB{db}
+}
+
+type BoltDB struct {
+	db *bolt.DB
+	...
+}
+
+func (b *BoltDB) Path() string {
+	return b.db.Path()
+}
+
+func (b *BoltDB) Close() {
+	b.db.Close()
+}
+```
+
+Database logic should be defined as methods on this wrapper struct.
+
+To initialize this struct from the native language (both platforms now sync
+their local storage to the cloud. These snippets disable that functionality for the
+database file):
+
+#### Android
+
+```java
+String path;
+if (android.os.Build.VERSION.SDK_INT >=android.os.Build.VERSION_CODES.LOLLIPOP){
+    path = getNoBackupFilesDir().getAbsolutePath();
+} else{
+    path = getFilesDir().getAbsolutePath();
+}
+Boltmobiledemo.BoltDB boltDB = Boltmobiledemo.NewBoltDB(path)
+```
+
+#### iOS
+
+```objc
+- (void)demo {
+    NSString* path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
+                                                          NSUserDomainMask,
+                                                          YES) objectAtIndex:0];
+	GoBoltmobiledemoBoltDB * demo = GoBoltmobiledemoNewBoltDB(path);
+	[self addSkipBackupAttributeToItemAtPath:demo.path];
+	//Some DB Logic would go here
+	[demo close];
+}
+
+- (BOOL)addSkipBackupAttributeToItemAtPath:(NSString *) filePathString
+{
+    NSURL* URL= [NSURL fileURLWithPath: filePathString];
+    assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
+    
+    NSError *error = nil;
+    BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
+                                  forKey: NSURLIsExcludedFromBackupKey error: &error];
+    if(!success){
+        NSLog(@"Error excluding %@ from backup %@", [URL lastPathComponent], error);
+    }
+    return success;
+}
+
+```
 
 ## Resources
 
@@ -583,9 +699,8 @@ It's important to pick the right tool for the job and Bolt is no exception.
 Here are a few things to note when evaluating and using Bolt:
 
 * Bolt is good for read intensive workloads. Sequential write performance is
-  also fast but random writes can be slow. You can add a write-ahead log or
-  [transaction coalescer](https://github.com/boltdb/coalescer) in front of Bolt
-  to mitigate this issue.
+  also fast but random writes can be slow. You can use `DB.Batch()` or add a
+  write-ahead log to help mitigate this issue.
 
 * Bolt uses a B+tree internally so there can be a lot of random page access.
   SSDs provide a significant performance boost over spinning disks.
@@ -621,7 +736,7 @@ Here are a few things to note when evaluating and using Bolt:
 
 * The data structures in the Bolt database are memory mapped so the data file
   will be endian specific. This means that you cannot copy a Bolt file from a
-  little endian machine to a big endian machine and have it work. For most 
+  little endian machine to a big endian machine and have it work. For most
   users this is not a concern since most modern CPUs are little endian.
 
 * Because of the way pages are laid out on disk, Bolt cannot truncate data files
@@ -696,21 +811,21 @@ Below is a list of public, open source projects that use Bolt:
 * [Skybox Analytics](https://github.com/skybox/skybox) - A standalone funnel analysis tool for web analytics.
 * [Scuttlebutt](https://github.com/benbjohnson/scuttlebutt) - Uses Bolt to store and process all Twitter mentions of GitHub projects.
 * [Wiki](https://github.com/peterhellberg/wiki) - A tiny wiki using Goji, BoltDB and Blackfriday.
-* [ChainStore](https://github.com/nulayer/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations.
+* [ChainStore](https://github.com/pressly/chainstore) - Simple key-value interface to a variety of storage engines organized as a chain of operations.
 * [MetricBase](https://github.com/msiebuhr/MetricBase) - Single-binary version of Graphite.
 * [Gitchain](https://github.com/gitchain/gitchain) - Decentralized, peer-to-peer Git repositories aka "Git meets Bitcoin".
 * [event-shuttle](https://github.com/sclasen/event-shuttle) - A Unix system service to collect and reliably deliver messages to Kafka.
 * [ipxed](https://github.com/kelseyhightower/ipxed) - Web interface and api for ipxed.
 * [BoltStore](https://github.com/yosssi/boltstore) - Session store using Bolt.
-* [photosite/session](http://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site.
+* [photosite/session](https://godoc.org/bitbucket.org/kardianos/photosite/session) - Sessions for a photo viewing site.
 * [LedisDB](https://github.com/siddontang/ledisdb) - A high performance NoSQL, using Bolt as optional storage.
 * [ipLocator](https://github.com/AndreasBriese/ipLocator) - A fast ip-geo-location-server using bolt with bloom filters.
 * [cayley](https://github.com/google/cayley) - Cayley is an open-source graph database using Bolt as optional backend.
 * [bleve](http://www.blevesearch.com/) - A pure Go search engine similar to ElasticSearch that uses Bolt as the default storage backend.
 * [tentacool](https://github.com/optiflows/tentacool) - REST api server to manage system stuff (IP, DNS, Gateway...) on a linux server.
 * [SkyDB](https://github.com/skydb/sky) - Behavioral analytics database.
-* [Seaweed File System](https://github.com/chrislusf/weed-fs) - Highly scalable distributed key~file system with O(1) disk read.
-* [InfluxDB](http://influxdb.com) - Scalable datastore for metrics, events, and real-time analytics.
+* [Seaweed File System](https://github.com/chrislusf/seaweedfs) - Highly scalable distributed key~file system with O(1) disk read.
+* [InfluxDB](https://influxdata.com) - Scalable datastore for metrics, events, and real-time analytics.
 * [Freehold](http://tshannon.bitbucket.org/freehold/) - An open, secure, and lightweight platform for your files and data.
 * [Prometheus Annotation Server](https://github.com/oliver006/prom_annotation_server) - Annotation server for PromDash & Prometheus service monitoring system.
 * [Consul](https://github.com/hashicorp/consul) - Consul is service discovery and configuration made easy. Distributed, highly available, and datacenter-aware.
@@ -720,5 +835,6 @@ Below is a list of public, open source projects that use Bolt:
   backed by boltdb.
 * [buckets](https://github.com/joyrexus/buckets) - a bolt wrapper streamlining
   simple tx and key scans.
+* [Request Baskets](https://github.com/darklynx/request-baskets) - A web service to collect arbitrary HTTP requests and inspect them via REST API or simple web UI, similar to [RequestBin](http://requestb.in/) service
 
 If you are using Bolt in a project please send a pull request to add it to the list.

+ 0 - 138
Godeps/_workspace/src/github.com/boltdb/bolt/batch.go

@@ -1,138 +0,0 @@
-package bolt
-
-import (
-	"errors"
-	"fmt"
-	"sync"
-	"time"
-)
-
-// Batch calls fn as part of a batch. It behaves similar to Update,
-// except:
-//
-// 1. concurrent Batch calls can be combined into a single Bolt
-// transaction.
-//
-// 2. the function passed to Batch may be called multiple times,
-// regardless of whether it returns error or not.
-//
-// This means that Batch function side effects must be idempotent and
-// take permanent effect only after a successful return is seen in
-// caller.
-//
-// The maximum batch size and delay can be adjusted with DB.MaxBatchSize
-// and DB.MaxBatchDelay, respectively.
-//
-// Batch is only useful when there are multiple goroutines calling it.
-func (db *DB) Batch(fn func(*Tx) error) error {
-	errCh := make(chan error, 1)
-
-	db.batchMu.Lock()
-	if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) {
-		// There is no existing batch, or the existing batch is full; start a new one.
-		db.batch = &batch{
-			db: db,
-		}
-		db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger)
-	}
-	db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh})
-	if len(db.batch.calls) >= db.MaxBatchSize {
-		// wake up batch, it's ready to run
-		go db.batch.trigger()
-	}
-	db.batchMu.Unlock()
-
-	err := <-errCh
-	if err == trySolo {
-		err = db.Update(fn)
-	}
-	return err
-}
-
-type call struct {
-	fn  func(*Tx) error
-	err chan<- error
-}
-
-type batch struct {
-	db    *DB
-	timer *time.Timer
-	start sync.Once
-	calls []call
-}
-
-// trigger runs the batch if it hasn't already been run.
-func (b *batch) trigger() {
-	b.start.Do(b.run)
-}
-
-// run performs the transactions in the batch and communicates results
-// back to DB.Batch.
-func (b *batch) run() {
-	b.db.batchMu.Lock()
-	b.timer.Stop()
-	// Make sure no new work is added to this batch, but don't break
-	// other batches.
-	if b.db.batch == b {
-		b.db.batch = nil
-	}
-	b.db.batchMu.Unlock()
-
-retry:
-	for len(b.calls) > 0 {
-		var failIdx = -1
-		err := b.db.Update(func(tx *Tx) error {
-			for i, c := range b.calls {
-				if err := safelyCall(c.fn, tx); err != nil {
-					failIdx = i
-					return err
-				}
-			}
-			return nil
-		})
-
-		if failIdx >= 0 {
-			// take the failing transaction out of the batch. it's
-			// safe to shorten b.calls here because db.batch no longer
-			// points to us, and we hold the mutex anyway.
-			c := b.calls[failIdx]
-			b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1]
-			// tell the submitter re-run it solo, continue with the rest of the batch
-			c.err <- trySolo
-			continue retry
-		}
-
-		// pass success, or bolt internal errors, to all callers
-		for _, c := range b.calls {
-			if c.err != nil {
-				c.err <- err
-			}
-		}
-		break retry
-	}
-}
-
-// trySolo is a special sentinel error value used for signaling that a
-// transaction function should be re-run. It should never be seen by
-// callers.
-var trySolo = errors.New("batch function returned an error and should be re-run solo")
-
-type panicked struct {
-	reason interface{}
-}
-
-func (p panicked) Error() string {
-	if err, ok := p.reason.(error); ok {
-		return err.Error()
-	}
-	return fmt.Sprintf("panic: %v", p.reason)
-}
-
-func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
-	defer func() {
-		if p := recover(); p != nil {
-			err = panicked{p}
-		}
-	}()
-	return fn(tx)
-}

+ 0 - 170
Godeps/_workspace/src/github.com/boltdb/bolt/batch_benchmark_test.go

@@ -1,170 +0,0 @@
-package bolt_test
-
-import (
-	"bytes"
-	"encoding/binary"
-	"errors"
-	"hash/fnv"
-	"sync"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-func validateBatchBench(b *testing.B, db *TestDB) {
-	var rollback = errors.New("sentinel error to cause rollback")
-	validate := func(tx *bolt.Tx) error {
-		bucket := tx.Bucket([]byte("bench"))
-		h := fnv.New32a()
-		buf := make([]byte, 4)
-		for id := uint32(0); id < 1000; id++ {
-			binary.LittleEndian.PutUint32(buf, id)
-			h.Reset()
-			h.Write(buf[:])
-			k := h.Sum(nil)
-			v := bucket.Get(k)
-			if v == nil {
-				b.Errorf("not found id=%d key=%x", id, k)
-				continue
-			}
-			if g, e := v, []byte("filler"); !bytes.Equal(g, e) {
-				b.Errorf("bad value for id=%d key=%x: %s != %q", id, k, g, e)
-			}
-			if err := bucket.Delete(k); err != nil {
-				return err
-			}
-		}
-		// should be empty now
-		c := bucket.Cursor()
-		for k, v := c.First(); k != nil; k, v = c.Next() {
-			b.Errorf("unexpected key: %x = %q", k, v)
-		}
-		return rollback
-	}
-	if err := db.Update(validate); err != nil && err != rollback {
-		b.Error(err)
-	}
-}
-
-func BenchmarkDBBatchAutomatic(b *testing.B) {
-	db := NewTestDB()
-	defer db.Close()
-	db.MustCreateBucket([]byte("bench"))
-
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		start := make(chan struct{})
-		var wg sync.WaitGroup
-
-		for round := 0; round < 1000; round++ {
-			wg.Add(1)
-
-			go func(id uint32) {
-				defer wg.Done()
-				<-start
-
-				h := fnv.New32a()
-				buf := make([]byte, 4)
-				binary.LittleEndian.PutUint32(buf, id)
-				h.Write(buf[:])
-				k := h.Sum(nil)
-				insert := func(tx *bolt.Tx) error {
-					b := tx.Bucket([]byte("bench"))
-					return b.Put(k, []byte("filler"))
-				}
-				if err := db.Batch(insert); err != nil {
-					b.Error(err)
-					return
-				}
-			}(uint32(round))
-		}
-		close(start)
-		wg.Wait()
-	}
-
-	b.StopTimer()
-	validateBatchBench(b, db)
-}
-
-func BenchmarkDBBatchSingle(b *testing.B) {
-	db := NewTestDB()
-	defer db.Close()
-	db.MustCreateBucket([]byte("bench"))
-
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		start := make(chan struct{})
-		var wg sync.WaitGroup
-
-		for round := 0; round < 1000; round++ {
-			wg.Add(1)
-			go func(id uint32) {
-				defer wg.Done()
-				<-start
-
-				h := fnv.New32a()
-				buf := make([]byte, 4)
-				binary.LittleEndian.PutUint32(buf, id)
-				h.Write(buf[:])
-				k := h.Sum(nil)
-				insert := func(tx *bolt.Tx) error {
-					b := tx.Bucket([]byte("bench"))
-					return b.Put(k, []byte("filler"))
-				}
-				if err := db.Update(insert); err != nil {
-					b.Error(err)
-					return
-				}
-			}(uint32(round))
-		}
-		close(start)
-		wg.Wait()
-	}
-
-	b.StopTimer()
-	validateBatchBench(b, db)
-}
-
-func BenchmarkDBBatchManual10x100(b *testing.B) {
-	db := NewTestDB()
-	defer db.Close()
-	db.MustCreateBucket([]byte("bench"))
-
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		start := make(chan struct{})
-		var wg sync.WaitGroup
-
-		for major := 0; major < 10; major++ {
-			wg.Add(1)
-			go func(id uint32) {
-				defer wg.Done()
-				<-start
-
-				insert100 := func(tx *bolt.Tx) error {
-					h := fnv.New32a()
-					buf := make([]byte, 4)
-					for minor := uint32(0); minor < 100; minor++ {
-						binary.LittleEndian.PutUint32(buf, uint32(id*100+minor))
-						h.Reset()
-						h.Write(buf[:])
-						k := h.Sum(nil)
-						b := tx.Bucket([]byte("bench"))
-						if err := b.Put(k, []byte("filler")); err != nil {
-							return err
-						}
-					}
-					return nil
-				}
-				if err := db.Update(insert100); err != nil {
-					b.Fatal(err)
-				}
-			}(uint32(major))
-		}
-		close(start)
-		wg.Wait()
-	}
-
-	b.StopTimer()
-	validateBatchBench(b, db)
-}

+ 0 - 148
Godeps/_workspace/src/github.com/boltdb/bolt/batch_example_test.go

@@ -1,148 +0,0 @@
-package bolt_test
-
-import (
-	"encoding/binary"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"math/rand"
-	"net/http"
-	"net/http/httptest"
-	"os"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-// Set this to see how the counts are actually updated.
-const verbose = false
-
-// Counter updates a counter in Bolt for every URL path requested.
-type counter struct {
-	db *bolt.DB
-}
-
-func (c counter) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
-	// Communicates the new count from a successful database
-	// transaction.
-	var result uint64
-
-	increment := func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucketIfNotExists([]byte("hits"))
-		if err != nil {
-			return err
-		}
-		key := []byte(req.URL.String())
-		// Decode handles key not found for us.
-		count := decode(b.Get(key)) + 1
-		b.Put(key, encode(count))
-		// All good, communicate new count.
-		result = count
-		return nil
-	}
-	if err := c.db.Batch(increment); err != nil {
-		http.Error(rw, err.Error(), 500)
-		return
-	}
-
-	if verbose {
-		log.Printf("server: %s: %d", req.URL.String(), result)
-	}
-
-	rw.Header().Set("Content-Type", "application/octet-stream")
-	fmt.Fprintf(rw, "%d\n", result)
-}
-
-func client(id int, base string, paths []string) error {
-	// Process paths in random order.
-	rng := rand.New(rand.NewSource(int64(id)))
-	permutation := rng.Perm(len(paths))
-
-	for i := range paths {
-		path := paths[permutation[i]]
-		resp, err := http.Get(base + path)
-		if err != nil {
-			return err
-		}
-		defer resp.Body.Close()
-		buf, err := ioutil.ReadAll(resp.Body)
-		if err != nil {
-			return err
-		}
-		if verbose {
-			log.Printf("client: %s: %s", path, buf)
-		}
-	}
-	return nil
-}
-
-func ExampleDB_Batch() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Start our web server
-	count := counter{db}
-	srv := httptest.NewServer(count)
-	defer srv.Close()
-
-	// Decrease the batch size to make things more interesting.
-	db.MaxBatchSize = 3
-
-	// Get every path multiple times concurrently.
-	const clients = 10
-	paths := []string{
-		"/foo",
-		"/bar",
-		"/baz",
-		"/quux",
-		"/thud",
-		"/xyzzy",
-	}
-	errors := make(chan error, clients)
-	for i := 0; i < clients; i++ {
-		go func(id int) {
-			errors <- client(id, srv.URL, paths)
-		}(i)
-	}
-	// Check all responses to make sure there's no error.
-	for i := 0; i < clients; i++ {
-		if err := <-errors; err != nil {
-			fmt.Printf("client error: %v", err)
-			return
-		}
-	}
-
-	// Check the final result
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("hits"))
-		c := b.Cursor()
-		for k, v := c.First(); k != nil; k, v = c.Next() {
-			fmt.Printf("hits to %s: %d\n", k, decode(v))
-		}
-		return nil
-	})
-
-	// Output:
-	// hits to /bar: 10
-	// hits to /baz: 10
-	// hits to /foo: 10
-	// hits to /quux: 10
-	// hits to /thud: 10
-	// hits to /xyzzy: 10
-}
-
-// encode marshals a counter.
-func encode(n uint64) []byte {
-	buf := make([]byte, 8)
-	binary.BigEndian.PutUint64(buf, n)
-	return buf
-}
-
-// decode unmarshals a counter. Nil buffers are decoded as 0.
-func decode(buf []byte) uint64 {
-	if buf == nil {
-		return 0
-	}
-	return binary.BigEndian.Uint64(buf)
-}

+ 0 - 167
Godeps/_workspace/src/github.com/boltdb/bolt/batch_test.go

@@ -1,167 +0,0 @@
-package bolt_test
-
-import (
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-// Ensure two functions can perform updates in a single batch.
-func TestDB_Batch(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.MustCreateBucket([]byte("widgets"))
-
-	// Iterate over multiple updates in separate goroutines.
-	n := 2
-	ch := make(chan error)
-	for i := 0; i < n; i++ {
-		go func(i int) {
-			ch <- db.Batch(func(tx *bolt.Tx) error {
-				return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
-			})
-		}(i)
-	}
-
-	// Check all responses to make sure there's no error.
-	for i := 0; i < n; i++ {
-		if err := <-ch; err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	// Ensure data is correct.
-	db.MustView(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		for i := 0; i < n; i++ {
-			if v := b.Get(u64tob(uint64(i))); v == nil {
-				t.Errorf("key not found: %d", i)
-			}
-		}
-		return nil
-	})
-}
-
-func TestDB_Batch_Panic(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	var sentinel int
-	var bork = &sentinel
-	var problem interface{}
-	var err error
-
-	// Execute a function inside a batch that panics.
-	func() {
-		defer func() {
-			if p := recover(); p != nil {
-				problem = p
-			}
-		}()
-		err = db.Batch(func(tx *bolt.Tx) error {
-			panic(bork)
-		})
-	}()
-
-	// Verify there is no error.
-	if g, e := err, error(nil); g != e {
-		t.Fatalf("wrong error: %v != %v", g, e)
-	}
-	// Verify the panic was captured.
-	if g, e := problem, bork; g != e {
-		t.Fatalf("wrong error: %v != %v", g, e)
-	}
-}
-
-func TestDB_BatchFull(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.MustCreateBucket([]byte("widgets"))
-
-	const size = 3
-	// buffered so we never leak goroutines
-	ch := make(chan error, size)
-	put := func(i int) {
-		ch <- db.Batch(func(tx *bolt.Tx) error {
-			return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
-		})
-	}
-
-	db.MaxBatchSize = size
-	// high enough to never trigger here
-	db.MaxBatchDelay = 1 * time.Hour
-
-	go put(1)
-	go put(2)
-
-	// Give the batch a chance to exhibit bugs.
-	time.Sleep(10 * time.Millisecond)
-
-	// not triggered yet
-	select {
-	case <-ch:
-		t.Fatalf("batch triggered too early")
-	default:
-	}
-
-	go put(3)
-
-	// Check all responses to make sure there's no error.
-	for i := 0; i < size; i++ {
-		if err := <-ch; err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	// Ensure data is correct.
-	db.MustView(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		for i := 1; i <= size; i++ {
-			if v := b.Get(u64tob(uint64(i))); v == nil {
-				t.Errorf("key not found: %d", i)
-			}
-		}
-		return nil
-	})
-}
-
-func TestDB_BatchTime(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.MustCreateBucket([]byte("widgets"))
-
-	const size = 1
-	// buffered so we never leak goroutines
-	ch := make(chan error, size)
-	put := func(i int) {
-		ch <- db.Batch(func(tx *bolt.Tx) error {
-			return tx.Bucket([]byte("widgets")).Put(u64tob(uint64(i)), []byte{})
-		})
-	}
-
-	db.MaxBatchSize = 1000
-	db.MaxBatchDelay = 0
-
-	go put(1)
-
-	// Batch must trigger by time alone.
-
-	// Check all responses to make sure there's no error.
-	for i := 0; i < size; i++ {
-		if err := <-ch; err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	// Ensure data is correct.
-	db.MustView(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		for i := 1; i <= size; i++ {
-			if v := b.Get(u64tob(uint64(i))); v == nil {
-				t.Errorf("key not found: %d", i)
-			}
-		}
-		return nil
-	})
-}

+ 0 - 36
Godeps/_workspace/src/github.com/boltdb/bolt/bolt_test.go

@@ -1,36 +0,0 @@
-package bolt_test
-
-import (
-	"fmt"
-	"path/filepath"
-	"reflect"
-	"runtime"
-	"testing"
-)
-
-// assert fails the test if the condition is false.
-func assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
-	if !condition {
-		_, file, line, _ := runtime.Caller(1)
-		fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
-		tb.FailNow()
-	}
-}
-
-// ok fails the test if an err is not nil.
-func ok(tb testing.TB, err error) {
-	if err != nil {
-		_, file, line, _ := runtime.Caller(1)
-		fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
-		tb.FailNow()
-	}
-}
-
-// equals fails the test if exp is not equal to act.
-func equals(tb testing.TB, exp, act interface{}) {
-	if !reflect.DeepEqual(exp, act) {
-		_, file, line, _ := runtime.Caller(1)
-		fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
-		tb.FailNow()
-	}
-}

+ 0 - 11
Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix.go

@@ -46,17 +46,6 @@ func funlock(f *os.File) error {
 
 // mmap memory maps a DB's data file.
 func mmap(db *DB, sz int) error {
-	// Truncate and fsync to ensure file size metadata is flushed.
-	// https://github.com/boltdb/bolt/issues/284
-	if !db.NoGrowSync && !db.readOnly {
-		if err := db.file.Truncate(int64(sz)); err != nil {
-			return fmt.Errorf("file resize error: %s", err)
-		}
-		if err := db.file.Sync(); err != nil {
-			return fmt.Errorf("file sync error: %s", err)
-		}
-	}
-
 	// Map the data file to memory.
 	b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
 	if err != nil {

+ 0 - 11
Godeps/_workspace/src/github.com/boltdb/bolt/bolt_unix_solaris.go

@@ -56,17 +56,6 @@ func funlock(f *os.File) error {
 
 // mmap memory maps a DB's data file.
 func mmap(db *DB, sz int) error {
-	// Truncate and fsync to ensure file size metadata is flushed.
-	// https://github.com/boltdb/bolt/issues/284
-	if !db.NoGrowSync && !db.readOnly {
-		if err := db.file.Truncate(int64(sz)); err != nil {
-			return fmt.Errorf("file resize error: %s", err)
-		}
-		if err := db.file.Sync(); err != nil {
-			return fmt.Errorf("file sync error: %s", err)
-		}
-	}
-
 	// Map the data file to memory.
 	b, err := unix.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags)
 	if err != nil {

+ 0 - 1169
Godeps/_workspace/src/github.com/boltdb/bolt/bucket_test.go

@@ -1,1169 +0,0 @@
-package bolt_test
-
-import (
-	"bytes"
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"math/rand"
-	"os"
-	"strconv"
-	"strings"
-	"testing"
-	"testing/quick"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-// Ensure that a bucket that gets a non-existent key returns nil.
-func TestBucket_Get_NonExistent(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		assert(t, value == nil, "")
-		return nil
-	})
-}
-
-// Ensure that a bucket can read a value that is not flushed yet.
-func TestBucket_Get_FromNode(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		b.Put([]byte("foo"), []byte("bar"))
-		value := b.Get([]byte("foo"))
-		equals(t, []byte("bar"), value)
-		return nil
-	})
-}
-
-// Ensure that a bucket retrieved via Get() returns a nil.
-func TestBucket_Get_IncompatibleValue(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		_, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo"))
-		ok(t, err)
-		assert(t, tx.Bucket([]byte("widgets")).Get([]byte("foo")) == nil, "")
-		return nil
-	})
-}
-
-// Ensure that a bucket can write a key/value.
-func TestBucket_Put(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		err := tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		ok(t, err)
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		equals(t, value, []byte("bar"))
-		return nil
-	})
-}
-
-// Ensure that a bucket can rewrite a key in the same transaction.
-func TestBucket_Put_Repeat(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		ok(t, b.Put([]byte("foo"), []byte("bar")))
-		ok(t, b.Put([]byte("foo"), []byte("baz")))
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		equals(t, value, []byte("baz"))
-		return nil
-	})
-}
-
-// Ensure that a bucket can write a bunch of large values.
-func TestBucket_Put_Large(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	count, factor := 100, 200
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		for i := 1; i < count; i++ {
-			ok(t, b.Put([]byte(strings.Repeat("0", i*factor)), []byte(strings.Repeat("X", (count-i)*factor))))
-		}
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		for i := 1; i < count; i++ {
-			value := b.Get([]byte(strings.Repeat("0", i*factor)))
-			equals(t, []byte(strings.Repeat("X", (count-i)*factor)), value)
-		}
-		return nil
-	})
-}
-
-// Ensure that a database can perform multiple large appends safely.
-func TestDB_Put_VeryLarge(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-
-	n, batchN := 400000, 200000
-	ksize, vsize := 8, 500
-
-	db := NewTestDB()
-	defer db.Close()
-
-	for i := 0; i < n; i += batchN {
-		err := db.Update(func(tx *bolt.Tx) error {
-			b, _ := tx.CreateBucketIfNotExists([]byte("widgets"))
-			for j := 0; j < batchN; j++ {
-				k, v := make([]byte, ksize), make([]byte, vsize)
-				binary.BigEndian.PutUint32(k, uint32(i+j))
-				ok(t, b.Put(k, v))
-			}
-			return nil
-		})
-		ok(t, err)
-	}
-}
-
-// Ensure that a setting a value on a key with a bucket value returns an error.
-func TestBucket_Put_IncompatibleValue(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		_, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo"))
-		ok(t, err)
-		equals(t, bolt.ErrIncompatibleValue, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")))
-		return nil
-	})
-}
-
-// Ensure that a setting a value while the transaction is closed returns an error.
-func TestBucket_Put_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	tx.CreateBucket([]byte("widgets"))
-	b := tx.Bucket([]byte("widgets"))
-	tx.Rollback()
-	equals(t, bolt.ErrTxClosed, b.Put([]byte("foo"), []byte("bar")))
-}
-
-// Ensure that setting a value on a read-only bucket returns an error.
-func TestBucket_Put_ReadOnly(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		err := b.Put([]byte("foo"), []byte("bar"))
-		equals(t, err, bolt.ErrTxNotWritable)
-		return nil
-	})
-}
-
-// Ensure that a bucket can delete an existing key.
-func TestBucket_Delete(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		err := tx.Bucket([]byte("widgets")).Delete([]byte("foo"))
-		ok(t, err)
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		assert(t, value == nil, "")
-		return nil
-	})
-}
-
-// Ensure that deleting a large set of keys will work correctly.
-func TestBucket_Delete_Large(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		var b, _ = tx.CreateBucket([]byte("widgets"))
-		for i := 0; i < 100; i++ {
-			ok(t, b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024))))
-		}
-		return nil
-	})
-	db.Update(func(tx *bolt.Tx) error {
-		var b = tx.Bucket([]byte("widgets"))
-		for i := 0; i < 100; i++ {
-			ok(t, b.Delete([]byte(strconv.Itoa(i))))
-		}
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		var b = tx.Bucket([]byte("widgets"))
-		for i := 0; i < 100; i++ {
-			assert(t, b.Get([]byte(strconv.Itoa(i))) == nil, "")
-		}
-		return nil
-	})
-}
-
-// Deleting a very large list of keys will cause the freelist to use overflow.
-func TestBucket_Delete_FreelistOverflow(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-
-	db := NewTestDB()
-	defer db.Close()
-	k := make([]byte, 16)
-	for i := uint64(0); i < 10000; i++ {
-		err := db.Update(func(tx *bolt.Tx) error {
-			b, err := tx.CreateBucketIfNotExists([]byte("0"))
-			if err != nil {
-				t.Fatalf("bucket error: %s", err)
-			}
-
-			for j := uint64(0); j < 1000; j++ {
-				binary.BigEndian.PutUint64(k[:8], i)
-				binary.BigEndian.PutUint64(k[8:], j)
-				if err := b.Put(k, nil); err != nil {
-					t.Fatalf("put error: %s", err)
-				}
-			}
-
-			return nil
-		})
-
-		if err != nil {
-			t.Fatalf("update error: %s", err)
-		}
-	}
-
-	// Delete all of them in one large transaction
-	err := db.Update(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("0"))
-		c := b.Cursor()
-		for k, _ := c.First(); k != nil; k, _ = c.Next() {
-			c.Delete()
-		}
-		return nil
-	})
-
-	// Check that a freelist overflow occurred.
-	ok(t, err)
-}
-
-// Ensure that accessing and updating nested buckets is ok across transactions.
-func TestBucket_Nested(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		// Create a widgets bucket.
-		b, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-
-		// Create a widgets/foo bucket.
-		_, err = b.CreateBucket([]byte("foo"))
-		ok(t, err)
-
-		// Create a widgets/bar key.
-		ok(t, b.Put([]byte("bar"), []byte("0000")))
-
-		return nil
-	})
-	db.MustCheck()
-
-	// Update widgets/bar.
-	db.Update(func(tx *bolt.Tx) error {
-		var b = tx.Bucket([]byte("widgets"))
-		ok(t, b.Put([]byte("bar"), []byte("xxxx")))
-		return nil
-	})
-	db.MustCheck()
-
-	// Cause a split.
-	db.Update(func(tx *bolt.Tx) error {
-		var b = tx.Bucket([]byte("widgets"))
-		for i := 0; i < 10000; i++ {
-			ok(t, b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))))
-		}
-		return nil
-	})
-	db.MustCheck()
-
-	// Insert into widgets/foo/baz.
-	db.Update(func(tx *bolt.Tx) error {
-		var b = tx.Bucket([]byte("widgets"))
-		ok(t, b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy")))
-		return nil
-	})
-	db.MustCheck()
-
-	// Verify.
-	db.View(func(tx *bolt.Tx) error {
-		var b = tx.Bucket([]byte("widgets"))
-		equals(t, []byte("yyyy"), b.Bucket([]byte("foo")).Get([]byte("baz")))
-		equals(t, []byte("xxxx"), b.Get([]byte("bar")))
-		for i := 0; i < 10000; i++ {
-			equals(t, []byte(strconv.Itoa(i)), b.Get([]byte(strconv.Itoa(i))))
-		}
-		return nil
-	})
-}
-
-// Ensure that deleting a bucket using Delete() returns an error.
-func TestBucket_Delete_Bucket(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		_, err := b.CreateBucket([]byte("foo"))
-		ok(t, err)
-		equals(t, bolt.ErrIncompatibleValue, b.Delete([]byte("foo")))
-		return nil
-	})
-}
-
-// Ensure that deleting a key on a read-only bucket returns an error.
-func TestBucket_Delete_ReadOnly(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		err := b.Delete([]byte("foo"))
-		equals(t, err, bolt.ErrTxNotWritable)
-		return nil
-	})
-}
-
-// Ensure that a deleting value while the transaction is closed returns an error.
-func TestBucket_Delete_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	tx.CreateBucket([]byte("widgets"))
-	b := tx.Bucket([]byte("widgets"))
-	tx.Rollback()
-	equals(t, bolt.ErrTxClosed, b.Delete([]byte("foo")))
-}
-
-// Ensure that deleting a bucket causes nested buckets to be deleted.
-func TestBucket_DeleteBucket_Nested(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		_, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo"))
-		ok(t, err)
-		_, err = tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).CreateBucket([]byte("bar"))
-		ok(t, err)
-		ok(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).Bucket([]byte("bar")).Put([]byte("baz"), []byte("bat")))
-		ok(t, tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")))
-		return nil
-	})
-}
-
-// Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed.
-func TestBucket_DeleteBucket_Nested2(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		_, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo"))
-		ok(t, err)
-		_, err = tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).CreateBucket([]byte("bar"))
-		ok(t, err)
-		ok(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).Bucket([]byte("bar")).Put([]byte("baz"), []byte("bat")))
-		return nil
-	})
-	db.Update(func(tx *bolt.Tx) error {
-		assert(t, tx.Bucket([]byte("widgets")) != nil, "")
-		assert(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo")) != nil, "")
-		assert(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).Bucket([]byte("bar")) != nil, "")
-		equals(t, []byte("bat"), tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).Bucket([]byte("bar")).Get([]byte("baz")))
-		ok(t, tx.DeleteBucket([]byte("widgets")))
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		assert(t, tx.Bucket([]byte("widgets")) == nil, "")
-		return nil
-	})
-}
-
-// Ensure that deleting a child bucket with multiple pages causes all pages to get collected.
-func TestBucket_DeleteBucket_Large(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-		_, err = tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo"))
-		ok(t, err)
-		b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo"))
-		for i := 0; i < 1000; i++ {
-			ok(t, b.Put([]byte(fmt.Sprintf("%d", i)), []byte(fmt.Sprintf("%0100d", i))))
-		}
-		return nil
-	})
-	db.Update(func(tx *bolt.Tx) error {
-		ok(t, tx.DeleteBucket([]byte("widgets")))
-		return nil
-	})
-
-	// NOTE: Consistency check in TestDB.Close() will panic if pages not freed properly.
-}
-
-// Ensure that a simple value retrieved via Bucket() returns a nil.
-func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		ok(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")))
-		assert(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo")) == nil, "")
-		return nil
-	})
-}
-
-// Ensure that creating a bucket on an existing non-bucket key returns an error.
-func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-		ok(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")))
-		_, err = tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo"))
-		equals(t, bolt.ErrIncompatibleValue, err)
-		return nil
-	})
-}
-
-// Ensure that deleting a bucket on an existing non-bucket key returns an error.
-func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-		ok(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")))
-		equals(t, bolt.ErrIncompatibleValue, tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")))
-		return nil
-	})
-}
-
-// Ensure that a bucket can return an autoincrementing sequence.
-func TestBucket_NextSequence(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.CreateBucket([]byte("woojits"))
-
-		// Make sure sequence increments.
-		seq, err := tx.Bucket([]byte("widgets")).NextSequence()
-		ok(t, err)
-		equals(t, seq, uint64(1))
-		seq, err = tx.Bucket([]byte("widgets")).NextSequence()
-		ok(t, err)
-		equals(t, seq, uint64(2))
-
-		// Buckets should be separate.
-		seq, err = tx.Bucket([]byte("woojits")).NextSequence()
-		ok(t, err)
-		equals(t, seq, uint64(1))
-		return nil
-	})
-}
-
-// Ensure that a bucket will persist an autoincrementing sequence even if its
-// the only thing updated on the bucket.
-// https://github.com/boltdb/bolt/issues/296
-func TestBucket_NextSequence_Persist(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, _ = tx.CreateBucket([]byte("widgets"))
-		return nil
-	})
-
-	db.Update(func(tx *bolt.Tx) error {
-		_, _ = tx.Bucket([]byte("widgets")).NextSequence()
-		return nil
-	})
-
-	db.Update(func(tx *bolt.Tx) error {
-		seq, err := tx.Bucket([]byte("widgets")).NextSequence()
-		if err != nil {
-			t.Fatalf("unexpected error: %s", err)
-		} else if seq != 2 {
-			t.Fatalf("unexpected sequence: %d", seq)
-		}
-		return nil
-	})
-}
-
-// Ensure that retrieving the next sequence on a read-only bucket returns an error.
-func TestBucket_NextSequence_ReadOnly(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		i, err := b.NextSequence()
-		equals(t, i, uint64(0))
-		equals(t, err, bolt.ErrTxNotWritable)
-		return nil
-	})
-}
-
-// Ensure that retrieving the next sequence for a bucket on a closed database return an error.
-func TestBucket_NextSequence_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	tx.CreateBucket([]byte("widgets"))
-	b := tx.Bucket([]byte("widgets"))
-	tx.Rollback()
-	_, err := b.NextSequence()
-	equals(t, bolt.ErrTxClosed, err)
-}
-
-// Ensure a user can loop over all key/value pairs in a bucket.
-func TestBucket_ForEach(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("0000"))
-		tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("0001"))
-		tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte("0002"))
-
-		var index int
-		err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
-			switch index {
-			case 0:
-				equals(t, k, []byte("bar"))
-				equals(t, v, []byte("0002"))
-			case 1:
-				equals(t, k, []byte("baz"))
-				equals(t, v, []byte("0001"))
-			case 2:
-				equals(t, k, []byte("foo"))
-				equals(t, v, []byte("0000"))
-			}
-			index++
-			return nil
-		})
-		ok(t, err)
-		equals(t, index, 3)
-		return nil
-	})
-}
-
-// Ensure a database can stop iteration early.
-func TestBucket_ForEach_ShortCircuit(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte("0000"))
-		tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("0000"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("0000"))
-
-		var index int
-		err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
-			index++
-			if bytes.Equal(k, []byte("baz")) {
-				return errors.New("marker")
-			}
-			return nil
-		})
-		equals(t, errors.New("marker"), err)
-		equals(t, 2, index)
-		return nil
-	})
-}
-
-// Ensure that looping over a bucket on a closed database returns an error.
-func TestBucket_ForEach_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	tx.CreateBucket([]byte("widgets"))
-	b := tx.Bucket([]byte("widgets"))
-	tx.Rollback()
-	err := b.ForEach(func(k, v []byte) error { return nil })
-	equals(t, bolt.ErrTxClosed, err)
-}
-
-// Ensure that an error is returned when inserting with an empty key.
-func TestBucket_Put_EmptyKey(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		err := tx.Bucket([]byte("widgets")).Put([]byte(""), []byte("bar"))
-		equals(t, err, bolt.ErrKeyRequired)
-		err = tx.Bucket([]byte("widgets")).Put(nil, []byte("bar"))
-		equals(t, err, bolt.ErrKeyRequired)
-		return nil
-	})
-}
-
-// Ensure that an error is returned when inserting with a key that's too large.
-func TestBucket_Put_KeyTooLarge(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		err := tx.Bucket([]byte("widgets")).Put(make([]byte, 32769), []byte("bar"))
-		equals(t, err, bolt.ErrKeyTooLarge)
-		return nil
-	})
-}
-
-// Ensure that an error is returned when inserting a value that's too large.
-func TestBucket_Put_ValueTooLarge(t *testing.T) {
-	if os.Getenv("DRONE") == "true" {
-		t.Skip("not enough RAM for test")
-	}
-
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		err := tx.Bucket([]byte("widgets")).Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1))
-		equals(t, err, bolt.ErrValueTooLarge)
-		return nil
-	})
-}
-
-// Ensure a bucket can calculate stats.
-func TestBucket_Stats(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	// Add bucket with fewer keys but one big value.
-	big_key := []byte("really-big-value")
-	for i := 0; i < 500; i++ {
-		db.Update(func(tx *bolt.Tx) error {
-			b, _ := tx.CreateBucketIfNotExists([]byte("woojits"))
-			return b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i)))
-		})
-	}
-	db.Update(func(tx *bolt.Tx) error {
-		b, _ := tx.CreateBucketIfNotExists([]byte("woojits"))
-		return b.Put(big_key, []byte(strings.Repeat("*", 10000)))
-	})
-
-	db.MustCheck()
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("woojits"))
-		stats := b.Stats()
-		equals(t, 1, stats.BranchPageN)
-		equals(t, 0, stats.BranchOverflowN)
-		equals(t, 7, stats.LeafPageN)
-		equals(t, 2, stats.LeafOverflowN)
-		equals(t, 501, stats.KeyN)
-		equals(t, 2, stats.Depth)
-
-		branchInuse := 16     // branch page header
-		branchInuse += 7 * 16 // branch elements
-		branchInuse += 7 * 3  // branch keys (6 3-byte keys)
-		equals(t, branchInuse, stats.BranchInuse)
-
-		leafInuse := 7 * 16                      // leaf page header
-		leafInuse += 501 * 16                    // leaf elements
-		leafInuse += 500*3 + len(big_key)        // leaf keys
-		leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values
-		equals(t, leafInuse, stats.LeafInuse)
-
-		if os.Getpagesize() == 4096 {
-			// Incompatible page size
-			equals(t, 4096, stats.BranchAlloc)
-			equals(t, 36864, stats.LeafAlloc)
-		}
-
-		equals(t, 1, stats.BucketN)
-		equals(t, 0, stats.InlineBucketN)
-		equals(t, 0, stats.InlineBucketInuse)
-		return nil
-	})
-}
-
-// Ensure a bucket with random insertion utilizes fill percentage correctly.
-func TestBucket_Stats_RandomFill(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	} else if os.Getpagesize() != 4096 {
-		t.Skip("invalid page size for test")
-	}
-
-	db := NewTestDB()
-	defer db.Close()
-
-	// Add a set of values in random order. It will be the same random
-	// order so we can maintain consistency between test runs.
-	var count int
-	r := rand.New(rand.NewSource(42))
-	for _, i := range r.Perm(1000) {
-		db.Update(func(tx *bolt.Tx) error {
-			b, _ := tx.CreateBucketIfNotExists([]byte("woojits"))
-			b.FillPercent = 0.9
-			for _, j := range r.Perm(100) {
-				index := (j * 10000) + i
-				b.Put([]byte(fmt.Sprintf("%d000000000000000", index)), []byte("0000000000"))
-				count++
-			}
-			return nil
-		})
-	}
-	db.MustCheck()
-
-	db.View(func(tx *bolt.Tx) error {
-		s := tx.Bucket([]byte("woojits")).Stats()
-		equals(t, 100000, s.KeyN)
-
-		equals(t, 98, s.BranchPageN)
-		equals(t, 0, s.BranchOverflowN)
-		equals(t, 130984, s.BranchInuse)
-		equals(t, 401408, s.BranchAlloc)
-
-		equals(t, 3412, s.LeafPageN)
-		equals(t, 0, s.LeafOverflowN)
-		equals(t, 4742482, s.LeafInuse)
-		equals(t, 13975552, s.LeafAlloc)
-		return nil
-	})
-}
-
-// Ensure a bucket can calculate stats.
-func TestBucket_Stats_Small(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		// Add a bucket that fits on a single root leaf.
-		b, err := tx.CreateBucket([]byte("whozawhats"))
-		ok(t, err)
-		b.Put([]byte("foo"), []byte("bar"))
-
-		return nil
-	})
-	db.MustCheck()
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("whozawhats"))
-		stats := b.Stats()
-		equals(t, 0, stats.BranchPageN)
-		equals(t, 0, stats.BranchOverflowN)
-		equals(t, 0, stats.LeafPageN)
-		equals(t, 0, stats.LeafOverflowN)
-		equals(t, 1, stats.KeyN)
-		equals(t, 1, stats.Depth)
-		equals(t, 0, stats.BranchInuse)
-		equals(t, 0, stats.LeafInuse)
-		if os.Getpagesize() == 4096 {
-			// Incompatible page size
-			equals(t, 0, stats.BranchAlloc)
-			equals(t, 0, stats.LeafAlloc)
-		}
-		equals(t, 1, stats.BucketN)
-		equals(t, 1, stats.InlineBucketN)
-		equals(t, 16+16+6, stats.InlineBucketInuse)
-		return nil
-	})
-}
-
-func TestBucket_Stats_EmptyBucket(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		// Add a bucket that fits on a single root leaf.
-		_, err := tx.CreateBucket([]byte("whozawhats"))
-		ok(t, err)
-		return nil
-	})
-	db.MustCheck()
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("whozawhats"))
-		stats := b.Stats()
-		equals(t, 0, stats.BranchPageN)
-		equals(t, 0, stats.BranchOverflowN)
-		equals(t, 0, stats.LeafPageN)
-		equals(t, 0, stats.LeafOverflowN)
-		equals(t, 0, stats.KeyN)
-		equals(t, 1, stats.Depth)
-		equals(t, 0, stats.BranchInuse)
-		equals(t, 0, stats.LeafInuse)
-		if os.Getpagesize() == 4096 {
-			// Incompatible page size
-			equals(t, 0, stats.BranchAlloc)
-			equals(t, 0, stats.LeafAlloc)
-		}
-		equals(t, 1, stats.BucketN)
-		equals(t, 1, stats.InlineBucketN)
-		equals(t, 16, stats.InlineBucketInuse)
-		return nil
-	})
-}
-
-// Ensure a bucket can calculate stats.
-func TestBucket_Stats_Nested(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("foo"))
-		ok(t, err)
-		for i := 0; i < 100; i++ {
-			b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i)))
-		}
-		bar, err := b.CreateBucket([]byte("bar"))
-		ok(t, err)
-		for i := 0; i < 10; i++ {
-			bar.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i)))
-		}
-		baz, err := bar.CreateBucket([]byte("baz"))
-		ok(t, err)
-		for i := 0; i < 10; i++ {
-			baz.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i)))
-		}
-		return nil
-	})
-
-	db.MustCheck()
-
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("foo"))
-		stats := b.Stats()
-		equals(t, 0, stats.BranchPageN)
-		equals(t, 0, stats.BranchOverflowN)
-		equals(t, 2, stats.LeafPageN)
-		equals(t, 0, stats.LeafOverflowN)
-		equals(t, 122, stats.KeyN)
-		equals(t, 3, stats.Depth)
-		equals(t, 0, stats.BranchInuse)
-
-		foo := 16            // foo (pghdr)
-		foo += 101 * 16      // foo leaf elements
-		foo += 100*2 + 100*2 // foo leaf key/values
-		foo += 3 + 16        // foo -> bar key/value
-
-		bar := 16      // bar (pghdr)
-		bar += 11 * 16 // bar leaf elements
-		bar += 10 + 10 // bar leaf key/values
-		bar += 3 + 16  // bar -> baz key/value
-
-		baz := 16      // baz (inline) (pghdr)
-		baz += 10 * 16 // baz leaf elements
-		baz += 10 + 10 // baz leaf key/values
-
-		equals(t, foo+bar+baz, stats.LeafInuse)
-		if os.Getpagesize() == 4096 {
-			// Incompatible page size
-			equals(t, 0, stats.BranchAlloc)
-			equals(t, 8192, stats.LeafAlloc)
-		}
-		equals(t, 3, stats.BucketN)
-		equals(t, 1, stats.InlineBucketN)
-		equals(t, baz, stats.InlineBucketInuse)
-		return nil
-	})
-}
-
-// Ensure a large bucket can calculate stats.
-func TestBucket_Stats_Large(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-
-	db := NewTestDB()
-	defer db.Close()
-
-	var index int
-	for i := 0; i < 100; i++ {
-		db.Update(func(tx *bolt.Tx) error {
-			// Add bucket with lots of keys.
-			b, _ := tx.CreateBucketIfNotExists([]byte("widgets"))
-			for i := 0; i < 1000; i++ {
-				b.Put([]byte(strconv.Itoa(index)), []byte(strconv.Itoa(index)))
-				index++
-			}
-			return nil
-		})
-	}
-	db.MustCheck()
-
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		stats := b.Stats()
-		equals(t, 13, stats.BranchPageN)
-		equals(t, 0, stats.BranchOverflowN)
-		equals(t, 1196, stats.LeafPageN)
-		equals(t, 0, stats.LeafOverflowN)
-		equals(t, 100000, stats.KeyN)
-		equals(t, 3, stats.Depth)
-		equals(t, 25257, stats.BranchInuse)
-		equals(t, 2596916, stats.LeafInuse)
-		if os.Getpagesize() == 4096 {
-			// Incompatible page size
-			equals(t, 53248, stats.BranchAlloc)
-			equals(t, 4898816, stats.LeafAlloc)
-		}
-		equals(t, 1, stats.BucketN)
-		equals(t, 0, stats.InlineBucketN)
-		equals(t, 0, stats.InlineBucketInuse)
-		return nil
-	})
-}
-
-// Ensure that a bucket can write random keys and values across multiple transactions.
-func TestBucket_Put_Single(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-
-	index := 0
-	f := func(items testdata) bool {
-		db := NewTestDB()
-		defer db.Close()
-
-		m := make(map[string][]byte)
-
-		db.Update(func(tx *bolt.Tx) error {
-			_, err := tx.CreateBucket([]byte("widgets"))
-			return err
-		})
-		for _, item := range items {
-			db.Update(func(tx *bolt.Tx) error {
-				if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil {
-					panic("put error: " + err.Error())
-				}
-				m[string(item.Key)] = item.Value
-				return nil
-			})
-
-			// Verify all key/values so far.
-			db.View(func(tx *bolt.Tx) error {
-				i := 0
-				for k, v := range m {
-					value := tx.Bucket([]byte("widgets")).Get([]byte(k))
-					if !bytes.Equal(value, v) {
-						t.Logf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v)
-						db.CopyTempFile()
-						t.FailNow()
-					}
-					i++
-				}
-				return nil
-			})
-		}
-
-		index++
-		return true
-	}
-	if err := quick.Check(f, qconfig()); err != nil {
-		t.Error(err)
-	}
-}
-
-// Ensure that a transaction can insert multiple key/value pairs at once.
-func TestBucket_Put_Multiple(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-
-	f := func(items testdata) bool {
-		db := NewTestDB()
-		defer db.Close()
-		// Bulk insert all values.
-		db.Update(func(tx *bolt.Tx) error {
-			_, err := tx.CreateBucket([]byte("widgets"))
-			return err
-		})
-		err := db.Update(func(tx *bolt.Tx) error {
-			b := tx.Bucket([]byte("widgets"))
-			for _, item := range items {
-				ok(t, b.Put(item.Key, item.Value))
-			}
-			return nil
-		})
-		ok(t, err)
-
-		// Verify all items exist.
-		db.View(func(tx *bolt.Tx) error {
-			b := tx.Bucket([]byte("widgets"))
-			for _, item := range items {
-				value := b.Get(item.Key)
-				if !bytes.Equal(item.Value, value) {
-					db.CopyTempFile()
-					t.Fatalf("exp=%x; got=%x", item.Value, value)
-				}
-			}
-			return nil
-		})
-		return true
-	}
-	if err := quick.Check(f, qconfig()); err != nil {
-		t.Error(err)
-	}
-}
-
-// Ensure that a transaction can delete all key/value pairs and return to a single leaf page.
-func TestBucket_Delete_Quick(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-
-	f := func(items testdata) bool {
-		db := NewTestDB()
-		defer db.Close()
-		// Bulk insert all values.
-		db.Update(func(tx *bolt.Tx) error {
-			_, err := tx.CreateBucket([]byte("widgets"))
-			return err
-		})
-		err := db.Update(func(tx *bolt.Tx) error {
-			b := tx.Bucket([]byte("widgets"))
-			for _, item := range items {
-				ok(t, b.Put(item.Key, item.Value))
-			}
-			return nil
-		})
-		ok(t, err)
-
-		// Remove items one at a time and check consistency.
-		for _, item := range items {
-			err := db.Update(func(tx *bolt.Tx) error {
-				return tx.Bucket([]byte("widgets")).Delete(item.Key)
-			})
-			ok(t, err)
-		}
-
-		// Anything before our deletion index should be nil.
-		db.View(func(tx *bolt.Tx) error {
-			tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error {
-				t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3))
-				return nil
-			})
-			return nil
-		})
-		return true
-	}
-	if err := quick.Check(f, qconfig()); err != nil {
-		t.Error(err)
-	}
-}
-
-func ExampleBucket_Put() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Start a write transaction.
-	db.Update(func(tx *bolt.Tx) error {
-		// Create a bucket.
-		tx.CreateBucket([]byte("widgets"))
-
-		// Set the value "bar" for the key "foo".
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		return nil
-	})
-
-	// Read value back in a different read-only transaction.
-	db.View(func(tx *bolt.Tx) error {
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		fmt.Printf("The value of 'foo' is: %s\n", value)
-		return nil
-	})
-
-	// Output:
-	// The value of 'foo' is: bar
-}
-
-func ExampleBucket_Delete() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Start a write transaction.
-	db.Update(func(tx *bolt.Tx) error {
-		// Create a bucket.
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-
-		// Set the value "bar" for the key "foo".
-		b.Put([]byte("foo"), []byte("bar"))
-
-		// Retrieve the key back from the database and verify it.
-		value := b.Get([]byte("foo"))
-		fmt.Printf("The value of 'foo' was: %s\n", value)
-		return nil
-	})
-
-	// Delete the key in a different write transaction.
-	db.Update(func(tx *bolt.Tx) error {
-		return tx.Bucket([]byte("widgets")).Delete([]byte("foo"))
-	})
-
-	// Retrieve the key again.
-	db.View(func(tx *bolt.Tx) error {
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		if value == nil {
-			fmt.Printf("The value of 'foo' is now: nil\n")
-		}
-		return nil
-	})
-
-	// Output:
-	// The value of 'foo' was: bar
-	// The value of 'foo' is now: nil
-}
-
-func ExampleBucket_ForEach() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Insert data into a bucket.
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("animals"))
-		b := tx.Bucket([]byte("animals"))
-		b.Put([]byte("dog"), []byte("fun"))
-		b.Put([]byte("cat"), []byte("lame"))
-		b.Put([]byte("liger"), []byte("awesome"))
-
-		// Iterate over items in sorted key order.
-		b.ForEach(func(k, v []byte) error {
-			fmt.Printf("A %s is %s.\n", k, v)
-			return nil
-		})
-		return nil
-	})
-
-	// Output:
-	// A cat is lame.
-	// A dog is fun.
-	// A liger is awesome.
-}

+ 4 - 1
Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main.go

@@ -825,7 +825,10 @@ func (cmd *StatsCommand) Run(args ...string) error {
 
 		fmt.Fprintln(cmd.Stdout, "Bucket statistics")
 		fmt.Fprintf(cmd.Stdout, "\tTotal number of buckets: %d\n", s.BucketN)
-		percentage = int(float32(s.InlineBucketN) * 100.0 / float32(s.BucketN))
+		percentage = 0
+		if s.BucketN != 0 {
+			percentage = int(float32(s.InlineBucketN) * 100.0 / float32(s.BucketN))
+		}
 		fmt.Fprintf(cmd.Stdout, "\tTotal number on inlined buckets: %d (%d%%)\n", s.InlineBucketN, percentage)
 		percentage = 0
 		if s.LeafInuse != 0 {

+ 0 - 145
Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt/main_test.go

@@ -1,145 +0,0 @@
-package main_test
-
-import (
-	"bytes"
-	"io/ioutil"
-	"os"
-	"strconv"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt/cmd/bolt"
-)
-
-// Ensure the "info" command can print information about a database.
-func TestInfoCommand_Run(t *testing.T) {
-	db := MustOpen(0666, nil)
-	db.DB.Close()
-	defer db.Close()
-
-	// Run the info command.
-	m := NewMain()
-	if err := m.Run("info", db.Path); err != nil {
-		t.Fatal(err)
-	}
-}
-
-// Ensure the "stats" command can execute correctly.
-func TestStatsCommand_Run(t *testing.T) {
-	// Ignore
-	if os.Getpagesize() != 4096 {
-		t.Skip("system does not use 4KB page size")
-	}
-
-	db := MustOpen(0666, nil)
-	defer db.Close()
-
-	if err := db.Update(func(tx *bolt.Tx) error {
-		// Create "foo" bucket.
-		b, err := tx.CreateBucket([]byte("foo"))
-		if err != nil {
-			return err
-		}
-		for i := 0; i < 10; i++ {
-			if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
-				return err
-			}
-		}
-
-		// Create "bar" bucket.
-		b, err = tx.CreateBucket([]byte("bar"))
-		if err != nil {
-			return err
-		}
-		for i := 0; i < 100; i++ {
-			if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil {
-				return err
-			}
-		}
-
-		// Create "baz" bucket.
-		b, err = tx.CreateBucket([]byte("baz"))
-		if err != nil {
-			return err
-		}
-		if err := b.Put([]byte("key"), []byte("value")); err != nil {
-			return err
-		}
-
-		return nil
-	}); err != nil {
-		t.Fatal(err)
-	}
-	db.DB.Close()
-
-	// Generate expected result.
-	exp := "Aggregate statistics for 3 buckets\n\n" +
-		"Page count statistics\n" +
-		"\tNumber of logical branch pages: 0\n" +
-		"\tNumber of physical branch overflow pages: 0\n" +
-		"\tNumber of logical leaf pages: 1\n" +
-		"\tNumber of physical leaf overflow pages: 0\n" +
-		"Tree statistics\n" +
-		"\tNumber of keys/value pairs: 111\n" +
-		"\tNumber of levels in B+tree: 1\n" +
-		"Page size utilization\n" +
-		"\tBytes allocated for physical branch pages: 0\n" +
-		"\tBytes actually used for branch data: 0 (0%)\n" +
-		"\tBytes allocated for physical leaf pages: 4096\n" +
-		"\tBytes actually used for leaf data: 1996 (48%)\n" +
-		"Bucket statistics\n" +
-		"\tTotal number of buckets: 3\n" +
-		"\tTotal number on inlined buckets: 2 (66%)\n" +
-		"\tBytes used for inlined buckets: 236 (11%)\n"
-
-	// Run the command.
-	m := NewMain()
-	if err := m.Run("stats", db.Path); err != nil {
-		t.Fatal(err)
-	} else if m.Stdout.String() != exp {
-		t.Fatalf("unexpected stdout:\n\n%s", m.Stdout.String())
-	}
-}
-
-// Main represents a test wrapper for main.Main that records output.
-type Main struct {
-	*main.Main
-	Stdin  bytes.Buffer
-	Stdout bytes.Buffer
-	Stderr bytes.Buffer
-}
-
-// NewMain returns a new instance of Main.
-func NewMain() *Main {
-	m := &Main{Main: main.NewMain()}
-	m.Main.Stdin = &m.Stdin
-	m.Main.Stdout = &m.Stdout
-	m.Main.Stderr = &m.Stderr
-	return m
-}
-
-// MustOpen creates a Bolt database in a temporary location.
-func MustOpen(mode os.FileMode, options *bolt.Options) *DB {
-	// Create temporary path.
-	f, _ := ioutil.TempFile("", "bolt-")
-	f.Close()
-	os.Remove(f.Name())
-
-	db, err := bolt.Open(f.Name(), mode, options)
-	if err != nil {
-		panic(err.Error())
-	}
-	return &DB{DB: db, Path: f.Name()}
-}
-
-// DB is a test wrapper for bolt.DB.
-type DB struct {
-	*bolt.DB
-	Path string
-}
-
-// Close closes and removes the database.
-func (db *DB) Close() error {
-	defer os.Remove(db.Path)
-	return db.DB.Close()
-}

+ 0 - 554
Godeps/_workspace/src/github.com/boltdb/bolt/cursor_test.go

@@ -1,554 +0,0 @@
-package bolt_test
-
-import (
-	"bytes"
-	"encoding/binary"
-	"fmt"
-	"os"
-	"sort"
-	"testing"
-	"testing/quick"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-// Ensure that a cursor can return a reference to the bucket that created it.
-func TestCursor_Bucket(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		b, _ := tx.CreateBucket([]byte("widgets"))
-		c := b.Cursor()
-		equals(t, b, c.Bucket())
-		return nil
-	})
-}
-
-// Ensure that a Tx cursor can seek to the appropriate keys.
-func TestCursor_Seek(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-		ok(t, b.Put([]byte("foo"), []byte("0001")))
-		ok(t, b.Put([]byte("bar"), []byte("0002")))
-		ok(t, b.Put([]byte("baz"), []byte("0003")))
-		_, err = b.CreateBucket([]byte("bkt"))
-		ok(t, err)
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		c := tx.Bucket([]byte("widgets")).Cursor()
-
-		// Exact match should go to the key.
-		k, v := c.Seek([]byte("bar"))
-		equals(t, []byte("bar"), k)
-		equals(t, []byte("0002"), v)
-
-		// Inexact match should go to the next key.
-		k, v = c.Seek([]byte("bas"))
-		equals(t, []byte("baz"), k)
-		equals(t, []byte("0003"), v)
-
-		// Low key should go to the first key.
-		k, v = c.Seek([]byte(""))
-		equals(t, []byte("bar"), k)
-		equals(t, []byte("0002"), v)
-
-		// High key should return no key.
-		k, v = c.Seek([]byte("zzz"))
-		assert(t, k == nil, "")
-		assert(t, v == nil, "")
-
-		// Buckets should return their key but no value.
-		k, v = c.Seek([]byte("bkt"))
-		equals(t, []byte("bkt"), k)
-		assert(t, v == nil, "")
-
-		return nil
-	})
-}
-
-func TestCursor_Delete(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	var count = 1000
-
-	// Insert every other key between 0 and $count.
-	db.Update(func(tx *bolt.Tx) error {
-		b, _ := tx.CreateBucket([]byte("widgets"))
-		for i := 0; i < count; i += 1 {
-			k := make([]byte, 8)
-			binary.BigEndian.PutUint64(k, uint64(i))
-			b.Put(k, make([]byte, 100))
-		}
-		b.CreateBucket([]byte("sub"))
-		return nil
-	})
-
-	db.Update(func(tx *bolt.Tx) error {
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		bound := make([]byte, 8)
-		binary.BigEndian.PutUint64(bound, uint64(count/2))
-		for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() {
-			if err := c.Delete(); err != nil {
-				return err
-			}
-		}
-		c.Seek([]byte("sub"))
-		err := c.Delete()
-		equals(t, err, bolt.ErrIncompatibleValue)
-		return nil
-	})
-
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		equals(t, b.Stats().KeyN, count/2+1)
-		return nil
-	})
-}
-
-// Ensure that a Tx cursor can seek to the appropriate keys when there are a
-// large number of keys. This test also checks that seek will always move
-// forward to the next key.
-//
-// Related: https://github.com/boltdb/bolt/pull/187
-func TestCursor_Seek_Large(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	var count = 10000
-
-	// Insert every other key between 0 and $count.
-	db.Update(func(tx *bolt.Tx) error {
-		b, _ := tx.CreateBucket([]byte("widgets"))
-		for i := 0; i < count; i += 100 {
-			for j := i; j < i+100; j += 2 {
-				k := make([]byte, 8)
-				binary.BigEndian.PutUint64(k, uint64(j))
-				b.Put(k, make([]byte, 100))
-			}
-		}
-		return nil
-	})
-
-	db.View(func(tx *bolt.Tx) error {
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		for i := 0; i < count; i++ {
-			seek := make([]byte, 8)
-			binary.BigEndian.PutUint64(seek, uint64(i))
-
-			k, _ := c.Seek(seek)
-
-			// The last seek is beyond the end of the the range so
-			// it should return nil.
-			if i == count-1 {
-				assert(t, k == nil, "")
-				continue
-			}
-
-			// Otherwise we should seek to the exact key or the next key.
-			num := binary.BigEndian.Uint64(k)
-			if i%2 == 0 {
-				equals(t, uint64(i), num)
-			} else {
-				equals(t, uint64(i+1), num)
-			}
-		}
-
-		return nil
-	})
-}
-
-// Ensure that a cursor can iterate over an empty bucket without error.
-func TestCursor_EmptyBucket(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-	db.View(func(tx *bolt.Tx) error {
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		k, v := c.First()
-		assert(t, k == nil, "")
-		assert(t, v == nil, "")
-		return nil
-	})
-}
-
-// Ensure that a Tx cursor can reverse iterate over an empty bucket without error.
-func TestCursor_EmptyBucketReverse(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-	db.View(func(tx *bolt.Tx) error {
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		k, v := c.Last()
-		assert(t, k == nil, "")
-		assert(t, v == nil, "")
-		return nil
-	})
-}
-
-// Ensure that a Tx cursor can iterate over a single root with a couple elements.
-func TestCursor_Iterate_Leaf(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte{})
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{0})
-		tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte{1})
-		return nil
-	})
-	tx, _ := db.Begin(false)
-	c := tx.Bucket([]byte("widgets")).Cursor()
-
-	k, v := c.First()
-	equals(t, string(k), "bar")
-	equals(t, v, []byte{1})
-
-	k, v = c.Next()
-	equals(t, string(k), "baz")
-	equals(t, v, []byte{})
-
-	k, v = c.Next()
-	equals(t, string(k), "foo")
-	equals(t, v, []byte{0})
-
-	k, v = c.Next()
-	assert(t, k == nil, "")
-	assert(t, v == nil, "")
-
-	k, v = c.Next()
-	assert(t, k == nil, "")
-	assert(t, v == nil, "")
-
-	tx.Rollback()
-}
-
-// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements.
-func TestCursor_LeafRootReverse(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte{})
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{0})
-		tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte{1})
-		return nil
-	})
-	tx, _ := db.Begin(false)
-	c := tx.Bucket([]byte("widgets")).Cursor()
-
-	k, v := c.Last()
-	equals(t, string(k), "foo")
-	equals(t, v, []byte{0})
-
-	k, v = c.Prev()
-	equals(t, string(k), "baz")
-	equals(t, v, []byte{})
-
-	k, v = c.Prev()
-	equals(t, string(k), "bar")
-	equals(t, v, []byte{1})
-
-	k, v = c.Prev()
-	assert(t, k == nil, "")
-	assert(t, v == nil, "")
-
-	k, v = c.Prev()
-	assert(t, k == nil, "")
-	assert(t, v == nil, "")
-
-	tx.Rollback()
-}
-
-// Ensure that a Tx cursor can restart from the beginning.
-func TestCursor_Restart(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte{})
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{})
-		return nil
-	})
-
-	tx, _ := db.Begin(false)
-	c := tx.Bucket([]byte("widgets")).Cursor()
-
-	k, _ := c.First()
-	equals(t, string(k), "bar")
-
-	k, _ = c.Next()
-	equals(t, string(k), "foo")
-
-	k, _ = c.First()
-	equals(t, string(k), "bar")
-
-	k, _ = c.Next()
-	equals(t, string(k), "foo")
-
-	tx.Rollback()
-}
-
-// Ensure that a cursor can skip over empty pages that have been deleted.
-func TestCursor_First_EmptyPages(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	// Create 1000 keys in the "widgets" bucket.
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		for i := 0; i < 1000; i++ {
-			if err := b.Put(u64tob(uint64(i)), []byte{}); err != nil {
-				t.Fatal(err)
-			}
-		}
-
-		return nil
-	})
-
-	// Delete half the keys and then try to iterate.
-	db.Update(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		for i := 0; i < 600; i++ {
-			if err := b.Delete(u64tob(uint64(i))); err != nil {
-				t.Fatal(err)
-			}
-		}
-
-		c := b.Cursor()
-		var n int
-		for k, _ := c.First(); k != nil; k, _ = c.Next() {
-			n++
-		}
-		if n != 400 {
-			t.Fatalf("unexpected key count: %d", n)
-		}
-
-		return nil
-	})
-}
-
-// Ensure that a Tx can iterate over all elements in a bucket.
-func TestCursor_QuickCheck(t *testing.T) {
-	f := func(items testdata) bool {
-		db := NewTestDB()
-		defer db.Close()
-
-		// Bulk insert all values.
-		tx, _ := db.Begin(true)
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		for _, item := range items {
-			ok(t, b.Put(item.Key, item.Value))
-		}
-		ok(t, tx.Commit())
-
-		// Sort test data.
-		sort.Sort(items)
-
-		// Iterate over all items and check consistency.
-		var index = 0
-		tx, _ = db.Begin(false)
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() {
-			equals(t, k, items[index].Key)
-			equals(t, v, items[index].Value)
-			index++
-		}
-		equals(t, len(items), index)
-		tx.Rollback()
-
-		return true
-	}
-	if err := quick.Check(f, qconfig()); err != nil {
-		t.Error(err)
-	}
-}
-
-// Ensure that a transaction can iterate over all elements in a bucket in reverse.
-func TestCursor_QuickCheck_Reverse(t *testing.T) {
-	f := func(items testdata) bool {
-		db := NewTestDB()
-		defer db.Close()
-
-		// Bulk insert all values.
-		tx, _ := db.Begin(true)
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		for _, item := range items {
-			ok(t, b.Put(item.Key, item.Value))
-		}
-		ok(t, tx.Commit())
-
-		// Sort test data.
-		sort.Sort(revtestdata(items))
-
-		// Iterate over all items and check consistency.
-		var index = 0
-		tx, _ = db.Begin(false)
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() {
-			equals(t, k, items[index].Key)
-			equals(t, v, items[index].Value)
-			index++
-		}
-		equals(t, len(items), index)
-		tx.Rollback()
-
-		return true
-	}
-	if err := quick.Check(f, qconfig()); err != nil {
-		t.Error(err)
-	}
-}
-
-// Ensure that a Tx cursor can iterate over subbuckets.
-func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-		_, err = b.CreateBucket([]byte("foo"))
-		ok(t, err)
-		_, err = b.CreateBucket([]byte("bar"))
-		ok(t, err)
-		_, err = b.CreateBucket([]byte("baz"))
-		ok(t, err)
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		var names []string
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		for k, v := c.First(); k != nil; k, v = c.Next() {
-			names = append(names, string(k))
-			assert(t, v == nil, "")
-		}
-		equals(t, names, []string{"bar", "baz", "foo"})
-		return nil
-	})
-}
-
-// Ensure that a Tx cursor can reverse iterate over subbuckets.
-func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		ok(t, err)
-		_, err = b.CreateBucket([]byte("foo"))
-		ok(t, err)
-		_, err = b.CreateBucket([]byte("bar"))
-		ok(t, err)
-		_, err = b.CreateBucket([]byte("baz"))
-		ok(t, err)
-		return nil
-	})
-	db.View(func(tx *bolt.Tx) error {
-		var names []string
-		c := tx.Bucket([]byte("widgets")).Cursor()
-		for k, v := c.Last(); k != nil; k, v = c.Prev() {
-			names = append(names, string(k))
-			assert(t, v == nil, "")
-		}
-		equals(t, names, []string{"foo", "baz", "bar"})
-		return nil
-	})
-}
-
-func ExampleCursor() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Start a read-write transaction.
-	db.Update(func(tx *bolt.Tx) error {
-		// Create a new bucket.
-		tx.CreateBucket([]byte("animals"))
-
-		// Insert data into a bucket.
-		b := tx.Bucket([]byte("animals"))
-		b.Put([]byte("dog"), []byte("fun"))
-		b.Put([]byte("cat"), []byte("lame"))
-		b.Put([]byte("liger"), []byte("awesome"))
-
-		// Create a cursor for iteration.
-		c := b.Cursor()
-
-		// Iterate over items in sorted key order. This starts from the
-		// first key/value pair and updates the k/v variables to the
-		// next key/value on each iteration.
-		//
-		// The loop finishes at the end of the cursor when a nil key is returned.
-		for k, v := c.First(); k != nil; k, v = c.Next() {
-			fmt.Printf("A %s is %s.\n", k, v)
-		}
-
-		return nil
-	})
-
-	// Output:
-	// A cat is lame.
-	// A dog is fun.
-	// A liger is awesome.
-}
-
-func ExampleCursor_reverse() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Start a read-write transaction.
-	db.Update(func(tx *bolt.Tx) error {
-		// Create a new bucket.
-		tx.CreateBucket([]byte("animals"))
-
-		// Insert data into a bucket.
-		b := tx.Bucket([]byte("animals"))
-		b.Put([]byte("dog"), []byte("fun"))
-		b.Put([]byte("cat"), []byte("lame"))
-		b.Put([]byte("liger"), []byte("awesome"))
-
-		// Create a cursor for iteration.
-		c := b.Cursor()
-
-		// Iterate over items in reverse sorted key order. This starts
-		// from the last key/value pair and updates the k/v variables to
-		// the previous key/value on each iteration.
-		//
-		// The loop finishes at the beginning of the cursor when a nil key
-		// is returned.
-		for k, v := c.Last(); k != nil; k, v = c.Prev() {
-			fmt.Printf("A %s is %s.\n", k, v)
-		}
-
-		return nil
-	})
-
-	// Output:
-	// A liger is awesome.
-	// A dog is fun.
-	// A cat is lame.
-}

+ 195 - 9
Godeps/_workspace/src/github.com/boltdb/bolt/db.go

@@ -1,8 +1,10 @@
 package bolt
 
 import (
+	"errors"
 	"fmt"
 	"hash/fnv"
+	"log"
 	"os"
 	"runtime"
 	"runtime/debug"
@@ -24,13 +26,14 @@ const magic uint32 = 0xED0CDAED
 // IgnoreNoSync specifies whether the NoSync field of a DB is ignored when
 // syncing changes to a file.  This is required as some operating systems,
 // such as OpenBSD, do not have a unified buffer cache (UBC) and writes
-// must be synchronzied using the msync(2) syscall.
+// must be synchronized using the msync(2) syscall.
 const IgnoreNoSync = runtime.GOOS == "openbsd"
 
 // Default values if not set in a DB instance.
 const (
 	DefaultMaxBatchSize  int = 1000
 	DefaultMaxBatchDelay     = 10 * time.Millisecond
+	DefaultAllocSize         = 16 * 1024 * 1024
 )
 
 // DB represents a collection of buckets persisted to a file on disk.
@@ -83,11 +86,17 @@ type DB struct {
 	// Do not change concurrently with calls to Batch.
 	MaxBatchDelay time.Duration
 
+	// AllocSize is the amount of space allocated when the database
+	// needs to create new pages. This is done to amortize the cost
+	// of truncate() and fsync() when growing the data file.
+	AllocSize int
+
 	path     string
 	file     *os.File
 	dataref  []byte // mmap'ed readonly, write throws SEGV
 	data     *[maxMapSize]byte
 	datasz   int
+	filesz   int // current on disk file size
 	meta0    *meta
 	meta1    *meta
 	pageSize int
@@ -145,6 +154,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
 	// Set default values for later DB operations.
 	db.MaxBatchSize = DefaultMaxBatchSize
 	db.MaxBatchDelay = DefaultMaxBatchDelay
+	db.AllocSize = DefaultAllocSize
 
 	flag := os.O_RDWR
 	if options.ReadOnly {
@@ -177,7 +187,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
 
 	// Initialize the database if it doesn't exist.
 	if info, err := db.file.Stat(); err != nil {
-		return nil, fmt.Errorf("stat error: %s", err)
+		return nil, err
 	} else if info.Size() == 0 {
 		// Initialize new files with meta pages.
 		if err := db.init(); err != nil {
@@ -189,14 +199,14 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
 		if _, err := db.file.ReadAt(buf[:], 0); err == nil {
 			m := db.pageInBuffer(buf[:], 0).meta()
 			if err := m.validate(); err != nil {
-				return nil, fmt.Errorf("meta0 error: %s", err)
+				return nil, err
 			}
 			db.pageSize = int(m.pageSize)
 		}
 	}
 
 	// Memory map the data file.
-	if err := db.mmap(0); err != nil {
+	if err := db.mmap(options.InitialMmapSize); err != nil {
 		_ = db.close()
 		return nil, err
 	}
@@ -253,10 +263,10 @@ func (db *DB) mmap(minsz int) error {
 
 	// Validate the meta pages.
 	if err := db.meta0.validate(); err != nil {
-		return fmt.Errorf("meta0 error: %s", err)
+		return err
 	}
 	if err := db.meta1.validate(); err != nil {
-		return fmt.Errorf("meta1 error: %s", err)
+		return err
 	}
 
 	return nil
@@ -271,7 +281,7 @@ func (db *DB) munmap() error {
 }
 
 // mmapSize determines the appropriate size for the mmap given the current size
-// of the database. The minimum size is 1MB and doubles until it reaches 1GB.
+// of the database. The minimum size is 32KB and doubles until it reaches 1GB.
 // Returns an error if the new mmap size is greater than the max allowed.
 func (db *DB) mmapSize(size int) (int, error) {
 	// Double the size from 32KB until 1GB.
@@ -387,7 +397,9 @@ func (db *DB) close() error {
 		// No need to unlock read-only file.
 		if !db.readOnly {
 			// Unlock the file.
-			_ = funlock(db.file)
+			if err := funlock(db.file); err != nil {
+				log.Printf("bolt.Close(): funlock error: %s", err)
+			}
 		}
 
 		// Close the file descriptor.
@@ -406,11 +418,15 @@ func (db *DB) close() error {
 // will cause the calls to block and be serialized until the current write
 // transaction finishes.
 //
-// Transactions should not be depedent on one another. Opening a read
+// Transactions should not be dependent on one another. Opening a read
 // transaction and a write transaction in the same goroutine can cause the
 // writer to deadlock because the database periodically needs to re-mmap itself
 // as it grows and it cannot do that while a read transaction is open.
 //
+// If a long running read transaction (for example, a snapshot transaction) is
+// needed, you might want to set DB.InitialMmapSize to a large enough value
+// to avoid potential blocking of write transaction.
+//
 // IMPORTANT: You must close read-only transactions after you are finished or
 // else the database will not reclaim old pages.
 func (db *DB) Begin(writable bool) (*Tx, error) {
@@ -594,6 +610,136 @@ func (db *DB) View(fn func(*Tx) error) error {
 	return nil
 }
 
+// Batch calls fn as part of a batch. It behaves similar to Update,
+// except:
+//
+// 1. concurrent Batch calls can be combined into a single Bolt
+// transaction.
+//
+// 2. the function passed to Batch may be called multiple times,
+// regardless of whether it returns error or not.
+//
+// This means that Batch function side effects must be idempotent and
+// take permanent effect only after a successful return is seen in
+// caller.
+//
+// The maximum batch size and delay can be adjusted with DB.MaxBatchSize
+// and DB.MaxBatchDelay, respectively.
+//
+// Batch is only useful when there are multiple goroutines calling it.
+func (db *DB) Batch(fn func(*Tx) error) error {
+	errCh := make(chan error, 1)
+
+	db.batchMu.Lock()
+	if (db.batch == nil) || (db.batch != nil && len(db.batch.calls) >= db.MaxBatchSize) {
+		// There is no existing batch, or the existing batch is full; start a new one.
+		db.batch = &batch{
+			db: db,
+		}
+		db.batch.timer = time.AfterFunc(db.MaxBatchDelay, db.batch.trigger)
+	}
+	db.batch.calls = append(db.batch.calls, call{fn: fn, err: errCh})
+	if len(db.batch.calls) >= db.MaxBatchSize {
+		// wake up batch, it's ready to run
+		go db.batch.trigger()
+	}
+	db.batchMu.Unlock()
+
+	err := <-errCh
+	if err == trySolo {
+		err = db.Update(fn)
+	}
+	return err
+}
+
+type call struct {
+	fn  func(*Tx) error
+	err chan<- error
+}
+
+type batch struct {
+	db    *DB
+	timer *time.Timer
+	start sync.Once
+	calls []call
+}
+
+// trigger runs the batch if it hasn't already been run.
+func (b *batch) trigger() {
+	b.start.Do(b.run)
+}
+
+// run performs the transactions in the batch and communicates results
+// back to DB.Batch.
+func (b *batch) run() {
+	b.db.batchMu.Lock()
+	b.timer.Stop()
+	// Make sure no new work is added to this batch, but don't break
+	// other batches.
+	if b.db.batch == b {
+		b.db.batch = nil
+	}
+	b.db.batchMu.Unlock()
+
+retry:
+	for len(b.calls) > 0 {
+		var failIdx = -1
+		err := b.db.Update(func(tx *Tx) error {
+			for i, c := range b.calls {
+				if err := safelyCall(c.fn, tx); err != nil {
+					failIdx = i
+					return err
+				}
+			}
+			return nil
+		})
+
+		if failIdx >= 0 {
+			// take the failing transaction out of the batch. it's
+			// safe to shorten b.calls here because db.batch no longer
+			// points to us, and we hold the mutex anyway.
+			c := b.calls[failIdx]
+			b.calls[failIdx], b.calls = b.calls[len(b.calls)-1], b.calls[:len(b.calls)-1]
+			// tell the submitter re-run it solo, continue with the rest of the batch
+			c.err <- trySolo
+			continue retry
+		}
+
+		// pass success, or bolt internal errors, to all callers
+		for _, c := range b.calls {
+			if c.err != nil {
+				c.err <- err
+			}
+		}
+		break retry
+	}
+}
+
+// trySolo is a special sentinel error value used for signaling that a
+// transaction function should be re-run. It should never be seen by
+// callers.
+var trySolo = errors.New("batch function returned an error and should be re-run solo")
+
+type panicked struct {
+	reason interface{}
+}
+
+func (p panicked) Error() string {
+	if err, ok := p.reason.(error); ok {
+		return err.Error()
+	}
+	return fmt.Sprintf("panic: %v", p.reason)
+}
+
+func safelyCall(fn func(*Tx) error, tx *Tx) (err error) {
+	defer func() {
+		if p := recover(); p != nil {
+			err = panicked{p}
+		}
+	}()
+	return fn(tx)
+}
+
 // Sync executes fdatasync() against the database file handle.
 //
 // This is not necessary under normal operation, however, if you use NoSync
@@ -660,6 +806,36 @@ func (db *DB) allocate(count int) (*page, error) {
 	return p, nil
 }
 
+// grow grows the size of the database to the given sz.
+func (db *DB) grow(sz int) error {
+	// Ignore if the new size is less than available file size.
+	if sz <= db.filesz {
+		return nil
+	}
+
+	// If the data is smaller than the alloc size then only allocate what's needed.
+	// Once it goes over the allocation size then allocate in chunks.
+	if db.datasz < db.AllocSize {
+		sz = db.datasz
+	} else {
+		sz += db.AllocSize
+	}
+
+	// Truncate and fsync to ensure file size metadata is flushed.
+	// https://github.com/boltdb/bolt/issues/284
+	if !db.NoGrowSync && !db.readOnly {
+		if err := db.file.Truncate(int64(sz)); err != nil {
+			return fmt.Errorf("file resize error: %s", err)
+		}
+		if err := db.file.Sync(); err != nil {
+			return fmt.Errorf("file sync error: %s", err)
+		}
+	}
+
+	db.filesz = sz
+	return nil
+}
+
 func (db *DB) IsReadOnly() bool {
 	return db.readOnly
 }
@@ -680,6 +856,16 @@ type Options struct {
 
 	// Sets the DB.MmapFlags flag before memory mapping the file.
 	MmapFlags int
+
+	// InitialMmapSize is the initial mmap size of the database
+	// in bytes. Read transactions won't block write transaction
+	// if the InitialMmapSize is large enough to hold database mmap
+	// size. (See DB.Begin for more information)
+	//
+	// If <=0, the initial map size is 0.
+	// If initialMmapSize is smaller than the previous database size,
+	// it takes no effect.
+	InitialMmapSize int
 }
 
 // DefaultOptions represent the options used if nil options are passed into Open().

+ 0 - 907
Godeps/_workspace/src/github.com/boltdb/bolt/db_test.go

@@ -1,907 +0,0 @@
-package bolt_test
-
-import (
-	"encoding/binary"
-	"errors"
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"regexp"
-	"runtime"
-	"sort"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-var statsFlag = flag.Bool("stats", false, "show performance stats")
-
-// Ensure that opening a database with a bad path returns an error.
-func TestOpen_BadPath(t *testing.T) {
-	db, err := bolt.Open("", 0666, nil)
-	assert(t, err != nil, "err: %s", err)
-	assert(t, db == nil, "")
-}
-
-// Ensure that a database can be opened without error.
-func TestOpen(t *testing.T) {
-	path := tempfile()
-	defer os.Remove(path)
-	db, err := bolt.Open(path, 0666, nil)
-	assert(t, db != nil, "")
-	ok(t, err)
-	equals(t, db.Path(), path)
-	ok(t, db.Close())
-}
-
-// Ensure that opening an already open database file will timeout.
-func TestOpen_Timeout(t *testing.T) {
-	if runtime.GOOS == "solaris" {
-		t.Skip("solaris fcntl locks don't support intra-process locking")
-	}
-
-	path := tempfile()
-	defer os.Remove(path)
-
-	// Open a data file.
-	db0, err := bolt.Open(path, 0666, nil)
-	assert(t, db0 != nil, "")
-	ok(t, err)
-
-	// Attempt to open the database again.
-	start := time.Now()
-	db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 100 * time.Millisecond})
-	assert(t, db1 == nil, "")
-	equals(t, bolt.ErrTimeout, err)
-	assert(t, time.Since(start) > 100*time.Millisecond, "")
-
-	db0.Close()
-}
-
-// Ensure that opening an already open database file will wait until its closed.
-func TestOpen_Wait(t *testing.T) {
-	if runtime.GOOS == "solaris" {
-		t.Skip("solaris fcntl locks don't support intra-process locking")
-	}
-
-	path := tempfile()
-	defer os.Remove(path)
-
-	// Open a data file.
-	db0, err := bolt.Open(path, 0666, nil)
-	assert(t, db0 != nil, "")
-	ok(t, err)
-
-	// Close it in just a bit.
-	time.AfterFunc(100*time.Millisecond, func() { db0.Close() })
-
-	// Attempt to open the database again.
-	start := time.Now()
-	db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 200 * time.Millisecond})
-	assert(t, db1 != nil, "")
-	ok(t, err)
-	assert(t, time.Since(start) > 100*time.Millisecond, "")
-}
-
-// Ensure that opening a database does not increase its size.
-// https://github.com/boltdb/bolt/issues/291
-func TestOpen_Size(t *testing.T) {
-	// Open a data file.
-	db := NewTestDB()
-	path := db.Path()
-	defer db.Close()
-
-	// Insert until we get above the minimum 4MB size.
-	ok(t, db.Update(func(tx *bolt.Tx) error {
-		b, _ := tx.CreateBucketIfNotExists([]byte("data"))
-		for i := 0; i < 10000; i++ {
-			ok(t, b.Put([]byte(fmt.Sprintf("%04d", i)), make([]byte, 1000)))
-		}
-		return nil
-	}))
-
-	// Close database and grab the size.
-	db.DB.Close()
-	sz := fileSize(path)
-	if sz == 0 {
-		t.Fatalf("unexpected new file size: %d", sz)
-	}
-
-	// Reopen database, update, and check size again.
-	db0, err := bolt.Open(path, 0666, nil)
-	ok(t, err)
-	ok(t, db0.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}) }))
-	ok(t, db0.Close())
-	newSz := fileSize(path)
-	if newSz == 0 {
-		t.Fatalf("unexpected new file size: %d", newSz)
-	}
-
-	// Compare the original size with the new size.
-	if sz != newSz {
-		t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
-	}
-}
-
-// Ensure that opening a database beyond the max step size does not increase its size.
-// https://github.com/boltdb/bolt/issues/303
-func TestOpen_Size_Large(t *testing.T) {
-	if testing.Short() {
-		t.Skip("short mode")
-	}
-
-	// Open a data file.
-	db := NewTestDB()
-	path := db.Path()
-	defer db.Close()
-
-	// Insert until we get above the minimum 4MB size.
-	var index uint64
-	for i := 0; i < 10000; i++ {
-		ok(t, db.Update(func(tx *bolt.Tx) error {
-			b, _ := tx.CreateBucketIfNotExists([]byte("data"))
-			for j := 0; j < 1000; j++ {
-				ok(t, b.Put(u64tob(index), make([]byte, 50)))
-				index++
-			}
-			return nil
-		}))
-	}
-
-	// Close database and grab the size.
-	db.DB.Close()
-	sz := fileSize(path)
-	if sz == 0 {
-		t.Fatalf("unexpected new file size: %d", sz)
-	} else if sz < (1 << 30) {
-		t.Fatalf("expected larger initial size: %d", sz)
-	}
-
-	// Reopen database, update, and check size again.
-	db0, err := bolt.Open(path, 0666, nil)
-	ok(t, err)
-	ok(t, db0.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}) }))
-	ok(t, db0.Close())
-	newSz := fileSize(path)
-	if newSz == 0 {
-		t.Fatalf("unexpected new file size: %d", newSz)
-	}
-
-	// Compare the original size with the new size.
-	if sz != newSz {
-		t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
-	}
-}
-
-// Ensure that a re-opened database is consistent.
-func TestOpen_Check(t *testing.T) {
-	path := tempfile()
-	defer os.Remove(path)
-
-	db, err := bolt.Open(path, 0666, nil)
-	ok(t, err)
-	ok(t, db.View(func(tx *bolt.Tx) error { return <-tx.Check() }))
-	db.Close()
-
-	db, err = bolt.Open(path, 0666, nil)
-	ok(t, err)
-	ok(t, db.View(func(tx *bolt.Tx) error { return <-tx.Check() }))
-	db.Close()
-}
-
-// Ensure that the database returns an error if the file handle cannot be open.
-func TestDB_Open_FileError(t *testing.T) {
-	path := tempfile()
-	defer os.Remove(path)
-
-	_, err := bolt.Open(path+"/youre-not-my-real-parent", 0666, nil)
-	assert(t, err.(*os.PathError) != nil, "")
-	equals(t, path+"/youre-not-my-real-parent", err.(*os.PathError).Path)
-	equals(t, "open", err.(*os.PathError).Op)
-}
-
-// Ensure that write errors to the meta file handler during initialization are returned.
-func TestDB_Open_MetaInitWriteError(t *testing.T) {
-	t.Skip("pending")
-}
-
-// Ensure that a database that is too small returns an error.
-func TestDB_Open_FileTooSmall(t *testing.T) {
-	path := tempfile()
-	defer os.Remove(path)
-
-	db, err := bolt.Open(path, 0666, nil)
-	ok(t, err)
-	db.Close()
-
-	// corrupt the database
-	ok(t, os.Truncate(path, int64(os.Getpagesize())))
-
-	db, err = bolt.Open(path, 0666, nil)
-	equals(t, errors.New("file size too small"), err)
-}
-
-// Ensure that a database can be opened in read-only mode by multiple processes
-// and that a database can not be opened in read-write mode and in read-only
-// mode at the same time.
-func TestOpen_ReadOnly(t *testing.T) {
-	if runtime.GOOS == "solaris" {
-		t.Skip("solaris fcntl locks don't support intra-process locking")
-	}
-
-	bucket, key, value := []byte(`bucket`), []byte(`key`), []byte(`value`)
-
-	path := tempfile()
-	defer os.Remove(path)
-
-	// Open in read-write mode.
-	db, err := bolt.Open(path, 0666, nil)
-	ok(t, db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket(bucket)
-		if err != nil {
-			return err
-		}
-		return b.Put(key, value)
-	}))
-	assert(t, db != nil, "")
-	assert(t, !db.IsReadOnly(), "")
-	ok(t, err)
-	ok(t, db.Close())
-
-	// Open in read-only mode.
-	db0, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true})
-	ok(t, err)
-	defer db0.Close()
-
-	// Opening in read-write mode should return an error.
-	_, err = bolt.Open(path, 0666, &bolt.Options{Timeout: time.Millisecond * 100})
-	assert(t, err != nil, "")
-
-	// And again (in read-only mode).
-	db1, err := bolt.Open(path, 0666, &bolt.Options{ReadOnly: true})
-	ok(t, err)
-	defer db1.Close()
-
-	// Verify both read-only databases are accessible.
-	for _, db := range []*bolt.DB{db0, db1} {
-		// Verify is is in read only mode indeed.
-		assert(t, db.IsReadOnly(), "")
-
-		// Read-only databases should not allow updates.
-		assert(t,
-			bolt.ErrDatabaseReadOnly == db.Update(func(*bolt.Tx) error {
-				panic(`should never get here`)
-			}),
-			"")
-
-		// Read-only databases should not allow beginning writable txns.
-		_, err = db.Begin(true)
-		assert(t, bolt.ErrDatabaseReadOnly == err, "")
-
-		// Verify the data.
-		ok(t, db.View(func(tx *bolt.Tx) error {
-			b := tx.Bucket(bucket)
-			if b == nil {
-				return fmt.Errorf("expected bucket `%s`", string(bucket))
-			}
-
-			got := string(b.Get(key))
-			expected := string(value)
-			if got != expected {
-				return fmt.Errorf("expected `%s`, got `%s`", expected, got)
-			}
-			return nil
-		}))
-	}
-}
-
-// TODO(benbjohnson): Test corruption at every byte of the first two pages.
-
-// Ensure that a database cannot open a transaction when it's not open.
-func TestDB_Begin_DatabaseNotOpen(t *testing.T) {
-	var db bolt.DB
-	tx, err := db.Begin(false)
-	assert(t, tx == nil, "")
-	equals(t, err, bolt.ErrDatabaseNotOpen)
-}
-
-// Ensure that a read-write transaction can be retrieved.
-func TestDB_BeginRW(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, err := db.Begin(true)
-	assert(t, tx != nil, "")
-	ok(t, err)
-	assert(t, tx.DB() == db.DB, "")
-	equals(t, tx.Writable(), true)
-	ok(t, tx.Commit())
-}
-
-// Ensure that opening a transaction while the DB is closed returns an error.
-func TestDB_BeginRW_Closed(t *testing.T) {
-	var db bolt.DB
-	tx, err := db.Begin(true)
-	equals(t, err, bolt.ErrDatabaseNotOpen)
-	assert(t, tx == nil, "")
-}
-
-func TestDB_Close_PendingTx_RW(t *testing.T) { testDB_Close_PendingTx(t, true) }
-func TestDB_Close_PendingTx_RO(t *testing.T) { testDB_Close_PendingTx(t, false) }
-
-// Ensure that a database cannot close while transactions are open.
-func testDB_Close_PendingTx(t *testing.T, writable bool) {
-	db := NewTestDB()
-	defer db.Close()
-
-	// Start transaction.
-	tx, err := db.Begin(true)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Open update in separate goroutine.
-	done := make(chan struct{})
-	go func() {
-		db.Close()
-		close(done)
-	}()
-
-	// Ensure database hasn't closed.
-	time.Sleep(100 * time.Millisecond)
-	select {
-	case <-done:
-		t.Fatal("database closed too early")
-	default:
-	}
-
-	// Commit transaction.
-	if err := tx.Commit(); err != nil {
-		t.Fatal(err)
-	}
-
-	// Ensure database closed now.
-	time.Sleep(100 * time.Millisecond)
-	select {
-	case <-done:
-	default:
-		t.Fatal("database did not close")
-	}
-}
-
-// Ensure a database can provide a transactional block.
-func TestDB_Update(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	err := db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		b.Put([]byte("foo"), []byte("bar"))
-		b.Put([]byte("baz"), []byte("bat"))
-		b.Delete([]byte("foo"))
-		return nil
-	})
-	ok(t, err)
-	err = db.View(func(tx *bolt.Tx) error {
-		assert(t, tx.Bucket([]byte("widgets")).Get([]byte("foo")) == nil, "")
-		equals(t, []byte("bat"), tx.Bucket([]byte("widgets")).Get([]byte("baz")))
-		return nil
-	})
-	ok(t, err)
-}
-
-// Ensure a closed database returns an error while running a transaction block
-func TestDB_Update_Closed(t *testing.T) {
-	var db bolt.DB
-	err := db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		return nil
-	})
-	equals(t, err, bolt.ErrDatabaseNotOpen)
-}
-
-// Ensure a panic occurs while trying to commit a managed transaction.
-func TestDB_Update_ManualCommit(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	var ok bool
-	db.Update(func(tx *bolt.Tx) error {
-		func() {
-			defer func() {
-				if r := recover(); r != nil {
-					ok = true
-				}
-			}()
-			tx.Commit()
-		}()
-		return nil
-	})
-	assert(t, ok, "expected panic")
-}
-
-// Ensure a panic occurs while trying to rollback a managed transaction.
-func TestDB_Update_ManualRollback(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	var ok bool
-	db.Update(func(tx *bolt.Tx) error {
-		func() {
-			defer func() {
-				if r := recover(); r != nil {
-					ok = true
-				}
-			}()
-			tx.Rollback()
-		}()
-		return nil
-	})
-	assert(t, ok, "expected panic")
-}
-
-// Ensure a panic occurs while trying to commit a managed transaction.
-func TestDB_View_ManualCommit(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	var ok bool
-	db.Update(func(tx *bolt.Tx) error {
-		func() {
-			defer func() {
-				if r := recover(); r != nil {
-					ok = true
-				}
-			}()
-			tx.Commit()
-		}()
-		return nil
-	})
-	assert(t, ok, "expected panic")
-}
-
-// Ensure a panic occurs while trying to rollback a managed transaction.
-func TestDB_View_ManualRollback(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	var ok bool
-	db.Update(func(tx *bolt.Tx) error {
-		func() {
-			defer func() {
-				if r := recover(); r != nil {
-					ok = true
-				}
-			}()
-			tx.Rollback()
-		}()
-		return nil
-	})
-	assert(t, ok, "expected panic")
-}
-
-// Ensure a write transaction that panics does not hold open locks.
-func TestDB_Update_Panic(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	func() {
-		defer func() {
-			if r := recover(); r != nil {
-				t.Log("recover: update", r)
-			}
-		}()
-		db.Update(func(tx *bolt.Tx) error {
-			tx.CreateBucket([]byte("widgets"))
-			panic("omg")
-		})
-	}()
-
-	// Verify we can update again.
-	err := db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-	ok(t, err)
-
-	// Verify that our change persisted.
-	err = db.Update(func(tx *bolt.Tx) error {
-		assert(t, tx.Bucket([]byte("widgets")) != nil, "")
-		return nil
-	})
-}
-
-// Ensure a database can return an error through a read-only transactional block.
-func TestDB_View_Error(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	err := db.View(func(tx *bolt.Tx) error {
-		return errors.New("xxx")
-	})
-	equals(t, errors.New("xxx"), err)
-}
-
-// Ensure a read transaction that panics does not hold open locks.
-func TestDB_View_Panic(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		return nil
-	})
-
-	func() {
-		defer func() {
-			if r := recover(); r != nil {
-				t.Log("recover: view", r)
-			}
-		}()
-		db.View(func(tx *bolt.Tx) error {
-			assert(t, tx.Bucket([]byte("widgets")) != nil, "")
-			panic("omg")
-		})
-	}()
-
-	// Verify that we can still use read transactions.
-	db.View(func(tx *bolt.Tx) error {
-		assert(t, tx.Bucket([]byte("widgets")) != nil, "")
-		return nil
-	})
-}
-
-// Ensure that an error is returned when a database write fails.
-func TestDB_Commit_WriteFail(t *testing.T) {
-	t.Skip("pending") // TODO(benbjohnson)
-}
-
-// Ensure that DB stats can be returned.
-func TestDB_Stats(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-	stats := db.Stats()
-	equals(t, 2, stats.TxStats.PageCount)
-	equals(t, 0, stats.FreePageN)
-	equals(t, 2, stats.PendingPageN)
-}
-
-// Ensure that database pages are in expected order and type.
-func TestDB_Consistency(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-
-	for i := 0; i < 10; i++ {
-		db.Update(func(tx *bolt.Tx) error {
-			ok(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")))
-			return nil
-		})
-	}
-	db.Update(func(tx *bolt.Tx) error {
-		p, _ := tx.Page(0)
-		assert(t, p != nil, "")
-		equals(t, "meta", p.Type)
-
-		p, _ = tx.Page(1)
-		assert(t, p != nil, "")
-		equals(t, "meta", p.Type)
-
-		p, _ = tx.Page(2)
-		assert(t, p != nil, "")
-		equals(t, "free", p.Type)
-
-		p, _ = tx.Page(3)
-		assert(t, p != nil, "")
-		equals(t, "free", p.Type)
-
-		p, _ = tx.Page(4)
-		assert(t, p != nil, "")
-		equals(t, "leaf", p.Type)
-
-		p, _ = tx.Page(5)
-		assert(t, p != nil, "")
-		equals(t, "freelist", p.Type)
-
-		p, _ = tx.Page(6)
-		assert(t, p == nil, "")
-		return nil
-	})
-}
-
-// Ensure that DB stats can be subtracted from one another.
-func TestDBStats_Sub(t *testing.T) {
-	var a, b bolt.Stats
-	a.TxStats.PageCount = 3
-	a.FreePageN = 4
-	b.TxStats.PageCount = 10
-	b.FreePageN = 14
-	diff := b.Sub(&a)
-	equals(t, 7, diff.TxStats.PageCount)
-	// free page stats are copied from the receiver and not subtracted
-	equals(t, 14, diff.FreePageN)
-}
-
-func ExampleDB_Update() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Execute several commands within a write transaction.
-	err := db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		if err != nil {
-			return err
-		}
-		if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
-			return err
-		}
-		return nil
-	})
-
-	// If our transactional block didn't return an error then our data is saved.
-	if err == nil {
-		db.View(func(tx *bolt.Tx) error {
-			value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-			fmt.Printf("The value of 'foo' is: %s\n", value)
-			return nil
-		})
-	}
-
-	// Output:
-	// The value of 'foo' is: bar
-}
-
-func ExampleDB_View() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Insert data into a bucket.
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("people"))
-		b := tx.Bucket([]byte("people"))
-		b.Put([]byte("john"), []byte("doe"))
-		b.Put([]byte("susy"), []byte("que"))
-		return nil
-	})
-
-	// Access data from within a read-only transactional block.
-	db.View(func(tx *bolt.Tx) error {
-		v := tx.Bucket([]byte("people")).Get([]byte("john"))
-		fmt.Printf("John's last name is %s.\n", v)
-		return nil
-	})
-
-	// Output:
-	// John's last name is doe.
-}
-
-func ExampleDB_Begin_ReadOnly() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Create a bucket.
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-
-	// Create several keys in a transaction.
-	tx, _ := db.Begin(true)
-	b := tx.Bucket([]byte("widgets"))
-	b.Put([]byte("john"), []byte("blue"))
-	b.Put([]byte("abby"), []byte("red"))
-	b.Put([]byte("zephyr"), []byte("purple"))
-	tx.Commit()
-
-	// Iterate over the values in sorted key order.
-	tx, _ = db.Begin(false)
-	c := tx.Bucket([]byte("widgets")).Cursor()
-	for k, v := c.First(); k != nil; k, v = c.Next() {
-		fmt.Printf("%s likes %s\n", k, v)
-	}
-	tx.Rollback()
-
-	// Output:
-	// abby likes red
-	// john likes blue
-	// zephyr likes purple
-}
-
-// TestDB represents a wrapper around a Bolt DB to handle temporary file
-// creation and automatic cleanup on close.
-type TestDB struct {
-	*bolt.DB
-}
-
-// NewTestDB returns a new instance of TestDB.
-func NewTestDB() *TestDB {
-	db, err := bolt.Open(tempfile(), 0666, nil)
-	if err != nil {
-		panic("cannot open db: " + err.Error())
-	}
-	return &TestDB{db}
-}
-
-// MustView executes a read-only function. Panic on error.
-func (db *TestDB) MustView(fn func(tx *bolt.Tx) error) {
-	if err := db.DB.View(func(tx *bolt.Tx) error {
-		return fn(tx)
-	}); err != nil {
-		panic(err.Error())
-	}
-}
-
-// MustUpdate executes a read-write function. Panic on error.
-func (db *TestDB) MustUpdate(fn func(tx *bolt.Tx) error) {
-	if err := db.DB.View(func(tx *bolt.Tx) error {
-		return fn(tx)
-	}); err != nil {
-		panic(err.Error())
-	}
-}
-
-// MustCreateBucket creates a new bucket. Panic on error.
-func (db *TestDB) MustCreateBucket(name []byte) {
-	if err := db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte(name))
-		return err
-	}); err != nil {
-		panic(err.Error())
-	}
-}
-
-// Close closes the database and deletes the underlying file.
-func (db *TestDB) Close() {
-	// Log statistics.
-	if *statsFlag {
-		db.PrintStats()
-	}
-
-	// Check database consistency after every test.
-	db.MustCheck()
-
-	// Close database and remove file.
-	defer os.Remove(db.Path())
-	db.DB.Close()
-}
-
-// PrintStats prints the database stats
-func (db *TestDB) PrintStats() {
-	var stats = db.Stats()
-	fmt.Printf("[db] %-20s %-20s %-20s\n",
-		fmt.Sprintf("pg(%d/%d)", stats.TxStats.PageCount, stats.TxStats.PageAlloc),
-		fmt.Sprintf("cur(%d)", stats.TxStats.CursorCount),
-		fmt.Sprintf("node(%d/%d)", stats.TxStats.NodeCount, stats.TxStats.NodeDeref),
-	)
-	fmt.Printf("     %-20s %-20s %-20s\n",
-		fmt.Sprintf("rebal(%d/%v)", stats.TxStats.Rebalance, truncDuration(stats.TxStats.RebalanceTime)),
-		fmt.Sprintf("spill(%d/%v)", stats.TxStats.Spill, truncDuration(stats.TxStats.SpillTime)),
-		fmt.Sprintf("w(%d/%v)", stats.TxStats.Write, truncDuration(stats.TxStats.WriteTime)),
-	)
-}
-
-// MustCheck runs a consistency check on the database and panics if any errors are found.
-func (db *TestDB) MustCheck() {
-	db.Update(func(tx *bolt.Tx) error {
-		// Collect all the errors.
-		var errors []error
-		for err := range tx.Check() {
-			errors = append(errors, err)
-			if len(errors) > 10 {
-				break
-			}
-		}
-
-		// If errors occurred, copy the DB and print the errors.
-		if len(errors) > 0 {
-			var path = tempfile()
-			tx.CopyFile(path, 0600)
-
-			// Print errors.
-			fmt.Print("\n\n")
-			fmt.Printf("consistency check failed (%d errors)\n", len(errors))
-			for _, err := range errors {
-				fmt.Println(err)
-			}
-			fmt.Println("")
-			fmt.Println("db saved to:")
-			fmt.Println(path)
-			fmt.Print("\n\n")
-			os.Exit(-1)
-		}
-
-		return nil
-	})
-}
-
-// CopyTempFile copies a database to a temporary file.
-func (db *TestDB) CopyTempFile() {
-	path := tempfile()
-	db.View(func(tx *bolt.Tx) error { return tx.CopyFile(path, 0600) })
-	fmt.Println("db copied to: ", path)
-}
-
-// tempfile returns a temporary file path.
-func tempfile() string {
-	f, _ := ioutil.TempFile("", "bolt-")
-	f.Close()
-	os.Remove(f.Name())
-	return f.Name()
-}
-
-// mustContainKeys checks that a bucket contains a given set of keys.
-func mustContainKeys(b *bolt.Bucket, m map[string]string) {
-	found := make(map[string]string)
-	b.ForEach(func(k, _ []byte) error {
-		found[string(k)] = ""
-		return nil
-	})
-
-	// Check for keys found in bucket that shouldn't be there.
-	var keys []string
-	for k, _ := range found {
-		if _, ok := m[string(k)]; !ok {
-			keys = append(keys, k)
-		}
-	}
-	if len(keys) > 0 {
-		sort.Strings(keys)
-		panic(fmt.Sprintf("keys found(%d): %s", len(keys), strings.Join(keys, ",")))
-	}
-
-	// Check for keys not found in bucket that should be there.
-	for k, _ := range m {
-		if _, ok := found[string(k)]; !ok {
-			keys = append(keys, k)
-		}
-	}
-	if len(keys) > 0 {
-		sort.Strings(keys)
-		panic(fmt.Sprintf("keys not found(%d): %s", len(keys), strings.Join(keys, ",")))
-	}
-}
-
-func trunc(b []byte, length int) []byte {
-	if length < len(b) {
-		return b[:length]
-	}
-	return b
-}
-
-func truncDuration(d time.Duration) string {
-	return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1")
-}
-
-func fileSize(path string) int64 {
-	fi, err := os.Stat(path)
-	if err != nil {
-		return 0
-	}
-	return fi.Size()
-}
-
-func warn(v ...interface{})              { fmt.Fprintln(os.Stderr, v...) }
-func warnf(msg string, v ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", v...) }
-
-// u64tob converts a uint64 into an 8-byte slice.
-func u64tob(v uint64) []byte {
-	b := make([]byte, 8)
-	binary.BigEndian.PutUint64(b, v)
-	return b
-}
-
-// btou64 converts an 8-byte slice into an uint64.
-func btou64(b []byte) uint64 { return binary.BigEndian.Uint64(b) }

+ 0 - 156
Godeps/_workspace/src/github.com/boltdb/bolt/freelist_test.go

@@ -1,156 +0,0 @@
-package bolt
-
-import (
-	"math/rand"
-	"reflect"
-	"sort"
-	"testing"
-	"unsafe"
-)
-
-// Ensure that a page is added to a transaction's freelist.
-func TestFreelist_free(t *testing.T) {
-	f := newFreelist()
-	f.free(100, &page{id: 12})
-	if !reflect.DeepEqual([]pgid{12}, f.pending[100]) {
-		t.Fatalf("exp=%v; got=%v", []pgid{12}, f.pending[100])
-	}
-}
-
-// Ensure that a page and its overflow is added to a transaction's freelist.
-func TestFreelist_free_overflow(t *testing.T) {
-	f := newFreelist()
-	f.free(100, &page{id: 12, overflow: 3})
-	if exp := []pgid{12, 13, 14, 15}; !reflect.DeepEqual(exp, f.pending[100]) {
-		t.Fatalf("exp=%v; got=%v", exp, f.pending[100])
-	}
-}
-
-// Ensure that a transaction's free pages can be released.
-func TestFreelist_release(t *testing.T) {
-	f := newFreelist()
-	f.free(100, &page{id: 12, overflow: 1})
-	f.free(100, &page{id: 9})
-	f.free(102, &page{id: 39})
-	f.release(100)
-	f.release(101)
-	if exp := []pgid{9, 12, 13}; !reflect.DeepEqual(exp, f.ids) {
-		t.Fatalf("exp=%v; got=%v", exp, f.ids)
-	}
-
-	f.release(102)
-	if exp := []pgid{9, 12, 13, 39}; !reflect.DeepEqual(exp, f.ids) {
-		t.Fatalf("exp=%v; got=%v", exp, f.ids)
-	}
-}
-
-// Ensure that a freelist can find contiguous blocks of pages.
-func TestFreelist_allocate(t *testing.T) {
-	f := &freelist{ids: []pgid{3, 4, 5, 6, 7, 9, 12, 13, 18}}
-	if id := int(f.allocate(3)); id != 3 {
-		t.Fatalf("exp=3; got=%v", id)
-	}
-	if id := int(f.allocate(1)); id != 6 {
-		t.Fatalf("exp=6; got=%v", id)
-	}
-	if id := int(f.allocate(3)); id != 0 {
-		t.Fatalf("exp=0; got=%v", id)
-	}
-	if id := int(f.allocate(2)); id != 12 {
-		t.Fatalf("exp=12; got=%v", id)
-	}
-	if id := int(f.allocate(1)); id != 7 {
-		t.Fatalf("exp=7; got=%v", id)
-	}
-	if id := int(f.allocate(0)); id != 0 {
-		t.Fatalf("exp=0; got=%v", id)
-	}
-	if id := int(f.allocate(0)); id != 0 {
-		t.Fatalf("exp=0; got=%v", id)
-	}
-	if exp := []pgid{9, 18}; !reflect.DeepEqual(exp, f.ids) {
-		t.Fatalf("exp=%v; got=%v", exp, f.ids)
-	}
-
-	if id := int(f.allocate(1)); id != 9 {
-		t.Fatalf("exp=9; got=%v", id)
-	}
-	if id := int(f.allocate(1)); id != 18 {
-		t.Fatalf("exp=18; got=%v", id)
-	}
-	if id := int(f.allocate(1)); id != 0 {
-		t.Fatalf("exp=0; got=%v", id)
-	}
-	if exp := []pgid{}; !reflect.DeepEqual(exp, f.ids) {
-		t.Fatalf("exp=%v; got=%v", exp, f.ids)
-	}
-}
-
-// Ensure that a freelist can deserialize from a freelist page.
-func TestFreelist_read(t *testing.T) {
-	// Create a page.
-	var buf [4096]byte
-	page := (*page)(unsafe.Pointer(&buf[0]))
-	page.flags = freelistPageFlag
-	page.count = 2
-
-	// Insert 2 page ids.
-	ids := (*[3]pgid)(unsafe.Pointer(&page.ptr))
-	ids[0] = 23
-	ids[1] = 50
-
-	// Deserialize page into a freelist.
-	f := newFreelist()
-	f.read(page)
-
-	// Ensure that there are two page ids in the freelist.
-	if exp := []pgid{23, 50}; !reflect.DeepEqual(exp, f.ids) {
-		t.Fatalf("exp=%v; got=%v", exp, f.ids)
-	}
-}
-
-// Ensure that a freelist can serialize into a freelist page.
-func TestFreelist_write(t *testing.T) {
-	// Create a freelist and write it to a page.
-	var buf [4096]byte
-	f := &freelist{ids: []pgid{12, 39}, pending: make(map[txid][]pgid)}
-	f.pending[100] = []pgid{28, 11}
-	f.pending[101] = []pgid{3}
-	p := (*page)(unsafe.Pointer(&buf[0]))
-	f.write(p)
-
-	// Read the page back out.
-	f2 := newFreelist()
-	f2.read(p)
-
-	// Ensure that the freelist is correct.
-	// All pages should be present and in reverse order.
-	if exp := []pgid{3, 11, 12, 28, 39}; !reflect.DeepEqual(exp, f2.ids) {
-		t.Fatalf("exp=%v; got=%v", exp, f2.ids)
-	}
-}
-
-func Benchmark_FreelistRelease10K(b *testing.B)    { benchmark_FreelistRelease(b, 10000) }
-func Benchmark_FreelistRelease100K(b *testing.B)   { benchmark_FreelistRelease(b, 100000) }
-func Benchmark_FreelistRelease1000K(b *testing.B)  { benchmark_FreelistRelease(b, 1000000) }
-func Benchmark_FreelistRelease10000K(b *testing.B) { benchmark_FreelistRelease(b, 10000000) }
-
-func benchmark_FreelistRelease(b *testing.B, size int) {
-	ids := randomPgids(size)
-	pending := randomPgids(len(ids) / 400)
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		f := &freelist{ids: ids, pending: map[txid][]pgid{1: pending}}
-		f.release(1)
-	}
-}
-
-func randomPgids(n int) []pgid {
-	rand.Seed(42)
-	pgids := make(pgids, n)
-	for i := range pgids {
-		pgids[i] = pgid(rand.Int63())
-	}
-	sort.Sort(pgids)
-	return pgids
-}

+ 0 - 156
Godeps/_workspace/src/github.com/boltdb/bolt/node_test.go

@@ -1,156 +0,0 @@
-package bolt
-
-import (
-	"testing"
-	"unsafe"
-)
-
-// Ensure that a node can insert a key/value.
-func TestNode_put(t *testing.T) {
-	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)
-	n.put([]byte("foo"), []byte("foo"), []byte("3"), 0, leafPageFlag)
-
-	if len(n.inodes) != 3 {
-		t.Fatalf("exp=3; got=%d", len(n.inodes))
-	}
-	if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "1" {
-		t.Fatalf("exp=<bar,1>; got=<%s,%s>", k, v)
-	}
-	if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "baz" || string(v) != "2" {
-		t.Fatalf("exp=<baz,2>; got=<%s,%s>", k, v)
-	}
-	if k, v := n.inodes[2].key, n.inodes[2].value; string(k) != "foo" || string(v) != "3" {
-		t.Fatalf("exp=<foo,3>; got=<%s,%s>", k, v)
-	}
-	if n.inodes[2].flags != uint32(leafPageFlag) {
-		t.Fatalf("not a leaf: %d", n.inodes[2].flags)
-	}
-}
-
-// Ensure that a node can deserialize from a leaf page.
-func TestNode_read_LeafPage(t *testing.T) {
-	// Create a page.
-	var buf [4096]byte
-	page := (*page)(unsafe.Pointer(&buf[0]))
-	page.flags = leafPageFlag
-	page.count = 2
-
-	// Insert 2 elements at the beginning. sizeof(leafPageElement) == 16
-	nodes := (*[3]leafPageElement)(unsafe.Pointer(&page.ptr))
-	nodes[0] = leafPageElement{flags: 0, pos: 32, ksize: 3, vsize: 4}  // pos = sizeof(leafPageElement) * 2
-	nodes[1] = leafPageElement{flags: 0, pos: 23, ksize: 10, vsize: 3} // pos = sizeof(leafPageElement) + 3 + 4
-
-	// Write data for the nodes at the end.
-	data := (*[4096]byte)(unsafe.Pointer(&nodes[2]))
-	copy(data[:], []byte("barfooz"))
-	copy(data[7:], []byte("helloworldbye"))
-
-	// Deserialize page into a leaf.
-	n := &node{}
-	n.read(page)
-
-	// Check that there are two inodes with correct data.
-	if !n.isLeaf {
-		t.Fatal("expected leaf")
-	}
-	if len(n.inodes) != 2 {
-		t.Fatalf("exp=2; got=%d", len(n.inodes))
-	}
-	if k, v := n.inodes[0].key, n.inodes[0].value; string(k) != "bar" || string(v) != "fooz" {
-		t.Fatalf("exp=<bar,fooz>; got=<%s,%s>", k, v)
-	}
-	if k, v := n.inodes[1].key, n.inodes[1].value; string(k) != "helloworld" || string(v) != "bye" {
-		t.Fatalf("exp=<helloworld,bye>; got=<%s,%s>", k, v)
-	}
-}
-
-// 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{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)
-
-	// Write it to a page.
-	var buf [4096]byte
-	p := (*page)(unsafe.Pointer(&buf[0]))
-	n.write(p)
-
-	// Read the page back in.
-	n2 := &node{}
-	n2.read(p)
-
-	// Check that the two pages are the same.
-	if len(n2.inodes) != 3 {
-		t.Fatalf("exp=3; got=%d", len(n2.inodes))
-	}
-	if k, v := n2.inodes[0].key, n2.inodes[0].value; string(k) != "john" || string(v) != "johnson" {
-		t.Fatalf("exp=<john,johnson>; got=<%s,%s>", k, v)
-	}
-	if k, v := n2.inodes[1].key, n2.inodes[1].value; string(k) != "ricki" || string(v) != "lake" {
-		t.Fatalf("exp=<ricki,lake>; got=<%s,%s>", k, v)
-	}
-	if k, v := n2.inodes[2].key, n2.inodes[2].value; string(k) != "susy" || string(v) != "que" {
-		t.Fatalf("exp=<susy,que>; got=<%s,%s>", k, v)
-	}
-}
-
-// 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{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)
-	n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
-	n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
-
-	// Split between 2 & 3.
-	n.split(100)
-
-	var parent = n.parent
-	if len(parent.children) != 2 {
-		t.Fatalf("exp=2; got=%d", len(parent.children))
-	}
-	if len(parent.children[0].inodes) != 2 {
-		t.Fatalf("exp=2; got=%d", len(parent.children[0].inodes))
-	}
-	if len(parent.children[1].inodes) != 3 {
-		t.Fatalf("exp=3; got=%d", len(parent.children[1].inodes))
-	}
-}
-
-// 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{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)
-
-	// Split.
-	n.split(20)
-	if n.parent != nil {
-		t.Fatalf("expected nil parent")
-	}
-}
-
-// 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{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)
-	n.put([]byte("00000004"), []byte("00000004"), []byte("0123456701234567"), 0, 0)
-	n.put([]byte("00000005"), []byte("00000005"), []byte("0123456701234567"), 0, 0)
-
-	// Split.
-	n.split(4096)
-	if n.parent != nil {
-		t.Fatalf("expected nil parent")
-	}
-}

+ 0 - 72
Godeps/_workspace/src/github.com/boltdb/bolt/page_test.go

@@ -1,72 +0,0 @@
-package bolt
-
-import (
-	"reflect"
-	"sort"
-	"testing"
-	"testing/quick"
-)
-
-// Ensure that the page type can be returned in human readable format.
-func TestPage_typ(t *testing.T) {
-	if typ := (&page{flags: branchPageFlag}).typ(); typ != "branch" {
-		t.Fatalf("exp=branch; got=%v", typ)
-	}
-	if typ := (&page{flags: leafPageFlag}).typ(); typ != "leaf" {
-		t.Fatalf("exp=leaf; got=%v", typ)
-	}
-	if typ := (&page{flags: metaPageFlag}).typ(); typ != "meta" {
-		t.Fatalf("exp=meta; got=%v", typ)
-	}
-	if typ := (&page{flags: freelistPageFlag}).typ(); typ != "freelist" {
-		t.Fatalf("exp=freelist; got=%v", typ)
-	}
-	if typ := (&page{flags: 20000}).typ(); typ != "unknown<4e20>" {
-		t.Fatalf("exp=unknown<4e20>; got=%v", typ)
-	}
-}
-
-// Ensure that the hexdump debugging function doesn't blow up.
-func TestPage_dump(t *testing.T) {
-	(&page{id: 256}).hexdump(16)
-}
-
-func TestPgids_merge(t *testing.T) {
-	a := pgids{4, 5, 6, 10, 11, 12, 13, 27}
-	b := pgids{1, 3, 8, 9, 25, 30}
-	c := a.merge(b)
-	if !reflect.DeepEqual(c, pgids{1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30}) {
-		t.Errorf("mismatch: %v", c)
-	}
-
-	a = pgids{4, 5, 6, 10, 11, 12, 13, 27, 35, 36}
-	b = pgids{8, 9, 25, 30}
-	c = a.merge(b)
-	if !reflect.DeepEqual(c, pgids{4, 5, 6, 8, 9, 10, 11, 12, 13, 25, 27, 30, 35, 36}) {
-		t.Errorf("mismatch: %v", c)
-	}
-}
-
-func TestPgids_merge_quick(t *testing.T) {
-	if err := quick.Check(func(a, b pgids) bool {
-		// Sort incoming lists.
-		sort.Sort(a)
-		sort.Sort(b)
-
-		// Merge the two lists together.
-		got := a.merge(b)
-
-		// The expected value should be the two lists combined and sorted.
-		exp := append(a, b...)
-		sort.Sort(exp)
-
-		if !reflect.DeepEqual(exp, got) {
-			t.Errorf("\nexp=%+v\ngot=%+v\n", exp, got)
-			return false
-		}
-
-		return true
-	}, nil); err != nil {
-		t.Fatal(err)
-	}
-}

+ 0 - 79
Godeps/_workspace/src/github.com/boltdb/bolt/quick_test.go

@@ -1,79 +0,0 @@
-package bolt_test
-
-import (
-	"bytes"
-	"flag"
-	"fmt"
-	"math/rand"
-	"os"
-	"reflect"
-	"testing/quick"
-	"time"
-)
-
-// testing/quick defaults to 5 iterations and a random seed.
-// You can override these settings from the command line:
-//
-//   -quick.count     The number of iterations to perform.
-//   -quick.seed      The seed to use for randomizing.
-//   -quick.maxitems  The maximum number of items to insert into a DB.
-//   -quick.maxksize  The maximum size of a key.
-//   -quick.maxvsize  The maximum size of a value.
-//
-
-var qcount, qseed, qmaxitems, qmaxksize, qmaxvsize int
-
-func init() {
-	flag.IntVar(&qcount, "quick.count", 5, "")
-	flag.IntVar(&qseed, "quick.seed", int(time.Now().UnixNano())%100000, "")
-	flag.IntVar(&qmaxitems, "quick.maxitems", 1000, "")
-	flag.IntVar(&qmaxksize, "quick.maxksize", 1024, "")
-	flag.IntVar(&qmaxvsize, "quick.maxvsize", 1024, "")
-	flag.Parse()
-	fmt.Fprintln(os.Stderr, "seed:", qseed)
-	fmt.Fprintf(os.Stderr, "quick settings: count=%v, items=%v, ksize=%v, vsize=%v\n", qcount, qmaxitems, qmaxksize, qmaxvsize)
-}
-
-func qconfig() *quick.Config {
-	return &quick.Config{
-		MaxCount: qcount,
-		Rand:     rand.New(rand.NewSource(int64(qseed))),
-	}
-}
-
-type testdata []testdataitem
-
-func (t testdata) Len() int           { return len(t) }
-func (t testdata) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
-func (t testdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == -1 }
-
-func (t testdata) Generate(rand *rand.Rand, size int) reflect.Value {
-	n := rand.Intn(qmaxitems-1) + 1
-	items := make(testdata, n)
-	for i := 0; i < n; i++ {
-		item := &items[i]
-		item.Key = randByteSlice(rand, 1, qmaxksize)
-		item.Value = randByteSlice(rand, 0, qmaxvsize)
-	}
-	return reflect.ValueOf(items)
-}
-
-type revtestdata []testdataitem
-
-func (t revtestdata) Len() int           { return len(t) }
-func (t revtestdata) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
-func (t revtestdata) Less(i, j int) bool { return bytes.Compare(t[i].Key, t[j].Key) == 1 }
-
-type testdataitem struct {
-	Key   []byte
-	Value []byte
-}
-
-func randByteSlice(rand *rand.Rand, minSize, maxSize int) []byte {
-	n := rand.Intn(maxSize-minSize) + minSize
-	b := make([]byte, n)
-	for i := 0; i < n; i++ {
-		b[i] = byte(rand.Intn(255))
-	}
-	return b
-}

+ 0 - 327
Godeps/_workspace/src/github.com/boltdb/bolt/simulation_test.go

@@ -1,327 +0,0 @@
-package bolt_test
-
-import (
-	"bytes"
-	"fmt"
-	"math/rand"
-	"sync"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-func TestSimulate_1op_1p(t *testing.T)     { testSimulate(t, 100, 1) }
-func TestSimulate_10op_1p(t *testing.T)    { testSimulate(t, 10, 1) }
-func TestSimulate_100op_1p(t *testing.T)   { testSimulate(t, 100, 1) }
-func TestSimulate_1000op_1p(t *testing.T)  { testSimulate(t, 1000, 1) }
-func TestSimulate_10000op_1p(t *testing.T) { testSimulate(t, 10000, 1) }
-
-func TestSimulate_10op_10p(t *testing.T)    { testSimulate(t, 10, 10) }
-func TestSimulate_100op_10p(t *testing.T)   { testSimulate(t, 100, 10) }
-func TestSimulate_1000op_10p(t *testing.T)  { testSimulate(t, 1000, 10) }
-func TestSimulate_10000op_10p(t *testing.T) { testSimulate(t, 10000, 10) }
-
-func TestSimulate_100op_100p(t *testing.T)   { testSimulate(t, 100, 100) }
-func TestSimulate_1000op_100p(t *testing.T)  { testSimulate(t, 1000, 100) }
-func TestSimulate_10000op_100p(t *testing.T) { testSimulate(t, 10000, 100) }
-
-func TestSimulate_10000op_1000p(t *testing.T) { testSimulate(t, 10000, 1000) }
-
-// Randomly generate operations on a given database with multiple clients to ensure consistency and thread safety.
-func testSimulate(t *testing.T, threadCount, parallelism int) {
-	if testing.Short() {
-		t.Skip("skipping test in short mode.")
-	}
-
-	rand.Seed(int64(qseed))
-
-	// A list of operations that readers and writers can perform.
-	var readerHandlers = []simulateHandler{simulateGetHandler}
-	var writerHandlers = []simulateHandler{simulateGetHandler, simulatePutHandler}
-
-	var versions = make(map[int]*QuickDB)
-	versions[1] = NewQuickDB()
-
-	db := NewTestDB()
-	defer db.Close()
-
-	var mutex sync.Mutex
-
-	// Run n threads in parallel, each with their own operation.
-	var wg sync.WaitGroup
-	var threads = make(chan bool, parallelism)
-	var i int
-	for {
-		threads <- true
-		wg.Add(1)
-		writable := ((rand.Int() % 100) < 20) // 20% writers
-
-		// Choose an operation to execute.
-		var handler simulateHandler
-		if writable {
-			handler = writerHandlers[rand.Intn(len(writerHandlers))]
-		} else {
-			handler = readerHandlers[rand.Intn(len(readerHandlers))]
-		}
-
-		// Execute a thread for the given operation.
-		go func(writable bool, handler simulateHandler) {
-			defer wg.Done()
-
-			// Start transaction.
-			tx, err := db.Begin(writable)
-			if err != nil {
-				t.Fatal("tx begin: ", err)
-			}
-
-			// Obtain current state of the dataset.
-			mutex.Lock()
-			var qdb = versions[tx.ID()]
-			if writable {
-				qdb = versions[tx.ID()-1].Copy()
-			}
-			mutex.Unlock()
-
-			// Make sure we commit/rollback the tx at the end and update the state.
-			if writable {
-				defer func() {
-					mutex.Lock()
-					versions[tx.ID()] = qdb
-					mutex.Unlock()
-
-					ok(t, tx.Commit())
-				}()
-			} else {
-				defer tx.Rollback()
-			}
-
-			// Ignore operation if we don't have data yet.
-			if qdb == nil {
-				return
-			}
-
-			// Execute handler.
-			handler(tx, qdb)
-
-			// Release a thread back to the scheduling loop.
-			<-threads
-		}(writable, handler)
-
-		i++
-		if i > threadCount {
-			break
-		}
-	}
-
-	// Wait until all threads are done.
-	wg.Wait()
-}
-
-type simulateHandler func(tx *bolt.Tx, qdb *QuickDB)
-
-// Retrieves a key from the database and verifies that it is what is expected.
-func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) {
-	// Randomly retrieve an existing exist.
-	keys := qdb.Rand()
-	if len(keys) == 0 {
-		return
-	}
-
-	// Retrieve root bucket.
-	b := tx.Bucket(keys[0])
-	if b == nil {
-		panic(fmt.Sprintf("bucket[0] expected: %08x\n", trunc(keys[0], 4)))
-	}
-
-	// Drill into nested buckets.
-	for _, key := range keys[1 : len(keys)-1] {
-		b = b.Bucket(key)
-		if b == nil {
-			panic(fmt.Sprintf("bucket[n] expected: %v -> %v\n", keys, key))
-		}
-	}
-
-	// Verify key/value on the final bucket.
-	expected := qdb.Get(keys)
-	actual := b.Get(keys[len(keys)-1])
-	if !bytes.Equal(actual, expected) {
-		fmt.Println("=== EXPECTED ===")
-		fmt.Println(expected)
-		fmt.Println("=== ACTUAL ===")
-		fmt.Println(actual)
-		fmt.Println("=== END ===")
-		panic("value mismatch")
-	}
-}
-
-// Inserts a key into the database.
-func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) {
-	var err error
-	keys, value := randKeys(), randValue()
-
-	// Retrieve root bucket.
-	b := tx.Bucket(keys[0])
-	if b == nil {
-		b, err = tx.CreateBucket(keys[0])
-		if err != nil {
-			panic("create bucket: " + err.Error())
-		}
-	}
-
-	// Create nested buckets, if necessary.
-	for _, key := range keys[1 : len(keys)-1] {
-		child := b.Bucket(key)
-		if child != nil {
-			b = child
-		} else {
-			b, err = b.CreateBucket(key)
-			if err != nil {
-				panic("create bucket: " + err.Error())
-			}
-		}
-	}
-
-	// Insert into database.
-	if err := b.Put(keys[len(keys)-1], value); err != nil {
-		panic("put: " + err.Error())
-	}
-
-	// Insert into in-memory database.
-	qdb.Put(keys, value)
-}
-
-// QuickDB is an in-memory database that replicates the functionality of the
-// Bolt DB type except that it is entirely in-memory. It is meant for testing
-// that the Bolt database is consistent.
-type QuickDB struct {
-	sync.RWMutex
-	m map[string]interface{}
-}
-
-// NewQuickDB returns an instance of QuickDB.
-func NewQuickDB() *QuickDB {
-	return &QuickDB{m: make(map[string]interface{})}
-}
-
-// Get retrieves the value at a key path.
-func (db *QuickDB) Get(keys [][]byte) []byte {
-	db.RLock()
-	defer db.RUnlock()
-
-	m := db.m
-	for _, key := range keys[:len(keys)-1] {
-		value := m[string(key)]
-		if value == nil {
-			return nil
-		}
-		switch value := value.(type) {
-		case map[string]interface{}:
-			m = value
-		case []byte:
-			return nil
-		}
-	}
-
-	// Only return if it's a simple value.
-	if value, ok := m[string(keys[len(keys)-1])].([]byte); ok {
-		return value
-	}
-	return nil
-}
-
-// Put inserts a value into a key path.
-func (db *QuickDB) Put(keys [][]byte, value []byte) {
-	db.Lock()
-	defer db.Unlock()
-
-	// Build buckets all the way down the key path.
-	m := db.m
-	for _, key := range keys[:len(keys)-1] {
-		if _, ok := m[string(key)].([]byte); ok {
-			return // Keypath intersects with a simple value. Do nothing.
-		}
-
-		if m[string(key)] == nil {
-			m[string(key)] = make(map[string]interface{})
-		}
-		m = m[string(key)].(map[string]interface{})
-	}
-
-	// Insert value into the last key.
-	m[string(keys[len(keys)-1])] = value
-}
-
-// Rand returns a random key path that points to a simple value.
-func (db *QuickDB) Rand() [][]byte {
-	db.RLock()
-	defer db.RUnlock()
-	if len(db.m) == 0 {
-		return nil
-	}
-	var keys [][]byte
-	db.rand(db.m, &keys)
-	return keys
-}
-
-func (db *QuickDB) rand(m map[string]interface{}, keys *[][]byte) {
-	i, index := 0, rand.Intn(len(m))
-	for k, v := range m {
-		if i == index {
-			*keys = append(*keys, []byte(k))
-			if v, ok := v.(map[string]interface{}); ok {
-				db.rand(v, keys)
-			}
-			return
-		}
-		i++
-	}
-	panic("quickdb rand: out-of-range")
-}
-
-// Copy copies the entire database.
-func (db *QuickDB) Copy() *QuickDB {
-	db.RLock()
-	defer db.RUnlock()
-	return &QuickDB{m: db.copy(db.m)}
-}
-
-func (db *QuickDB) copy(m map[string]interface{}) map[string]interface{} {
-	clone := make(map[string]interface{}, len(m))
-	for k, v := range m {
-		switch v := v.(type) {
-		case map[string]interface{}:
-			clone[k] = db.copy(v)
-		default:
-			clone[k] = v
-		}
-	}
-	return clone
-}
-
-func randKey() []byte {
-	var min, max = 1, 1024
-	n := rand.Intn(max-min) + min
-	b := make([]byte, n)
-	for i := 0; i < n; i++ {
-		b[i] = byte(rand.Intn(255))
-	}
-	return b
-}
-
-func randKeys() [][]byte {
-	var keys [][]byte
-	var count = rand.Intn(2) + 2
-	for i := 0; i < count; i++ {
-		keys = append(keys, randKey())
-	}
-	return keys
-}
-
-func randValue() []byte {
-	n := rand.Intn(8192)
-	b := make([]byte, n)
-	for i := 0; i < n; i++ {
-		b[i] = byte(rand.Intn(255))
-	}
-	return b
-}

+ 13 - 3
Godeps/_workspace/src/github.com/boltdb/bolt/tx.go

@@ -168,6 +168,8 @@ func (tx *Tx) Commit() error {
 	// Free the old root bucket.
 	tx.meta.root.root = tx.root.root
 
+	opgid := tx.meta.pgid
+
 	// Free the freelist and allocate new pages for it. This will overestimate
 	// the size of the freelist but not underestimate the size (which would be bad).
 	tx.db.freelist.free(tx.meta.txid, tx.db.page(tx.meta.freelist))
@@ -182,6 +184,14 @@ func (tx *Tx) Commit() error {
 	}
 	tx.meta.freelist = p.id
 
+	// If the high water mark has moved up then attempt to grow the database.
+	if tx.meta.pgid > opgid {
+		if err := tx.db.grow(int(tx.meta.pgid+1) * tx.db.pageSize); err != nil {
+			tx.rollback()
+			return err
+		}
+	}
+
 	// Write dirty pages to disk.
 	startTime = time.Now()
 	if err := tx.write(); err != nil {
@@ -271,7 +281,7 @@ func (tx *Tx) close() {
 }
 
 // Copy writes the entire database to a writer.
-// This function exists for backwards compatibility. Use WriteTo() in
+// This function exists for backwards compatibility. Use WriteTo() instead.
 func (tx *Tx) Copy(w io.Writer) error {
 	_, err := tx.WriteTo(w)
 	return err
@@ -285,7 +295,7 @@ func (tx *Tx) WriteTo(w io.Writer) (n int64, err error) {
 	if err != nil {
 		return 0, err
 	}
-	defer f.Close()
+	defer func() { _ = f.Close() }()
 
 	// Copy the meta pages.
 	tx.db.metalock.Lock()
@@ -505,7 +515,7 @@ func (tx *Tx) writeMeta() error {
 }
 
 // page returns a reference to the page with a given id.
-// If page has been written to then a temporary bufferred page is returned.
+// If page has been written to then a temporary buffered page is returned.
 func (tx *Tx) page(id pgid) *page {
 	// Check the dirty pages first.
 	if tx.pages != nil {

+ 0 - 456
Godeps/_workspace/src/github.com/boltdb/bolt/tx_test.go

@@ -1,456 +0,0 @@
-package bolt_test
-
-import (
-	"errors"
-	"fmt"
-	"os"
-	"testing"
-
-	"github.com/coreos/etcd/Godeps/_workspace/src/github.com/boltdb/bolt"
-)
-
-// Ensure that committing a closed transaction returns an error.
-func TestTx_Commit_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	tx.CreateBucket([]byte("foo"))
-	ok(t, tx.Commit())
-	equals(t, tx.Commit(), bolt.ErrTxClosed)
-}
-
-// Ensure that rolling back a closed transaction returns an error.
-func TestTx_Rollback_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	ok(t, tx.Rollback())
-	equals(t, tx.Rollback(), bolt.ErrTxClosed)
-}
-
-// Ensure that committing a read-only transaction returns an error.
-func TestTx_Commit_ReadOnly(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(false)
-	equals(t, tx.Commit(), bolt.ErrTxNotWritable)
-}
-
-// Ensure that a transaction can retrieve a cursor on the root bucket.
-func TestTx_Cursor(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.CreateBucket([]byte("woojits"))
-		c := tx.Cursor()
-
-		k, v := c.First()
-		equals(t, "widgets", string(k))
-		assert(t, v == nil, "")
-
-		k, v = c.Next()
-		equals(t, "woojits", string(k))
-		assert(t, v == nil, "")
-
-		k, v = c.Next()
-		assert(t, k == nil, "")
-		assert(t, v == nil, "")
-
-		return nil
-	})
-}
-
-// Ensure that creating a bucket with a read-only transaction returns an error.
-func TestTx_CreateBucket_ReadOnly(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.View(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("foo"))
-		assert(t, b == nil, "")
-		equals(t, bolt.ErrTxNotWritable, err)
-		return nil
-	})
-}
-
-// Ensure that creating a bucket on a closed transaction returns an error.
-func TestTx_CreateBucket_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	tx.Commit()
-	b, err := tx.CreateBucket([]byte("foo"))
-	assert(t, b == nil, "")
-	equals(t, bolt.ErrTxClosed, err)
-}
-
-// Ensure that a Tx can retrieve a bucket.
-func TestTx_Bucket(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		b := tx.Bucket([]byte("widgets"))
-		assert(t, b != nil, "")
-		return nil
-	})
-}
-
-// Ensure that a Tx retrieving a non-existent key returns nil.
-func TestTx_Get_Missing(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		value := tx.Bucket([]byte("widgets")).Get([]byte("no_such_key"))
-		assert(t, value == nil, "")
-		return nil
-	})
-}
-
-// Ensure that a bucket can be created and retrieved.
-func TestTx_CreateBucket(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	// Create a bucket.
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		assert(t, b != nil, "")
-		ok(t, err)
-		return nil
-	})
-
-	// Read the bucket through a separate transaction.
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		assert(t, b != nil, "")
-		return nil
-	})
-}
-
-// Ensure that a bucket can be created if it doesn't already exist.
-func TestTx_CreateBucketIfNotExists(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucketIfNotExists([]byte("widgets"))
-		assert(t, b != nil, "")
-		ok(t, err)
-
-		b, err = tx.CreateBucketIfNotExists([]byte("widgets"))
-		assert(t, b != nil, "")
-		ok(t, err)
-
-		b, err = tx.CreateBucketIfNotExists([]byte{})
-		assert(t, b == nil, "")
-		equals(t, bolt.ErrBucketNameRequired, err)
-
-		b, err = tx.CreateBucketIfNotExists(nil)
-		assert(t, b == nil, "")
-		equals(t, bolt.ErrBucketNameRequired, err)
-		return nil
-	})
-
-	// Read the bucket through a separate transaction.
-	db.View(func(tx *bolt.Tx) error {
-		b := tx.Bucket([]byte("widgets"))
-		assert(t, b != nil, "")
-		return nil
-	})
-}
-
-// Ensure that a bucket cannot be created twice.
-func TestTx_CreateBucket_Exists(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	// Create a bucket.
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		assert(t, b != nil, "")
-		ok(t, err)
-		return nil
-	})
-
-	// Create the same bucket again.
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket([]byte("widgets"))
-		assert(t, b == nil, "")
-		equals(t, bolt.ErrBucketExists, err)
-		return nil
-	})
-}
-
-// Ensure that a bucket is created with a non-blank name.
-func TestTx_CreateBucket_NameRequired(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		b, err := tx.CreateBucket(nil)
-		assert(t, b == nil, "")
-		equals(t, bolt.ErrBucketNameRequired, err)
-		return nil
-	})
-}
-
-// Ensure that a bucket can be deleted.
-func TestTx_DeleteBucket(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-
-	// Create a bucket and add a value.
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		return nil
-	})
-
-	// Delete the bucket and make sure we can't get the value.
-	db.Update(func(tx *bolt.Tx) error {
-		ok(t, tx.DeleteBucket([]byte("widgets")))
-		assert(t, tx.Bucket([]byte("widgets")) == nil, "")
-		return nil
-	})
-
-	db.Update(func(tx *bolt.Tx) error {
-		// Create the bucket again and make sure there's not a phantom value.
-		b, err := tx.CreateBucket([]byte("widgets"))
-		assert(t, b != nil, "")
-		ok(t, err)
-		assert(t, tx.Bucket([]byte("widgets")).Get([]byte("foo")) == nil, "")
-		return nil
-	})
-}
-
-// Ensure that deleting a bucket on a closed transaction returns an error.
-func TestTx_DeleteBucket_Closed(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	tx, _ := db.Begin(true)
-	tx.Commit()
-	equals(t, tx.DeleteBucket([]byte("foo")), bolt.ErrTxClosed)
-}
-
-// Ensure that deleting a bucket with a read-only transaction returns an error.
-func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.View(func(tx *bolt.Tx) error {
-		equals(t, tx.DeleteBucket([]byte("foo")), bolt.ErrTxNotWritable)
-		return nil
-	})
-}
-
-// Ensure that nothing happens when deleting a bucket that doesn't exist.
-func TestTx_DeleteBucket_NotFound(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		equals(t, bolt.ErrBucketNotFound, tx.DeleteBucket([]byte("widgets")))
-		return nil
-	})
-}
-
-// Ensure that no error is returned when a tx.ForEach function does not return
-// an error.
-func TestTx_ForEach_NoError(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-
-		equals(t, nil, tx.ForEach(func(name []byte, b *bolt.Bucket) error {
-			return nil
-		}))
-		return nil
-	})
-}
-
-// Ensure that an error is returned when a tx.ForEach function returns an error.
-func TestTx_ForEach_WithError(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-
-		err := errors.New("foo")
-		equals(t, err, tx.ForEach(func(name []byte, b *bolt.Bucket) error {
-			return err
-		}))
-		return nil
-	})
-}
-
-// Ensure that Tx commit handlers are called after a transaction successfully commits.
-func TestTx_OnCommit(t *testing.T) {
-	var x int
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.OnCommit(func() { x += 1 })
-		tx.OnCommit(func() { x += 2 })
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-	equals(t, 3, x)
-}
-
-// Ensure that Tx commit handlers are NOT called after a transaction rolls back.
-func TestTx_OnCommit_Rollback(t *testing.T) {
-	var x int
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.OnCommit(func() { x += 1 })
-		tx.OnCommit(func() { x += 2 })
-		tx.CreateBucket([]byte("widgets"))
-		return errors.New("rollback this commit")
-	})
-	equals(t, 0, x)
-}
-
-// Ensure that the database can be copied to a file path.
-func TestTx_CopyFile(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	var dest = tempfile()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
-		return nil
-	})
-
-	ok(t, db.View(func(tx *bolt.Tx) error { return tx.CopyFile(dest, 0600) }))
-
-	db2, err := bolt.Open(dest, 0600, nil)
-	ok(t, err)
-	defer db2.Close()
-
-	db2.View(func(tx *bolt.Tx) error {
-		equals(t, []byte("bar"), tx.Bucket([]byte("widgets")).Get([]byte("foo")))
-		equals(t, []byte("bat"), tx.Bucket([]byte("widgets")).Get([]byte("baz")))
-		return nil
-	})
-}
-
-type failWriterError struct{}
-
-func (failWriterError) Error() string {
-	return "error injected for tests"
-}
-
-type failWriter struct {
-	// fail after this many bytes
-	After int
-}
-
-func (f *failWriter) Write(p []byte) (n int, err error) {
-	n = len(p)
-	if n > f.After {
-		n = f.After
-		err = failWriterError{}
-	}
-	f.After -= n
-	return n, err
-}
-
-// Ensure that Copy handles write errors right.
-func TestTx_CopyFile_Error_Meta(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
-		return nil
-	})
-
-	err := db.View(func(tx *bolt.Tx) error { return tx.Copy(&failWriter{}) })
-	equals(t, err.Error(), "meta copy: error injected for tests")
-}
-
-// Ensure that Copy handles write errors right.
-func TestTx_CopyFile_Error_Normal(t *testing.T) {
-	db := NewTestDB()
-	defer db.Close()
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat"))
-		return nil
-	})
-
-	err := db.View(func(tx *bolt.Tx) error { return tx.Copy(&failWriter{3 * db.Info().PageSize}) })
-	equals(t, err.Error(), "error injected for tests")
-}
-
-func ExampleTx_Rollback() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Create a bucket.
-	db.Update(func(tx *bolt.Tx) error {
-		_, err := tx.CreateBucket([]byte("widgets"))
-		return err
-	})
-
-	// Set a value for a key.
-	db.Update(func(tx *bolt.Tx) error {
-		return tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-	})
-
-	// Update the key but rollback the transaction so it never saves.
-	tx, _ := db.Begin(true)
-	b := tx.Bucket([]byte("widgets"))
-	b.Put([]byte("foo"), []byte("baz"))
-	tx.Rollback()
-
-	// Ensure that our original value is still set.
-	db.View(func(tx *bolt.Tx) error {
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		fmt.Printf("The value for 'foo' is still: %s\n", value)
-		return nil
-	})
-
-	// Output:
-	// The value for 'foo' is still: bar
-}
-
-func ExampleTx_CopyFile() {
-	// Open the database.
-	db, _ := bolt.Open(tempfile(), 0666, nil)
-	defer os.Remove(db.Path())
-	defer db.Close()
-
-	// Create a bucket and a key.
-	db.Update(func(tx *bolt.Tx) error {
-		tx.CreateBucket([]byte("widgets"))
-		tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))
-		return nil
-	})
-
-	// Copy the database to another file.
-	toFile := tempfile()
-	db.View(func(tx *bolt.Tx) error { return tx.CopyFile(toFile, 0666) })
-	defer os.Remove(toFile)
-
-	// Open the cloned database.
-	db2, _ := bolt.Open(toFile, 0666, nil)
-	defer db2.Close()
-
-	// Ensure that the key exists in the copy.
-	db2.View(func(tx *bolt.Tx) error {
-		value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
-		fmt.Printf("The value for 'foo' in the clone is: %s\n", value)
-		return nil
-	})
-
-	// Output:
-	// The value for 'foo' in the clone is: bar
-}