func (b *BoltDB) Delete(key string) error {
	var (
		db  *bolt.DB
		err error
	)
	b.Lock()
	defer b.Unlock()
	if db, err = b.getDBhandle(); err != nil {
		return err
	}
	defer b.releaseDBhandle()
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(b.boltBucket)
		if bucket == nil {
			return store.ErrKeyNotFound
		}
		err := bucket.Delete([]byte(key))
		return err
	})
	return err
}
Delete the value for the given key.
package boltdb
import (
	"bytes"
	"encoding/binary"
	"errors"
	"os"
	"path/filepath"
	"sync"
	"sync/atomic"
	"time"
	"github.com/boltdb/bolt"
	"github.com/docker/libkv"
	"github.com/docker/libkv/store"
)
var (
	ErrMultipleEndpointsUnsupported = errors.New("boltdb supports one endpoint and should be a file path")
	ErrBoltBucketOptionMissing = errors.New("boltBucket config option missing")
)
const (
	filePerm os.FileMode = 0644
)
type BoltDB struct {
	client     *bolt.DB
	boltBucket []byte
	dbIndex    uint64
	path       string
	timeout    time.Duration
	PersistConnection bool
	sync.Mutex
}
const (
	libkvmetadatalen = 8
	transientTimeout = time.Duration(10) * time.Second
)
func Register() {
	libkv.AddStore(store.BOLTDB, New)
}
func New(endpoints []string, options *store.Config) (store.Store, error) {
	var (
		db          *bolt.DB
		err         error
		boltOptions *bolt.Options
		timeout     = transientTimeout
	)
	if len(endpoints) > 1 {
		return nil, ErrMultipleEndpointsUnsupported
	}
	if (options == nil) || (len(options.Bucket) == 0) {
		return nil, ErrBoltBucketOptionMissing
	}
	dir, _ := filepath.Split(endpoints[0])
	if err = os.MkdirAll(dir, 0750); err != nil {
		return nil, err
	}
	if options.PersistConnection {
		boltOptions = &bolt.Options{Timeout: options.ConnectionTimeout}
		db, err = bolt.Open(endpoints[0], filePerm, boltOptions)
		if err != nil {
			return nil, err
		}
	}
	if options.ConnectionTimeout != 0 {
		timeout = options.ConnectionTimeout
	}
	b := &BoltDB{
		client:            db,
		path:              endpoints[0],
		boltBucket:        []byte(options.Bucket),
		timeout:           timeout,
		PersistConnection: options.PersistConnection,
	}
	return b, nil
}
func (b *BoltDB) reset() {
	b.path = ""
	b.boltBucket = []byte{}
}
func (b *BoltDB) getDBhandle() (*bolt.DB, error) {
	var (
		db  *bolt.DB
		err error
	)
	if !b.PersistConnection {
		boltOptions := &bolt.Options{Timeout: b.timeout}
		if db, err = bolt.Open(b.path, filePerm, boltOptions); err != nil {
			return nil, err
		}
		b.client = db
	}
	return b.client, nil
}
func (b *BoltDB) releaseDBhandle() {
	if !b.PersistConnection {
		b.client.Close()
	}
}
func (b *BoltDB) Get(key string) (*store.KVPair, error) {
	var (
		val []byte
		db  *bolt.DB
		err error
	)
	b.Lock()
	defer b.Unlock()
	if db, err = b.getDBhandle(); err != nil {
		return nil, err
	}
	defer b.releaseDBhandle()
	err = db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(b.boltBucket)
		if bucket == nil {
			return store.ErrKeyNotFound
		}
		v := bucket.Get([]byte(key))
		val = make([]byte, len(v))
		copy(val, v)
		return nil
	})
	if len(val) == 0 {
		return nil, store.ErrKeyNotFound
	}
	if err != nil {
		return nil, err
	}
	dbIndex := binary.LittleEndian.Uint64(val[:libkvmetadatalen])
	val = val[libkvmetadatalen:]
	return &store.KVPair{Key: key, Value: val, LastIndex: (dbIndex)}, nil
}
func (b *BoltDB) Put(key string, value []byte, opts *store.WriteOptions) error {
	var (
		dbIndex uint64
		db      *bolt.DB
		err     error
	)
	b.Lock()
	defer b.Unlock()
	dbval := make([]byte, libkvmetadatalen)
	if db, err = b.getDBhandle(); err != nil {
		return err
	}
	defer b.releaseDBhandle()
	err = db.Update(func(tx *bolt.Tx) error {
		bucket, err := tx.CreateBucketIfNotExists(b.boltBucket)
		if err != nil {
			return err
		}
		dbIndex = atomic.AddUint64(&b.dbIndex, 1)
		binary.LittleEndian.PutUint64(dbval, dbIndex)
		dbval = append(dbval, value...)
		err = bucket.Put([]byte(key), dbval)
		if err != nil {
			return err
		}
		return nil
	})
	return err
}