Skip to content

Commit

Permalink
expose a hook to skip tables during iteration
Browse files Browse the repository at this point in the history
Add a `table_filter` to `ReadOptions` that allows specifying a callback
to be executed during iteration before each table in the database is
scanned. The callback is passed the table's properties; if the callback
returns false, the table is not scanned.

This can be used in conjunction with a `TablePropertiesCollector` to
dramatically speed up scans by skipping tables that are known to contain
irrelevant data for the scan at hand.
  • Loading branch information
benesch committed Jul 5, 2017
1 parent 8d0b0c6 commit fcfb2de
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
64 changes: 64 additions & 0 deletions db/db_iterator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1911,6 +1911,70 @@ TEST_F(DBIteratorTest, DBIteratorSkipRecentDuplicatesTest) {
NUMBER_OF_RESEEKS_IN_ITERATION));
}

TEST_F(DBIteratorTest, TableFilter) {
ASSERT_OK(Put("a", "1"));
dbfull()->Flush(FlushOptions());
ASSERT_OK(Put("b", "2"));
ASSERT_OK(Put("c", "3"));
dbfull()->Flush(FlushOptions());
ASSERT_OK(Put("d", "4"));
ASSERT_OK(Put("e", "5"));
ASSERT_OK(Put("f", "6"));
dbfull()->Flush(FlushOptions());

// Ensure the table_filter callback is called once for each table.
{
ReadOptions opts;
opts.table_filter = [](const TableProperties& props) {
static std::set<uint64_t> unseen {1, 2, 3};
auto it = unseen.find(props.num_entries);
if (it == unseen.end()) {
ADD_FAILURE() << "saw table properties with an unexpected " << props.num_entries << " entries";
} else {
unseen.erase(it);
}
return true;
};
auto iter = db_->NewIterator(opts);
iter->SeekToFirst();
ASSERT_EQ(IterStatus(iter), "a->1");
iter->Next();
ASSERT_EQ(IterStatus(iter), "b->2");
iter->Next();
ASSERT_EQ(IterStatus(iter), "c->3");
iter->Next();
ASSERT_EQ(IterStatus(iter), "d->4");
iter->Next();
ASSERT_EQ(IterStatus(iter), "e->5");
iter->Next();
ASSERT_EQ(IterStatus(iter), "f->6");
iter->Next();
ASSERT_FALSE(iter->Valid());
delete iter;
}

// Ensure returning true in the table_filter hides the keys from that table
// during iteration.
{
ReadOptions opts;
opts.table_filter = [](const TableProperties& props) {
return props.num_entries != 2;
};
auto iter = db_->NewIterator(opts);
iter->SeekToFirst();
ASSERT_EQ(IterStatus(iter), "a->1");
iter->Next();
ASSERT_EQ(IterStatus(iter), "d->4");
iter->Next();
ASSERT_EQ(IterStatus(iter), "e->5");
iter->Next();
ASSERT_EQ(IterStatus(iter), "f->6");
iter->Next();
ASSERT_FALSE(iter->Valid());
delete iter;
}
}

} // namespace rocksdb

int main(int argc, char** argv) {
Expand Down
9 changes: 7 additions & 2 deletions db/table_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,13 @@ InternalIterator* TableCache::NewIterator(
}
InternalIterator* result = nullptr;
if (s.ok()) {
result =
table_reader->NewIterator(options, arena, &icomparator, skip_filters);
if (options.table_filter &&
!options.table_filter(*table_reader->GetTableProperties())) {
result = NewEmptyInternalIterator(arena);
} else {
result =
table_reader->NewIterator(options, arena, &icomparator, skip_filters);
}
if (create_new_table_reader) {
assert(handle == nullptr);
result->RegisterCleanup(&DeleteTableReader, table_reader, nullptr);
Expand Down
7 changes: 7 additions & 0 deletions include/rocksdb/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,13 @@ struct ReadOptions {
// Default: 0
uint64_t max_skippable_internal_keys;

// A callback to determine whether relevant keys for this scan exist in a
// given table based on the table's properties. The callback is passed the
// properties of each table during iteration. If the callback returns false,
// the table will not be scanned.
// Default: empty (every table will be scanned)
std::function<bool(const TableProperties&)> table_filter;

ReadOptions();
ReadOptions(bool cksum, bool cache);
};
Expand Down

0 comments on commit fcfb2de

Please sign in to comment.