From a993fa4f74e95e76fb54442f4193b62d5cc1a2e8 Mon Sep 17 00:00:00 2001 From: deoxxa Date: Sun, 24 Aug 2014 17:06:44 +1000 Subject: [PATCH] add boltdb storage type --- index/store/boltdb/batch.go | 63 ++++++++++++++++++ index/store/boltdb/iterator.go | 72 ++++++++++++++++++++ index/store/boltdb/store.go | 109 +++++++++++++++++++++++++++++++ index/store/boltdb/store_test.go | 26 ++++++++ 4 files changed, 270 insertions(+) create mode 100644 index/store/boltdb/batch.go create mode 100644 index/store/boltdb/iterator.go create mode 100644 index/store/boltdb/store.go create mode 100644 index/store/boltdb/store_test.go diff --git a/index/store/boltdb/batch.go b/index/store/boltdb/batch.go new file mode 100644 index 00000000..f046629a --- /dev/null +++ b/index/store/boltdb/batch.go @@ -0,0 +1,63 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +package boltdb + +import ( + "github.com/boltdb/bolt" +) + +type op struct { + k []byte + v []byte +} + +type BoltDBBatch struct { + store *BoltDBStore + ops []op +} + +func newBoltDBBatch(store *BoltDBStore) *BoltDBBatch { + rv := BoltDBBatch{ + store: store, + ops: make([]op, 0), + } + return &rv +} + +func (i *BoltDBBatch) Set(key, val []byte) { + i.ops = append(i.ops, op{key, val}) +} + +func (i *BoltDBBatch) Delete(key []byte) { + i.ops = append(i.ops, op{key, nil}) +} + +func (i *BoltDBBatch) Execute() error { + return i.store.db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte(i.store.bucket)) + + for _, o := range i.ops { + if o.v == nil { + if err := b.Delete(o.k); err != nil { + return err + } + } else { + if err := b.Put(o.k, o.v); err != nil { + return err + } + } + } + + return nil + }) +} + +func (i *BoltDBBatch) Close() error { + return nil +} diff --git a/index/store/boltdb/iterator.go b/index/store/boltdb/iterator.go new file mode 100644 index 00000000..97fef90c --- /dev/null +++ b/index/store/boltdb/iterator.go @@ -0,0 +1,72 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +package boltdb + +import ( + "github.com/boltdb/bolt" +) + +type BoltDBIterator struct { + store *BoltDBStore + tx *bolt.Tx + cursor *bolt.Cursor + valid bool + key []byte + val []byte +} + +func newBoltDBIterator(store *BoltDBStore) *BoltDBIterator { + tx, _ := store.db.Begin(false) + b := tx.Bucket([]byte(store.bucket)) + cursor := b.Cursor() + + return &BoltDBIterator{ + store: store, + tx: tx, + cursor: cursor, + } +} + +func (i *BoltDBIterator) SeekFirst() { + i.key, i.val = i.cursor.First() + + i.valid = (i.key != nil) +} + +func (i *BoltDBIterator) Seek(k []byte) { + i.key, i.val = i.cursor.Seek(k) + + i.valid = (i.key != nil) +} + +func (i *BoltDBIterator) Next() { + i.key, i.val = i.cursor.Next() + + i.valid = (i.key != nil) +} + +func (i *BoltDBIterator) Current() ([]byte, []byte, bool) { + return i.key, i.val, i.valid +} + +func (i *BoltDBIterator) Key() []byte { + return i.key +} + +func (i *BoltDBIterator) Value() []byte { + return i.val +} + +func (i *BoltDBIterator) Valid() bool { + return i.valid +} + +func (i *BoltDBIterator) Close() { + i.tx.Commit() +} diff --git a/index/store/boltdb/store.go b/index/store/boltdb/store.go new file mode 100644 index 00000000..94a18bc6 --- /dev/null +++ b/index/store/boltdb/store.go @@ -0,0 +1,109 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +package boltdb + +import ( + "fmt" + + "github.com/boltdb/bolt" + "github.com/couchbaselabs/bleve/index/store" + "github.com/couchbaselabs/bleve/registry" +) + +const Name = "boltdb" + +type BoltDBStore struct { + path string + bucket string + db *bolt.DB +} + +func Open(path string, bucket string) (*BoltDBStore, error) { + rv := BoltDBStore{ + path: path, + bucket: bucket, + } + + var err error + rv.db, err = bolt.Open(path, 0600, nil) + if err != nil { + return nil, err + } + + err = rv.db.Update(func(tx *bolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte(rv.bucket)) + + return err + }) + if err != nil { + return nil, err + } + + return &rv, nil +} + +func (bs *BoltDBStore) Get(key []byte) ([]byte, error) { + var rv []byte = nil + + err := bs.db.View(func(tx *bolt.Tx) error { + rv = tx.Bucket([]byte(bs.bucket)).Get(key) + + return nil + }) + + return rv, err +} + +func (bs *BoltDBStore) Set(key, val []byte) error { + return bs.db.Update(func(tx *bolt.Tx) error { + return tx.Bucket([]byte(bs.bucket)).Put(key, val) + }) +} + +func (bs *BoltDBStore) Delete(key []byte) error { + return bs.db.Update(func(tx *bolt.Tx) error { + return tx.Bucket([]byte(bs.bucket)).Delete(key) + }) +} + +func (bs *BoltDBStore) Commit() error { + return nil +} + +func (bs *BoltDBStore) Close() error { + return bs.db.Close() +} + +func (bs *BoltDBStore) Iterator(key []byte) store.KVIterator { + rv := newBoltDBIterator(bs) + rv.Seek(key) + return rv +} + +func (bs *BoltDBStore) NewBatch() store.KVBatch { + return newBoltDBBatch(bs) +} + +func StoreConstructor(config map[string]interface{}) (store.KVStore, error) { + path, ok := config["path"].(string) + if !ok { + return nil, fmt.Errorf("must specify path") + } + + bucket, ok := config["bucket"].(string) + if !ok { + bucket = "index" + } + + return Open(path, bucket) +} + +func init() { + registry.RegisterKVStore(Name, StoreConstructor) +} diff --git a/index/store/boltdb/store_test.go b/index/store/boltdb/store_test.go new file mode 100644 index 00000000..034767d6 --- /dev/null +++ b/index/store/boltdb/store_test.go @@ -0,0 +1,26 @@ +// Copyright (c) 2014 Couchbase, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software distributed under the +// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +// either express or implied. See the License for the specific language governing permissions +// and limitations under the License. +package boltdb + +import ( + "os" + "testing" + + "github.com/couchbaselabs/bleve/index/store/test" +) + +func TestBoltDBStore(t *testing.T) { + s, err := Open("test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll("test") + + store_test.CommonTestKVStore(t, s) +}