From fb048f6c64396c9cc0081bc864c5baca8a7c9d1a Mon Sep 17 00:00:00 2001 From: Steve Yen Date: Wed, 13 Jan 2016 15:12:10 -0800 Subject: [PATCH] added KVReader.MultiGet() method --- index/store/boltdb/reader.go | 4 ++++ index/store/goleveldb/reader.go | 4 ++++ index/store/gtreap/reader.go | 4 ++++ index/store/kvstore.go | 3 +++ index/store/metrics/reader.go | 10 ++++++++++ index/store/metrics/store.go | 7 +++++++ index/store/multiget.go | 28 ++++++++++++++++++++++++++++ index/store/null/null.go | 4 ++++ 8 files changed, 64 insertions(+) create mode 100644 index/store/multiget.go diff --git a/index/store/boltdb/reader.go b/index/store/boltdb/reader.go index efb3e5dd..f8138c5d 100644 --- a/index/store/boltdb/reader.go +++ b/index/store/boltdb/reader.go @@ -30,6 +30,10 @@ func (r *Reader) Get(key []byte) ([]byte, error) { return rv, nil } +func (r *Reader) MultiGet(keys [][]byte) ([][]byte, error) { + return store.MultiGet(r, keys) +} + func (r *Reader) PrefixIterator(prefix []byte) store.KVIterator { cursor := r.bucket.Cursor() diff --git a/index/store/goleveldb/reader.go b/index/store/goleveldb/reader.go index 7807d571..ec423679 100644 --- a/index/store/goleveldb/reader.go +++ b/index/store/goleveldb/reader.go @@ -28,6 +28,10 @@ func (r *Reader) Get(key []byte) ([]byte, error) { return b, err } +func (r *Reader) MultiGet(keys [][]byte) ([][]byte, error) { + return store.MultiGet(r, keys) +} + func (r *Reader) PrefixIterator(prefix []byte) store.KVIterator { byteRange := util.BytesPrefix(prefix) iter := r.snapshot.NewIterator(byteRange, r.store.defaultReadOptions) diff --git a/index/store/gtreap/reader.go b/index/store/gtreap/reader.go index 6f92a751..842d5e97 100644 --- a/index/store/gtreap/reader.go +++ b/index/store/gtreap/reader.go @@ -35,6 +35,10 @@ func (w *Reader) Get(k []byte) (v []byte, err error) { return nil, nil } +func (r *Reader) MultiGet(keys [][]byte) ([][]byte, error) { + return store.MultiGet(r, keys) +} + func (w *Reader) PrefixIterator(k []byte) store.KVIterator { rv := Iterator{ t: w.t, diff --git a/index/store/kvstore.go b/index/store/kvstore.go index d1ecea3e..3bdd0c5c 100644 --- a/index/store/kvstore.go +++ b/index/store/kvstore.go @@ -40,6 +40,9 @@ type KVReader interface { // The caller owns the bytes returned. Get(key []byte) ([]byte, error) + // MultiGet retrieves multiple values in one call. + MultiGet(keys [][]byte) ([][]byte, error) + // PrefixIterator returns a KVIterator that will // visit all K/V pairs with the provided prefix PrefixIterator(prefix []byte) KVIterator diff --git a/index/store/metrics/reader.go b/index/store/metrics/reader.go index c555c736..01fd8182 100644 --- a/index/store/metrics/reader.go +++ b/index/store/metrics/reader.go @@ -17,6 +17,16 @@ func (r *Reader) Get(key []byte) (v []byte, err error) { return } +func (r *Reader) MultiGet(keys [][]byte) (vals [][]byte, err error) { + r.s.TimerReaderMultiGet.Time(func() { + vals, err = r.o.MultiGet(keys) + if err != nil { + r.s.AddError("Reader.MultiGet", err, nil) + } + }) + return +} + func (r *Reader) PrefixIterator(prefix []byte) (i store.KVIterator) { r.s.TimerReaderPrefixIterator.Time(func() { i = &Iterator{s: r.s, o: r.o.PrefixIterator(prefix)} diff --git a/index/store/metrics/store.go b/index/store/metrics/store.go index c7889e51..c97c7829 100644 --- a/index/store/metrics/store.go +++ b/index/store/metrics/store.go @@ -33,6 +33,7 @@ type Store struct { o store.KVStore TimerReaderGet metrics.Timer + TimerReaderMultiGet metrics.Timer TimerReaderPrefixIterator metrics.Timer TimerReaderRangeIterator metrics.Timer TimerWriterExecuteBatch metrics.Timer @@ -71,6 +72,7 @@ func New(mo store.MergeOperator, config map[string]interface{}) (store.KVStore, o: kvs, TimerReaderGet: metrics.NewTimer(), + TimerReaderMultiGet: metrics.NewTimer(), TimerReaderPrefixIterator: metrics.NewTimer(), TimerReaderRangeIterator: metrics.NewTimer(), TimerWriterExecuteBatch: metrics.NewTimer(), @@ -141,6 +143,11 @@ func (s *Store) WriteJSON(w io.Writer) (err error) { return } WriteTimerJSON(w, s.TimerReaderGet) + _, err = w.Write([]byte(`,"TimerReaderMultiGet":`)) + if err != nil { + return + } + WriteTimerJSON(w, s.TimerReaderMultiGet) _, err = w.Write([]byte(`,"TimerReaderPrefixIterator":`)) if err != nil { return diff --git a/index/store/multiget.go b/index/store/multiget.go new file mode 100644 index 00000000..bab50530 --- /dev/null +++ b/index/store/multiget.go @@ -0,0 +1,28 @@ +// Copyright (c) 2016 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 store + +// MultiGet is a helper function to retrieve mutiple keys from a +// KVReader, and might be used by KVStore implementations that don't +// have a native multi-get facility. +func MultiGet(kvreader KVReader, keys [][]byte) ([][]byte, error) { + vals := make([][]byte, 0, len(keys)) + + for i, key := range keys { + val, err := kvreader.Get(key) + if err != nil { + return nil, err + } + + vals[i] = val + } + + return vals, nil +} diff --git a/index/store/null/null.go b/index/store/null/null.go index 92be3330..10730664 100644 --- a/index/store/null/null.go +++ b/index/store/null/null.go @@ -40,6 +40,10 @@ func (r *reader) Get(key []byte) ([]byte, error) { return nil, nil } +func (r *reader) MultiGet(keys [][]byte) ([][]byte, error) { + return make([][]byte, len(keys)), nil +} + func (r *reader) PrefixIterator(prefix []byte) store.KVIterator { return &iterator{} }