leveldb-ruby 0.14 → 0.15
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +24 -0
- data/README +60 -16
- data/ext/leveldb/extconf.rb +1 -1
- data/ext/leveldb/leveldb.cc +187 -18
- data/leveldb/Makefile +82 -96
- data/leveldb/build_detect_platform +137 -51
- data/leveldb/db/c.cc +110 -0
- data/leveldb/db/db_bench.cc +105 -4
- data/leveldb/db/db_impl.cc +135 -45
- data/leveldb/db/db_impl.h +12 -10
- data/leveldb/db/db_test.cc +666 -431
- data/leveldb/db/dbformat.cc +20 -0
- data/leveldb/db/dbformat.h +12 -0
- data/leveldb/db/repair.cc +3 -1
- data/leveldb/db/skiplist.h +2 -1
- data/leveldb/db/table_cache.cc +42 -16
- data/leveldb/db/table_cache.h +11 -0
- data/leveldb/db/version_set.cc +46 -41
- data/leveldb/db/version_set.h +9 -0
- data/leveldb/db/write_batch.cc +13 -4
- data/leveldb/db/write_batch_internal.h +2 -0
- data/leveldb/db/write_batch_test.cc +31 -0
- data/leveldb/include/leveldb/c.h +29 -0
- data/leveldb/include/leveldb/db.h +2 -1
- data/leveldb/include/leveldb/filter_policy.h +70 -0
- data/leveldb/include/leveldb/options.h +8 -0
- data/leveldb/include/leveldb/status.h +6 -0
- data/leveldb/include/leveldb/table.h +15 -0
- data/leveldb/include/leveldb/table_builder.h +1 -0
- data/leveldb/port/atomic_pointer.h +13 -5
- data/leveldb/port/port.h +0 -2
- data/leveldb/port/port_example.h +10 -0
- data/leveldb/port/port_posix.cc +4 -0
- data/leveldb/port/port_posix.h +24 -9
- data/leveldb/table/block.cc +8 -4
- data/leveldb/table/block.h +3 -2
- data/leveldb/table/filter_block.cc +111 -0
- data/leveldb/table/filter_block.h +68 -0
- data/leveldb/table/filter_block_test.cc +128 -0
- data/leveldb/table/format.cc +17 -7
- data/leveldb/table/format.h +9 -4
- data/leveldb/table/table.cc +107 -6
- data/leveldb/table/table_builder.cc +49 -6
- data/leveldb/table/table_test.cc +8 -24
- data/leveldb/util/bloom.cc +95 -0
- data/leveldb/util/bloom_test.cc +159 -0
- data/leveldb/util/coding_test.cc +23 -0
- data/leveldb/util/comparator.cc +8 -3
- data/leveldb/util/env_posix.cc +46 -4
- data/leveldb/util/filter_policy.cc +11 -0
- data/leveldb/util/options.cc +2 -1
- data/lib/leveldb.rb +31 -5
- metadata +227 -109
- data/leveldb/port/port_android.cc +0 -64
- data/leveldb/port/port_android.h +0 -156
@@ -0,0 +1,70 @@
|
|
1
|
+
// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
4
|
+
//
|
5
|
+
// A database can be configured with a custom FilterPolicy object.
|
6
|
+
// This object is responsible for creating a small filter from a set
|
7
|
+
// of keys. These filters are stored in leveldb and are consulted
|
8
|
+
// automatically by leveldb to decide whether or not to read some
|
9
|
+
// information from disk. In many cases, a filter can cut down the
|
10
|
+
// number of disk seeks form a handful to a single disk seek per
|
11
|
+
// DB::Get() call.
|
12
|
+
//
|
13
|
+
// Most people will want to use the builtin bloom filter support (see
|
14
|
+
// NewBloomFilterPolicy() below).
|
15
|
+
|
16
|
+
#ifndef STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
17
|
+
#define STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
18
|
+
|
19
|
+
#include <string>
|
20
|
+
|
21
|
+
namespace leveldb {
|
22
|
+
|
23
|
+
class Slice;
|
24
|
+
|
25
|
+
class FilterPolicy {
|
26
|
+
public:
|
27
|
+
virtual ~FilterPolicy();
|
28
|
+
|
29
|
+
// Return the name of this policy. Note that if the filter encoding
|
30
|
+
// changes in an incompatible way, the name returned by this method
|
31
|
+
// must be changed. Otherwise, old incompatible filters may be
|
32
|
+
// passed to methods of this type.
|
33
|
+
virtual const char* Name() const = 0;
|
34
|
+
|
35
|
+
// keys[0,n-1] contains a list of keys (potentially with duplicates)
|
36
|
+
// that are ordered according to the user supplied comparator.
|
37
|
+
// Append a filter that summarizes keys[0,n-1] to *dst.
|
38
|
+
//
|
39
|
+
// Warning: do not change the initial contents of *dst. Instead,
|
40
|
+
// append the newly constructed filter to *dst.
|
41
|
+
virtual void CreateFilter(const Slice* keys, int n, std::string* dst)
|
42
|
+
const = 0;
|
43
|
+
|
44
|
+
// "filter" contains the data appended by a preceding call to
|
45
|
+
// CreateFilter() on this class. This method must return true if
|
46
|
+
// the key was in the list of keys passed to CreateFilter().
|
47
|
+
// This method may return true or false if the key was not on the
|
48
|
+
// list, but it should aim to return false with a high probability.
|
49
|
+
virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0;
|
50
|
+
};
|
51
|
+
|
52
|
+
// Return a new filter policy that uses a bloom filter with approximately
|
53
|
+
// the specified number of bits per key. A good value for bits_per_key
|
54
|
+
// is 10, which yields a filter with ~ 1% false positive rate.
|
55
|
+
//
|
56
|
+
// Callers must delete the result after any database that is using the
|
57
|
+
// result has been closed.
|
58
|
+
//
|
59
|
+
// Note: if you are using a custom comparator that ignores some parts
|
60
|
+
// of the keys being compared, you must not use NewBloomFilterPolicy()
|
61
|
+
// and must provide your own FilterPolicy that also ignores the
|
62
|
+
// corresponding parts of the keys. For example, if the comparator
|
63
|
+
// ignores trailing spaces, it would be incorrect to use a
|
64
|
+
// FilterPolicy (like NewBloomFilterPolicy) that does not ignore
|
65
|
+
// trailing spaces in keys.
|
66
|
+
extern const FilterPolicy* NewBloomFilterPolicy(int bits_per_key);
|
67
|
+
|
68
|
+
}
|
69
|
+
|
70
|
+
#endif // STORAGE_LEVELDB_INCLUDE_FILTER_POLICY_H_
|
@@ -12,6 +12,7 @@ namespace leveldb {
|
|
12
12
|
class Cache;
|
13
13
|
class Comparator;
|
14
14
|
class Env;
|
15
|
+
class FilterPolicy;
|
15
16
|
class Logger;
|
16
17
|
class Snapshot;
|
17
18
|
|
@@ -127,6 +128,13 @@ struct Options {
|
|
127
128
|
// efficiently detect that and will switch to uncompressed mode.
|
128
129
|
CompressionType compression;
|
129
130
|
|
131
|
+
// If non-NULL, use the specified filter policy to reduce disk reads.
|
132
|
+
// Many applications will benefit from passing the result of
|
133
|
+
// NewBloomFilterPolicy() here.
|
134
|
+
//
|
135
|
+
// Default: NULL
|
136
|
+
const FilterPolicy* filter_policy;
|
137
|
+
|
130
138
|
// Create an Options object with default values for all fields.
|
131
139
|
Options();
|
132
140
|
};
|
@@ -54,6 +54,12 @@ class Status {
|
|
54
54
|
// Returns true iff the status indicates a NotFound error.
|
55
55
|
bool IsNotFound() const { return code() == kNotFound; }
|
56
56
|
|
57
|
+
// Returns true iff the status indicates a Corruption error.
|
58
|
+
bool IsCorruption() const { return code() == kCorruption; }
|
59
|
+
|
60
|
+
// Returns true iff the status indicates an IOError.
|
61
|
+
bool IsIOError() const { return code() == kIOError; }
|
62
|
+
|
57
63
|
// Return a string representation of this status suitable for printing.
|
58
64
|
// Returns the string "OK" for success.
|
59
65
|
std::string ToString() const;
|
@@ -12,9 +12,11 @@ namespace leveldb {
|
|
12
12
|
|
13
13
|
class Block;
|
14
14
|
class BlockHandle;
|
15
|
+
class Footer;
|
15
16
|
struct Options;
|
16
17
|
class RandomAccessFile;
|
17
18
|
struct ReadOptions;
|
19
|
+
class TableCache;
|
18
20
|
|
19
21
|
// A Table is a sorted map from strings to strings. Tables are
|
20
22
|
// immutable and persistent. A Table may be safely accessed from
|
@@ -60,6 +62,19 @@ class Table {
|
|
60
62
|
explicit Table(Rep* rep) { rep_ = rep; }
|
61
63
|
static Iterator* BlockReader(void*, const ReadOptions&, const Slice&);
|
62
64
|
|
65
|
+
// Calls (*handle_result)(arg, ...) with the entry found after a call
|
66
|
+
// to Seek(key). May not make such a call if filter policy says
|
67
|
+
// that key is not present.
|
68
|
+
friend class TableCache;
|
69
|
+
Status InternalGet(
|
70
|
+
const ReadOptions&, const Slice& key,
|
71
|
+
void* arg,
|
72
|
+
void (*handle_result)(void* arg, const Slice& k, const Slice& v));
|
73
|
+
|
74
|
+
|
75
|
+
void ReadMeta(const Footer& footer);
|
76
|
+
void ReadFilter(const Slice& filter_handle_value);
|
77
|
+
|
63
78
|
// No copying allowed
|
64
79
|
Table(const Table&);
|
65
80
|
void operator=(const Table&);
|
@@ -73,13 +73,21 @@ inline void MemoryBarrier() {
|
|
73
73
|
}
|
74
74
|
#define LEVELDB_HAVE_MEMORY_BARRIER
|
75
75
|
|
76
|
-
// ARM
|
77
|
-
#elif defined(ARCH_CPU_ARM_FAMILY)
|
76
|
+
// ARM Linux
|
77
|
+
#elif defined(ARCH_CPU_ARM_FAMILY) && defined(__linux__)
|
78
78
|
typedef void (*LinuxKernelMemoryBarrierFunc)(void);
|
79
|
-
|
80
|
-
|
79
|
+
// The Linux ARM kernel provides a highly optimized device-specific memory
|
80
|
+
// barrier function at a fixed memory address that is mapped in every
|
81
|
+
// user-level process.
|
82
|
+
//
|
83
|
+
// This beats using CPU-specific instructions which are, on single-core
|
84
|
+
// devices, un-necessary and very costly (e.g. ARMv7-A "dmb" takes more
|
85
|
+
// than 180ns on a Cortex-A8 like the one on a Nexus One). Benchmarking
|
86
|
+
// shows that the extra function call cost is completely negligible on
|
87
|
+
// multi-core devices.
|
88
|
+
//
|
81
89
|
inline void MemoryBarrier() {
|
82
|
-
|
90
|
+
(*(LinuxKernelMemoryBarrierFunc)0xffff0fa0)();
|
83
91
|
}
|
84
92
|
#define LEVELDB_HAVE_MEMORY_BARRIER
|
85
93
|
|
data/leveldb/port/port.h
CHANGED
data/leveldb/port/port_example.h
CHANGED
@@ -60,6 +60,16 @@ class CondVar {
|
|
60
60
|
void SignallAll();
|
61
61
|
};
|
62
62
|
|
63
|
+
// Thread-safe initialization.
|
64
|
+
// Used as follows:
|
65
|
+
// static port::OnceType init_control = LEVELDB_ONCE_INIT;
|
66
|
+
// static void Initializer() { ... do something ...; }
|
67
|
+
// ...
|
68
|
+
// port::InitOnce(&init_control, &Initializer);
|
69
|
+
typedef intptr_t OnceType;
|
70
|
+
#define LEVELDB_ONCE_INIT 0
|
71
|
+
extern void InitOnce(port::OnceType*, void (*initializer)());
|
72
|
+
|
63
73
|
// A type that holds a pointer that can be read or written atomically
|
64
74
|
// (i.e., without word-tearing.)
|
65
75
|
class AtomicPointer {
|
data/leveldb/port/port_posix.cc
CHANGED
@@ -46,5 +46,9 @@ void CondVar::SignalAll() {
|
|
46
46
|
PthreadCall("broadcast", pthread_cond_broadcast(&cv_));
|
47
47
|
}
|
48
48
|
|
49
|
+
void InitOnce(OnceType* once, void (*initializer)()) {
|
50
|
+
PthreadCall("once", pthread_once(once, initializer));
|
51
|
+
}
|
52
|
+
|
49
53
|
} // namespace port
|
50
54
|
} // namespace leveldb
|
data/leveldb/port/port_posix.h
CHANGED
@@ -7,17 +7,22 @@
|
|
7
7
|
#ifndef STORAGE_LEVELDB_PORT_PORT_POSIX_H_
|
8
8
|
#define STORAGE_LEVELDB_PORT_PORT_POSIX_H_
|
9
9
|
|
10
|
+
#undef PLATFORM_IS_LITTLE_ENDIAN
|
10
11
|
#if defined(OS_MACOSX)
|
11
12
|
#include <machine/endian.h>
|
13
|
+
#if defined(__DARWIN_LITTLE_ENDIAN) && defined(__DARWIN_BYTE_ORDER)
|
14
|
+
#define PLATFORM_IS_LITTLE_ENDIAN \
|
15
|
+
(__DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN)
|
16
|
+
#endif
|
12
17
|
#elif defined(OS_SOLARIS)
|
13
18
|
#include <sys/isa_defs.h>
|
14
19
|
#ifdef _LITTLE_ENDIAN
|
15
|
-
#define
|
20
|
+
#define PLATFORM_IS_LITTLE_ENDIAN true
|
16
21
|
#else
|
17
|
-
#define
|
22
|
+
#define PLATFORM_IS_LITTLE_ENDIAN false
|
18
23
|
#endif
|
19
24
|
#elif defined(OS_FREEBSD) || defined(OS_OPENBSD) || defined(OS_NETBSD) ||\
|
20
|
-
defined(OS_DRAGONFLYBSD)
|
25
|
+
defined(OS_DRAGONFLYBSD) || defined(OS_ANDROID)
|
21
26
|
#include <sys/types.h>
|
22
27
|
#include <sys/endian.h>
|
23
28
|
#else
|
@@ -31,14 +36,13 @@
|
|
31
36
|
#include <string>
|
32
37
|
#include "port/atomic_pointer.h"
|
33
38
|
|
34
|
-
#
|
35
|
-
#define
|
36
|
-
#else
|
37
|
-
#define IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
|
39
|
+
#ifndef PLATFORM_IS_LITTLE_ENDIAN
|
40
|
+
#define PLATFORM_IS_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
|
38
41
|
#endif
|
39
42
|
|
40
43
|
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
|
41
|
-
defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD)
|
44
|
+
defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
|
45
|
+
defined(OS_ANDROID)
|
42
46
|
// Use fread/fwrite/fflush on platforms without _unlocked variants
|
43
47
|
#define fread_unlocked fread
|
44
48
|
#define fwrite_unlocked fwrite
|
@@ -51,10 +55,17 @@
|
|
51
55
|
#define fdatasync fsync
|
52
56
|
#endif
|
53
57
|
|
58
|
+
#if defined(OS_ANDROID) && __ANDROID_API__ < 9
|
59
|
+
// fdatasync() was only introduced in API level 9 on Android. Use fsync()
|
60
|
+
// when targetting older platforms.
|
61
|
+
#define fdatasync fsync
|
62
|
+
#endif
|
63
|
+
|
54
64
|
namespace leveldb {
|
55
65
|
namespace port {
|
56
66
|
|
57
|
-
static const bool kLittleEndian =
|
67
|
+
static const bool kLittleEndian = PLATFORM_IS_LITTLE_ENDIAN;
|
68
|
+
#undef PLATFORM_IS_LITTLE_ENDIAN
|
58
69
|
|
59
70
|
class CondVar;
|
60
71
|
|
@@ -88,6 +99,10 @@ class CondVar {
|
|
88
99
|
Mutex* mu_;
|
89
100
|
};
|
90
101
|
|
102
|
+
typedef pthread_once_t OnceType;
|
103
|
+
#define LEVELDB_ONCE_INIT PTHREAD_ONCE_INIT
|
104
|
+
extern void InitOnce(OnceType* once, void (*initializer)());
|
105
|
+
|
91
106
|
inline bool Snappy_Compress(const char* input, size_t length,
|
92
107
|
::std::string* output) {
|
93
108
|
#ifdef SNAPPY
|
data/leveldb/table/block.cc
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
#include <vector>
|
10
10
|
#include <algorithm>
|
11
11
|
#include "leveldb/comparator.h"
|
12
|
+
#include "table/format.h"
|
12
13
|
#include "util/coding.h"
|
13
14
|
#include "util/logging.h"
|
14
15
|
|
@@ -19,9 +20,10 @@ inline uint32_t Block::NumRestarts() const {
|
|
19
20
|
return DecodeFixed32(data_ + size_ - sizeof(uint32_t));
|
20
21
|
}
|
21
22
|
|
22
|
-
Block::Block(const
|
23
|
-
: data_(data),
|
24
|
-
size_(size)
|
23
|
+
Block::Block(const BlockContents& contents)
|
24
|
+
: data_(contents.data.data()),
|
25
|
+
size_(contents.data.size()),
|
26
|
+
owned_(contents.heap_allocated) {
|
25
27
|
if (size_ < sizeof(uint32_t)) {
|
26
28
|
size_ = 0; // Error marker
|
27
29
|
} else {
|
@@ -35,7 +37,9 @@ Block::Block(const char* data, size_t size)
|
|
35
37
|
}
|
36
38
|
|
37
39
|
Block::~Block() {
|
38
|
-
|
40
|
+
if (owned_) {
|
41
|
+
delete[] data_;
|
42
|
+
}
|
39
43
|
}
|
40
44
|
|
41
45
|
// Helper routine: decode the next block entry starting at "p",
|
data/leveldb/table/block.h
CHANGED
@@ -11,13 +11,13 @@
|
|
11
11
|
|
12
12
|
namespace leveldb {
|
13
13
|
|
14
|
+
struct BlockContents;
|
14
15
|
class Comparator;
|
15
16
|
|
16
17
|
class Block {
|
17
18
|
public:
|
18
19
|
// Initialize the block with the specified contents.
|
19
|
-
|
20
|
-
Block(const char* data, size_t size);
|
20
|
+
explicit Block(const BlockContents& contents);
|
21
21
|
|
22
22
|
~Block();
|
23
23
|
|
@@ -30,6 +30,7 @@ class Block {
|
|
30
30
|
const char* data_;
|
31
31
|
size_t size_;
|
32
32
|
uint32_t restart_offset_; // Offset in data_ of restart array
|
33
|
+
bool owned_; // Block owns data_[]
|
33
34
|
|
34
35
|
// No copying allowed
|
35
36
|
Block(const Block&);
|
@@ -0,0 +1,111 @@
|
|
1
|
+
// Copyright (c) 2012 The LevelDB Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
4
|
+
|
5
|
+
#include "table/filter_block.h"
|
6
|
+
|
7
|
+
#include "leveldb/filter_policy.h"
|
8
|
+
#include "util/coding.h"
|
9
|
+
|
10
|
+
namespace leveldb {
|
11
|
+
|
12
|
+
// See doc/table_format.txt for an explanation of the filter block format.
|
13
|
+
|
14
|
+
// Generate new filter every 2KB of data
|
15
|
+
static const size_t kFilterBaseLg = 11;
|
16
|
+
static const size_t kFilterBase = 1 << kFilterBaseLg;
|
17
|
+
|
18
|
+
FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy)
|
19
|
+
: policy_(policy) {
|
20
|
+
}
|
21
|
+
|
22
|
+
void FilterBlockBuilder::StartBlock(uint64_t block_offset) {
|
23
|
+
uint64_t filter_index = (block_offset / kFilterBase);
|
24
|
+
assert(filter_index >= filter_offsets_.size());
|
25
|
+
while (filter_index > filter_offsets_.size()) {
|
26
|
+
GenerateFilter();
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
void FilterBlockBuilder::AddKey(const Slice& key) {
|
31
|
+
Slice k = key;
|
32
|
+
start_.push_back(keys_.size());
|
33
|
+
keys_.append(k.data(), k.size());
|
34
|
+
}
|
35
|
+
|
36
|
+
Slice FilterBlockBuilder::Finish() {
|
37
|
+
if (!start_.empty()) {
|
38
|
+
GenerateFilter();
|
39
|
+
}
|
40
|
+
|
41
|
+
// Append array of per-filter offsets
|
42
|
+
const uint32_t array_offset = result_.size();
|
43
|
+
for (size_t i = 0; i < filter_offsets_.size(); i++) {
|
44
|
+
PutFixed32(&result_, filter_offsets_[i]);
|
45
|
+
}
|
46
|
+
|
47
|
+
PutFixed32(&result_, array_offset);
|
48
|
+
result_.push_back(kFilterBaseLg); // Save encoding parameter in result
|
49
|
+
return Slice(result_);
|
50
|
+
}
|
51
|
+
|
52
|
+
void FilterBlockBuilder::GenerateFilter() {
|
53
|
+
const size_t num_keys = start_.size();
|
54
|
+
if (num_keys == 0) {
|
55
|
+
// Fast path if there are no keys for this filter
|
56
|
+
filter_offsets_.push_back(result_.size());
|
57
|
+
return;
|
58
|
+
}
|
59
|
+
|
60
|
+
// Make list of keys from flattened key structure
|
61
|
+
start_.push_back(keys_.size()); // Simplify length computation
|
62
|
+
tmp_keys_.resize(num_keys);
|
63
|
+
for (size_t i = 0; i < num_keys; i++) {
|
64
|
+
const char* base = keys_.data() + start_[i];
|
65
|
+
size_t length = start_[i+1] - start_[i];
|
66
|
+
tmp_keys_[i] = Slice(base, length);
|
67
|
+
}
|
68
|
+
|
69
|
+
// Generate filter for current set of keys and append to result_.
|
70
|
+
filter_offsets_.push_back(result_.size());
|
71
|
+
policy_->CreateFilter(&tmp_keys_[0], num_keys, &result_);
|
72
|
+
|
73
|
+
tmp_keys_.clear();
|
74
|
+
keys_.clear();
|
75
|
+
start_.clear();
|
76
|
+
}
|
77
|
+
|
78
|
+
FilterBlockReader::FilterBlockReader(const FilterPolicy* policy,
|
79
|
+
const Slice& contents)
|
80
|
+
: policy_(policy),
|
81
|
+
data_(NULL),
|
82
|
+
offset_(NULL),
|
83
|
+
num_(0),
|
84
|
+
base_lg_(0) {
|
85
|
+
size_t n = contents.size();
|
86
|
+
if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array
|
87
|
+
base_lg_ = contents[n-1];
|
88
|
+
uint32_t last_word = DecodeFixed32(contents.data() + n - 5);
|
89
|
+
if (last_word > n - 5) return;
|
90
|
+
data_ = contents.data();
|
91
|
+
offset_ = data_ + last_word;
|
92
|
+
num_ = (n - 5 - last_word) / 4;
|
93
|
+
}
|
94
|
+
|
95
|
+
bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) {
|
96
|
+
uint64_t index = block_offset >> base_lg_;
|
97
|
+
if (index < num_) {
|
98
|
+
uint32_t start = DecodeFixed32(offset_ + index*4);
|
99
|
+
uint32_t limit = DecodeFixed32(offset_ + index*4 + 4);
|
100
|
+
if (start <= limit && limit <= (offset_ - data_)) {
|
101
|
+
Slice filter = Slice(data_ + start, limit - start);
|
102
|
+
return policy_->KeyMayMatch(key, filter);
|
103
|
+
} else if (start == limit) {
|
104
|
+
// Empty filters do not match any keys
|
105
|
+
return false;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
return true; // Errors are treated as potential matches
|
109
|
+
}
|
110
|
+
|
111
|
+
}
|