Summary: Similar to v2 (db and table code understands prefixes), but use ReadOptions as in v3. Also, make the CreateFilter code faster and cleaner. Test Plan: make db_test; export LEVELDB_TESTS=PrefixScan; ./db_test Reviewers: dhruba Reviewed By: dhruba CC: haobo, emayanke Differential Revision: https://reviews.facebook.net/D12027main
parent
3b81df34bd
commit
f5f1842282
@ -0,0 +1,76 @@ |
|||||||
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||||
|
//
|
||||||
|
// Wrap an underlying iterator, but exclude any results not starting
|
||||||
|
// with a given prefix. Seeking to keys not beginning with the prefix
|
||||||
|
// is invalid, and SeekToLast is not implemented (that would be
|
||||||
|
// non-trivial), but otherwise this iterator will behave just like the
|
||||||
|
// underlying iterator would if there happened to be no non-matching
|
||||||
|
// keys in the dataset.
|
||||||
|
|
||||||
|
#ifndef STORAGE_LEVELDB_DB_PREFIX_FILTER_ITERATOR_H_ |
||||||
|
#define STORAGE_LEVELDB_DB_PREFIX_FILTER_ITERATOR_H_ |
||||||
|
|
||||||
|
#include "leveldb/iterator.h" |
||||||
|
|
||||||
|
namespace leveldb { |
||||||
|
|
||||||
|
class PrefixFilterIterator : public Iterator { |
||||||
|
private: |
||||||
|
Iterator* iter_; |
||||||
|
const Slice &prefix_; |
||||||
|
const SliceTransform *prefix_extractor_; |
||||||
|
Status status_; |
||||||
|
|
||||||
|
public: |
||||||
|
PrefixFilterIterator(Iterator* iter, |
||||||
|
const Slice &prefix, |
||||||
|
const SliceTransform* prefix_extractor) |
||||||
|
: iter_(iter), prefix_(prefix), |
||||||
|
prefix_extractor_(prefix_extractor), |
||||||
|
status_(Status::OK()) { |
||||||
|
if (prefix_extractor == nullptr) { |
||||||
|
status_ = Status::InvalidArgument("A prefix filter may not be used " |
||||||
|
"unless a function is also defined " |
||||||
|
"for extracting prefixes"); |
||||||
|
} else if (!prefix_extractor_->InRange(prefix)) { |
||||||
|
status_ = Status::InvalidArgument("Must provide a slice for prefix which" |
||||||
|
"is a prefix for some key"); |
||||||
|
} |
||||||
|
} |
||||||
|
~PrefixFilterIterator() { |
||||||
|
delete iter_; |
||||||
|
} |
||||||
|
Slice key() const { return iter_->key(); } |
||||||
|
Slice value() const { return iter_->value(); } |
||||||
|
Status status() const { |
||||||
|
if (!status_.ok()) { |
||||||
|
return status_; |
||||||
|
} |
||||||
|
return iter_->status(); |
||||||
|
} |
||||||
|
void Next() { iter_->Next(); } |
||||||
|
void Prev() { iter_->Prev(); } |
||||||
|
void Seek(const Slice& k) { |
||||||
|
if (prefix_extractor_->Transform(k) == prefix_) { |
||||||
|
iter_->Seek(k); |
||||||
|
} else { |
||||||
|
status_ = Status::InvalidArgument("Seek must begin with target prefix"); |
||||||
|
} |
||||||
|
} |
||||||
|
void SeekToFirst() { |
||||||
|
Seek(prefix_); |
||||||
|
} |
||||||
|
void SeekToLast() { |
||||||
|
status_ = Status::NotSupported("SeekToLast is incompatible with prefixes"); |
||||||
|
} |
||||||
|
bool Valid() const { |
||||||
|
return (status_.ok() && iter_->Valid() && |
||||||
|
prefix_extractor_->Transform(iter_->key()) == prefix_); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace leveldb
|
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,41 @@ |
|||||||
|
// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||||
|
//
|
||||||
|
// Class for specifying user-defined functions which perform a
|
||||||
|
// transformation on a slice. It is not required that every slice
|
||||||
|
// belong to the domain and/or range of a function. Subclasses should
|
||||||
|
// define InDomain and InRange to determine which slices are in either
|
||||||
|
// of these sets respectively.
|
||||||
|
|
||||||
|
#ifndef STORAGE_LEVELDB_INCLUDE_SLICE_TRANSFORM_H_ |
||||||
|
#define STORAGE_LEVELDB_INCLUDE_SLICE_TRANSFORM_H_ |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
namespace leveldb { |
||||||
|
|
||||||
|
class Slice; |
||||||
|
|
||||||
|
class SliceTransform { |
||||||
|
public: |
||||||
|
virtual ~SliceTransform() {}; |
||||||
|
|
||||||
|
// Return the name of this transformation.
|
||||||
|
virtual const char* Name() const = 0; |
||||||
|
|
||||||
|
// transform a src in domain to a dst in the range
|
||||||
|
virtual Slice Transform(const Slice& src) const = 0; |
||||||
|
|
||||||
|
// determine whether this is a valid src upon the function applies
|
||||||
|
virtual bool InDomain(const Slice& src) const = 0; |
||||||
|
|
||||||
|
// determine whether dst=Transform(src) for some src
|
||||||
|
virtual bool InRange(const Slice& dst) const = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
extern const SliceTransform* NewFixedPrefixTransform(size_t prefix_len); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
#endif // STORAGE_LEVELDB_INCLUDE_SLICE_TRANSFORM_H_
|
@ -0,0 +1,43 @@ |
|||||||
|
// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||||
|
|
||||||
|
#include "leveldb/slice_transform.h" |
||||||
|
|
||||||
|
#include "leveldb/slice.h" |
||||||
|
|
||||||
|
namespace leveldb { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
class FixedPrefixTransform : public SliceTransform { |
||||||
|
private: |
||||||
|
size_t prefix_len_; |
||||||
|
|
||||||
|
public: |
||||||
|
explicit FixedPrefixTransform(size_t prefix_len) : prefix_len_(prefix_len) { } |
||||||
|
|
||||||
|
virtual const char* Name() const { |
||||||
|
return "rocksdb.FixedPrefix"; |
||||||
|
} |
||||||
|
|
||||||
|
virtual Slice Transform(const Slice& src) const { |
||||||
|
assert(InDomain(src)); |
||||||
|
return Slice(src.data(), prefix_len_); |
||||||
|
} |
||||||
|
|
||||||
|
virtual bool InDomain(const Slice& src) const { |
||||||
|
return (src.size() >= prefix_len_); |
||||||
|
} |
||||||
|
|
||||||
|
virtual bool InRange(const Slice& dst) const { |
||||||
|
return (dst.size() == prefix_len_); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
const SliceTransform* NewFixedPrefixTransform(size_t prefix_len) { |
||||||
|
return new FixedPrefixTransform(prefix_len); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace leveldb
|
Loading…
Reference in new issue