github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/search/bleve_leveldb_store.go (about)

     1  // Copyright 2019 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package search
     6  
     7  import (
     8  	"github.com/blevesearch/bleve/index/store"
     9  	"github.com/keybase/client/go/kbfs/libfs"
    10  	"github.com/pkg/errors"
    11  	"github.com/syndtr/goleveldb/leveldb"
    12  	ldberrors "github.com/syndtr/goleveldb/leveldb/errors"
    13  	"github.com/syndtr/goleveldb/leveldb/iterator"
    14  	"github.com/syndtr/goleveldb/leveldb/storage"
    15  	"github.com/syndtr/goleveldb/leveldb/util"
    16  	billy "gopkg.in/src-d/go-billy.v4"
    17  )
    18  
    19  type bleveLevelDBIterator struct {
    20  	iter iterator.Iterator
    21  }
    22  
    23  var _ store.KVIterator = (*bleveLevelDBIterator)(nil)
    24  
    25  // Seek implements the store.KVIterator interface for bleveLevelDBIterator.
    26  func (bldbi *bleveLevelDBIterator) Seek(key []byte) {
    27  	_ = bldbi.iter.Seek(key)
    28  }
    29  
    30  // Next implements the store.KVIterator interface for bleveLevelDBIterator.
    31  func (bldbi *bleveLevelDBIterator) Next() {
    32  	_ = bldbi.iter.Next()
    33  }
    34  
    35  // Key implements the store.KVIterator interface for bleveLevelDBIterator.
    36  func (bldbi *bleveLevelDBIterator) Key() []byte {
    37  	return bldbi.iter.Key()
    38  }
    39  
    40  // Value implements the store.KVIterator interface for bleveLevelDBIterator.
    41  func (bldbi *bleveLevelDBIterator) Value() []byte {
    42  	return bldbi.iter.Value()
    43  }
    44  
    45  // Valid implements the store.KVIterator interface for bleveLevelDBIterator.
    46  func (bldbi *bleveLevelDBIterator) Valid() bool {
    47  	return bldbi.iter.Valid()
    48  }
    49  
    50  // Current implements the store.KVIterator interface for bleveLevelDBIterator.
    51  func (bldbi *bleveLevelDBIterator) Current() ([]byte, []byte, bool) {
    52  	return bldbi.Key(), bldbi.Value(), bldbi.Valid()
    53  }
    54  
    55  // Close implements the store.KVIterator interface for bleveLevelDBIterator.
    56  func (bldbi *bleveLevelDBIterator) Close() error {
    57  	bldbi.iter.Release()
    58  	return nil
    59  }
    60  
    61  type bleveLevelDBReader struct {
    62  	snap *leveldb.Snapshot
    63  }
    64  
    65  var _ store.KVReader = (*bleveLevelDBReader)(nil)
    66  
    67  // Get implements the store.KVReader interface for bleveLevelDBReader.
    68  func (bldbr *bleveLevelDBReader) Get(key []byte) ([]byte, error) {
    69  	v, err := bldbr.snap.Get(key, nil)
    70  	if err == ldberrors.ErrNotFound {
    71  		return nil, nil
    72  	}
    73  	return v, err
    74  }
    75  
    76  // MultiGet implements the store.KVReader interface for bleveLevelDBReader.
    77  func (bldbr *bleveLevelDBReader) MultiGet(keys [][]byte) (
    78  	values [][]byte, err error) {
    79  	return store.MultiGet(bldbr, keys)
    80  }
    81  
    82  // PrefixIterator implements the store.KVReader interface for bleveLevelDBReader.
    83  func (bldbr *bleveLevelDBReader) PrefixIterator(prefix []byte) store.KVIterator {
    84  	r := util.BytesPrefix(prefix)
    85  	i := &bleveLevelDBIterator{
    86  		iter: bldbr.snap.NewIterator(r, nil),
    87  	}
    88  	i.Next()
    89  	return i
    90  }
    91  
    92  // RangeIterator implements the store.KVReader interface for bleveLevelDBReader.
    93  func (bldbr *bleveLevelDBReader) RangeIterator(
    94  	start, end []byte) store.KVIterator {
    95  	i := &bleveLevelDBIterator{
    96  		iter: bldbr.snap.NewIterator(&util.Range{
    97  			Start: start,
    98  			Limit: end,
    99  		}, nil),
   100  	}
   101  	i.Next()
   102  	return i
   103  }
   104  
   105  // Close implements the store.KVReader interface for bleveLevelDBReader.
   106  func (bldbr *bleveLevelDBReader) Close() error {
   107  	bldbr.snap.Release()
   108  	return nil
   109  }
   110  
   111  type bleveLevelDBBatch struct {
   112  	b *leveldb.Batch
   113  	m *store.EmulatedMerge
   114  }
   115  
   116  func newbleveLevelDBBatch(
   117  	totalBytes int, mo store.MergeOperator) *bleveLevelDBBatch {
   118  	return &bleveLevelDBBatch{
   119  		b: leveldb.MakeBatch(totalBytes),
   120  		m: store.NewEmulatedMerge(mo),
   121  	}
   122  }
   123  
   124  var _ store.KVBatch = (*bleveLevelDBBatch)(nil)
   125  
   126  func (bldbb *bleveLevelDBBatch) Set(key, val []byte) {
   127  	bldbb.b.Put(key, val)
   128  }
   129  
   130  func (bldbb *bleveLevelDBBatch) Delete(key []byte) {
   131  	bldbb.b.Delete(key)
   132  }
   133  
   134  func (bldbb *bleveLevelDBBatch) Merge(key, val []byte) {
   135  	// Adapted from github.com/blevesearch/bleve/index/store/batch.go.
   136  	ck := make([]byte, len(key))
   137  	copy(ck, key)
   138  	cv := make([]byte, len(val))
   139  	copy(cv, val)
   140  	bldbb.m.Merge(key, val)
   141  }
   142  
   143  func (bldbb *bleveLevelDBBatch) Reset() {
   144  	bldbb.b.Reset()
   145  }
   146  
   147  func (bldbb *bleveLevelDBBatch) Close() error {
   148  	return nil
   149  }
   150  
   151  type bleveLevelDBWriter struct {
   152  	db *leveldb.DB
   153  	mo store.MergeOperator
   154  }
   155  
   156  var _ store.KVWriter = (*bleveLevelDBWriter)(nil)
   157  
   158  // NewBatch implements the store.KVReader interface for bleveLevelDBWriter.
   159  func (bldbw *bleveLevelDBWriter) NewBatch() store.KVBatch {
   160  	return newbleveLevelDBBatch(0, bldbw.mo)
   161  }
   162  
   163  // NewBatchEx implements the store.KVReader interface for bleveLevelDBWriter.
   164  func (bldbw *bleveLevelDBWriter) NewBatchEx(opts store.KVBatchOptions) (
   165  	[]byte, store.KVBatch, error) {
   166  	return make([]byte, opts.TotalBytes),
   167  		newbleveLevelDBBatch(opts.TotalBytes, bldbw.mo), nil
   168  }
   169  
   170  // ExecuteBatch implements the store.KVReader interface for bleveLevelDBWriter.
   171  func (bldbw *bleveLevelDBWriter) ExecuteBatch(batch store.KVBatch) error {
   172  	b, ok := batch.(*bleveLevelDBBatch)
   173  	if !ok {
   174  		return errors.Errorf("Unexpected batch type: %T", batch)
   175  	}
   176  
   177  	// Adapted from github.com/blevesearch/bleve/index/store/boltdb/writer.go.
   178  	for k, mergeOps := range b.m.Merges {
   179  		kb := []byte(k)
   180  		existingVal, err := bldbw.db.Get(kb, nil)
   181  		if err == ldberrors.ErrNotFound {
   182  			existingVal = nil
   183  		} else if err != nil {
   184  			return err
   185  		}
   186  
   187  		mergedVal, fullMergeOk := bldbw.mo.FullMerge(kb, existingVal, mergeOps)
   188  		if !fullMergeOk {
   189  			return errors.Errorf("merge operator returned failure")
   190  		}
   191  		b.Set(kb, mergedVal)
   192  	}
   193  
   194  	return bldbw.db.Write(b.b, nil)
   195  }
   196  
   197  // Close implements the store.KVReader interface for bleveLevelDBWriter.
   198  func (bldbw *bleveLevelDBWriter) Close() error {
   199  	// Does this need to close outstanding batches allocated by this writer?
   200  	return nil
   201  }
   202  
   203  type bleveLevelDBStore struct {
   204  	s  storage.Storage
   205  	db *leveldb.DB
   206  	mo store.MergeOperator
   207  }
   208  
   209  var _ store.KVStore = (*bleveLevelDBStore)(nil)
   210  
   211  func newBleveLevelDBStore(
   212  	bfs billy.Filesystem, readOnly bool, mo store.MergeOperator) (
   213  	*bleveLevelDBStore, error) {
   214  	s, err := libfs.OpenLevelDBStorage(bfs, readOnly)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	db, err := leveldb.Open(s, nil)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return &bleveLevelDBStore{s: s, db: db, mo: mo}, nil
   223  }
   224  
   225  // Writer implements the store.KVStore interface for bleveLevelDBStore.
   226  func (bldbs *bleveLevelDBStore) Writer() (store.KVWriter, error) {
   227  	return &bleveLevelDBWriter{db: bldbs.db, mo: bldbs.mo}, nil
   228  }
   229  
   230  // Writer implements the store.KVStore interface for bleveLevelDBStore.
   231  func (bldbs *bleveLevelDBStore) Reader() (store.KVReader, error) {
   232  	snap, err := bldbs.db.GetSnapshot()
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	return &bleveLevelDBReader{snap: snap}, nil
   237  }
   238  
   239  // close implements the store.KVStore interface for bleveLevelDBStore.
   240  func (bldbs *bleveLevelDBStore) Close() error {
   241  	err := bldbs.db.Close()
   242  	if err != nil {
   243  		return err
   244  	}
   245  	return bldbs.s.Close()
   246  }