提交 6c7b1a0c 编写于 作者: A anand76 提交者: Facebook Github Bot

Batched MultiGet API for multiple column families (#5816)

Summary:
Add a new API that allows a user to call MultiGet specifying multiple keys belonging to different column families. This is mainly useful for users who want to do a consistent read of keys across column families, with the added performance benefits of batching and returning values using PinnableSlice.

As part of this change, the code in the original multi-column family MultiGet for acquiring the super versions has been refactored into a separate function that can be used by both, the batching and the non-batching versions of MultiGet.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/5816

Test Plan:
make check
make asan_check
asan_crash_test

Differential Revision: D18408676

Pulled By: anand1976

fbshipit-source-id: 933e7bec91dd70e7b633be4ff623a1116cc28c8d
上级 a19de78d
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
### New Features ### New Features
* Universal compaction to support options.periodic_compaction_seconds. A full compaction will be triggered if any file is over the threshold. * Universal compaction to support options.periodic_compaction_seconds. A full compaction will be triggered if any file is over the threshold.
* `GetLiveFilesMetaData` and `GetColumnFamilyMetaData` now expose the file number of SST files as well as the oldest blob file referenced by each SST. * `GetLiveFilesMetaData` and `GetColumnFamilyMetaData` now expose the file number of SST files as well as the oldest blob file referenced by each SST.
* A batched MultiGet API (DB::MultiGet()) that supports retrieving keys from multiple column families.
### Performance Improvements ### Performance Improvements
* For 64-bit hashing, RocksDB is standardizing on a slightly modified preview version of XXH3. This function is now used for many non-persisted hashes, along with fastrange64() in place of the modulus operator, and some benchmarks show a slight improvement. * For 64-bit hashing, RocksDB is standardizing on a slightly modified preview version of XXH3. This function is now used for many non-persisted hashes, along with fastrange64() in place of the modulus operator, and some benchmarks show a slight improvement.
......
...@@ -1019,15 +1019,27 @@ TEST_F(DBBasicTest, DBCloseFlushError) { ...@@ -1019,15 +1019,27 @@ TEST_F(DBBasicTest, DBCloseFlushError) {
Destroy(options); Destroy(options);
} }
TEST_F(DBBasicTest, MultiGetMultiCF) { class DBMultiGetTestWithParam : public DBBasicTest,
public testing::WithParamInterface<bool> {};
TEST_P(DBMultiGetTestWithParam, MultiGetMultiCF) {
Options options = CurrentOptions(); Options options = CurrentOptions();
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich", CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
"alyosha", "popovich"}, "alyosha", "popovich"},
options); options);
// <CF, key, value> tuples
for (int i = 0; i < 8; ++i) { std::vector<std::tuple<int, std::string, std::string>> cf_kv_vec;
ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key", static const int num_keys = 24;
"cf" + std::to_string(i) + "_val")); cf_kv_vec.reserve(num_keys);
for (int i = 0; i < num_keys; ++i) {
int cf = i / 3;
int cf_key = 1 % 3;
cf_kv_vec.emplace_back(std::make_tuple(
cf, "cf" + std::to_string(cf) + "_key_" + std::to_string(cf_key),
"cf" + std::to_string(cf) + "_val_" + std::to_string(cf_key)));
ASSERT_OK(Put(std::get<0>(cf_kv_vec[i]), std::get<1>(cf_kv_vec[i]),
std::get<2>(cf_kv_vec[i])));
} }
int get_sv_count = 0; int get_sv_count = 0;
...@@ -1037,10 +1049,14 @@ TEST_F(DBBasicTest, MultiGetMultiCF) { ...@@ -1037,10 +1049,14 @@ TEST_F(DBBasicTest, MultiGetMultiCF) {
if (++get_sv_count == 2) { if (++get_sv_count == 2) {
// After MultiGet refs a couple of CFs, flush all CFs so MultiGet // After MultiGet refs a couple of CFs, flush all CFs so MultiGet
// is forced to repeat the process // is forced to repeat the process
for (int i = 0; i < 8; ++i) { for (int i = 0; i < num_keys; ++i) {
ASSERT_OK(Flush(i)); int cf = i / 3;
ASSERT_OK(Put(i, "cf" + std::to_string(i) + "_key", int cf_key = i % 8;
"cf" + std::to_string(i) + "_val2")); if (cf_key == 0) {
ASSERT_OK(Flush(cf));
}
ASSERT_OK(Put(std::get<0>(cf_kv_vec[i]), std::get<1>(cf_kv_vec[i]),
std::get<2>(cf_kv_vec[i]) + "_2"));
} }
} }
if (get_sv_count == 11) { if (get_sv_count == 11) {
...@@ -1058,26 +1074,53 @@ TEST_F(DBBasicTest, MultiGetMultiCF) { ...@@ -1058,26 +1074,53 @@ TEST_F(DBBasicTest, MultiGetMultiCF) {
std::vector<std::string> keys; std::vector<std::string> keys;
std::vector<std::string> values; std::vector<std::string> values;
for (int i = 0; i < 8; ++i) { for (int i = 0; i < num_keys; ++i) {
cfs.push_back(i); cfs.push_back(std::get<0>(cf_kv_vec[i]));
keys.push_back("cf" + std::to_string(i) + "_key"); keys.push_back(std::get<1>(cf_kv_vec[i]));
} }
values = MultiGet(cfs, keys, nullptr); values = MultiGet(cfs, keys, nullptr, GetParam());
ASSERT_EQ(values.size(), 8); ASSERT_EQ(values.size(), num_keys);
for (unsigned int j = 0; j < values.size(); ++j) { for (unsigned int j = 0; j < values.size(); ++j) {
ASSERT_EQ(values[j], "cf" + std::to_string(j) + "_val2"); ASSERT_EQ(values[j], std::get<2>(cf_kv_vec[j]) + "_2");
} }
for (int i = 0; i < 8; ++i) {
keys.clear();
cfs.clear();
cfs.push_back(std::get<0>(cf_kv_vec[0]));
keys.push_back(std::get<1>(cf_kv_vec[0]));
cfs.push_back(std::get<0>(cf_kv_vec[3]));
keys.push_back(std::get<1>(cf_kv_vec[3]));
cfs.push_back(std::get<0>(cf_kv_vec[4]));
keys.push_back(std::get<1>(cf_kv_vec[4]));
values = MultiGet(cfs, keys, nullptr, GetParam());
ASSERT_EQ(values[0], std::get<2>(cf_kv_vec[0]) + "_2");
ASSERT_EQ(values[1], std::get<2>(cf_kv_vec[3]) + "_2");
ASSERT_EQ(values[2], std::get<2>(cf_kv_vec[4]) + "_2");
keys.clear();
cfs.clear();
cfs.push_back(std::get<0>(cf_kv_vec[7]));
keys.push_back(std::get<1>(cf_kv_vec[7]));
cfs.push_back(std::get<0>(cf_kv_vec[6]));
keys.push_back(std::get<1>(cf_kv_vec[6]));
cfs.push_back(std::get<0>(cf_kv_vec[1]));
keys.push_back(std::get<1>(cf_kv_vec[1]));
values = MultiGet(cfs, keys, nullptr, GetParam());
ASSERT_EQ(values[0], std::get<2>(cf_kv_vec[7]) + "_2");
ASSERT_EQ(values[1], std::get<2>(cf_kv_vec[6]) + "_2");
ASSERT_EQ(values[2], std::get<2>(cf_kv_vec[1]) + "_2");
for (int cf = 0; cf < 8; ++cf) {
auto* cfd = reinterpret_cast<ColumnFamilyHandleImpl*>( auto* cfd = reinterpret_cast<ColumnFamilyHandleImpl*>(
reinterpret_cast<DBImpl*>(db_)->GetColumnFamilyHandle(i)) reinterpret_cast<DBImpl*>(db_)->GetColumnFamilyHandle(cf))
->cfd(); ->cfd();
ASSERT_NE(cfd->TEST_GetLocalSV()->Get(), SuperVersion::kSVInUse); ASSERT_NE(cfd->TEST_GetLocalSV()->Get(), SuperVersion::kSVInUse);
ASSERT_NE(cfd->TEST_GetLocalSV()->Get(), SuperVersion::kSVObsolete); ASSERT_NE(cfd->TEST_GetLocalSV()->Get(), SuperVersion::kSVObsolete);
} }
} }
TEST_F(DBBasicTest, MultiGetMultiCFMutex) { TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFMutex) {
Options options = CurrentOptions(); Options options = CurrentOptions();
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich", CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
"alyosha", "popovich"}, "alyosha", "popovich"},
...@@ -1123,7 +1166,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) { ...@@ -1123,7 +1166,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) {
keys.push_back("cf" + std::to_string(i) + "_key"); keys.push_back("cf" + std::to_string(i) + "_key");
} }
values = MultiGet(cfs, keys, nullptr); values = MultiGet(cfs, keys, nullptr, GetParam());
ASSERT_TRUE(last_try); ASSERT_TRUE(last_try);
ASSERT_EQ(values.size(), 8); ASSERT_EQ(values.size(), 8);
for (unsigned int j = 0; j < values.size(); ++j) { for (unsigned int j = 0; j < values.size(); ++j) {
...@@ -1138,7 +1181,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) { ...@@ -1138,7 +1181,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFMutex) {
} }
} }
TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) { TEST_P(DBMultiGetTestWithParam, MultiGetMultiCFSnapshot) {
Options options = CurrentOptions(); Options options = CurrentOptions();
CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich", CreateAndReopenWithCF({"pikachu", "ilya", "muromec", "dobrynia", "nikitich",
"alyosha", "popovich"}, "alyosha", "popovich"},
...@@ -1183,7 +1226,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) { ...@@ -1183,7 +1226,7 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) {
} }
const Snapshot* snapshot = db_->GetSnapshot(); const Snapshot* snapshot = db_->GetSnapshot();
values = MultiGet(cfs, keys, snapshot); values = MultiGet(cfs, keys, snapshot, GetParam());
db_->ReleaseSnapshot(snapshot); db_->ReleaseSnapshot(snapshot);
ASSERT_EQ(values.size(), 8); ASSERT_EQ(values.size(), 8);
for (unsigned int j = 0; j < values.size(); ++j) { for (unsigned int j = 0; j < values.size(); ++j) {
...@@ -1197,6 +1240,9 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) { ...@@ -1197,6 +1240,9 @@ TEST_F(DBBasicTest, MultiGetMultiCFSnapshot) {
} }
} }
INSTANTIATE_TEST_CASE_P(DBMultiGetTestWithParam, DBMultiGetTestWithParam,
testing::Bool());
TEST_F(DBBasicTest, MultiGetBatchedSimpleUnsorted) { TEST_F(DBBasicTest, MultiGetBatchedSimpleUnsorted) {
do { do {
CreateAndReopenWithCF({"pikachu"}, CurrentOptions()); CreateAndReopenWithCF({"pikachu"}, CurrentOptions());
......
此差异已折叠。
...@@ -199,11 +199,15 @@ class DBImpl : public DB { ...@@ -199,11 +199,15 @@ class DBImpl : public DB {
PinnableSlice* values, Status* statuses, PinnableSlice* values, Status* statuses,
const bool sorted_input = false) override; const bool sorted_input = false) override;
void MultiGetImpl( virtual void MultiGet(const ReadOptions& options, const size_t num_keys,
ColumnFamilyHandle** column_families, const Slice* keys,
PinnableSlice* values, Status* statuses,
const bool sorted_input = false) override;
virtual void MultiGetWithCallback(
const ReadOptions& options, ColumnFamilyHandle* column_family, const ReadOptions& options, ColumnFamilyHandle* column_family,
autovector<KeyContext, MultiGetContext::MAX_BATCH_SIZE>& key_context, ReadCallback* callback,
bool sorted_input, ReadCallback* callback = nullptr, autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE>* sorted_keys);
bool* is_blob_index = nullptr);
virtual Status CreateColumnFamily(const ColumnFamilyOptions& cf_options, virtual Status CreateColumnFamily(const ColumnFamilyOptions& cf_options,
const std::string& column_family, const std::string& column_family,
...@@ -1640,6 +1644,81 @@ class DBImpl : public DB { ...@@ -1640,6 +1644,81 @@ class DBImpl : public DB {
const DBOptions& db_options, const DBOptions& db_options,
const std::vector<ColumnFamilyDescriptor>& column_families); const std::vector<ColumnFamilyDescriptor>& column_families);
// Utility function to do some debug validation and sort the given vector
// of MultiGet keys
void PrepareMultiGetKeys(
const size_t num_keys, bool sorted,
autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE>* key_ptrs);
// A structure to hold the information required to process MultiGet of keys
// belonging to one column family. For a multi column family MultiGet, there
// will be a container of these objects.
struct MultiGetColumnFamilyData {
ColumnFamilyHandle* cf;
ColumnFamilyData* cfd;
// For the batched MultiGet which relies on sorted keys, start specifies
// the index of first key belonging to this column family in the sorted
// list.
size_t start;
// For the batched MultiGet case, num_keys specifies the number of keys
// belonging to this column family in the sorted list
size_t num_keys;
// SuperVersion for the column family obtained in a manner that ensures a
// consistent view across all column families in the DB
SuperVersion* super_version;
MultiGetColumnFamilyData(ColumnFamilyHandle* column_family,
SuperVersion* sv)
: cf(column_family),
cfd(static_cast<ColumnFamilyHandleImpl*>(cf)->cfd()),
start(0),
num_keys(0),
super_version(sv) {}
MultiGetColumnFamilyData(ColumnFamilyHandle* column_family, size_t first,
size_t count, SuperVersion* sv)
: cf(column_family),
cfd(static_cast<ColumnFamilyHandleImpl*>(cf)->cfd()),
start(first),
num_keys(count),
super_version(sv) {}
MultiGetColumnFamilyData() = default;
};
// A common function to obtain a consistent snapshot, which can be implicit
// if the user doesn't specify a snapshot in read_options, across
// multiple column families for MultiGet. It will attempt to get an implicit
// snapshot without acquiring the db_mutes, but will give up after a few
// tries and acquire the mutex if a memtable flush happens. The template
// allows both the batched and non-batched MultiGet to call this with
// either an std::unordered_map or autovector of column families.
//
// If callback is non-null, the callback is refreshed with the snapshot
// sequence number
//
// A return value of true indicates that the SuperVersions were obtained
// from the ColumnFamilyData, whereas false indicates they are thread
// local
template <class T>
bool MultiCFSnapshot(
const ReadOptions& read_options, ReadCallback* callback,
std::function<MultiGetColumnFamilyData*(typename T::iterator&)>&
iter_deref_func,
T* cf_list, SequenceNumber* snapshot);
// The actual implementation of the batching MultiGet. The caller is expected
// to have acquired the SuperVersion and pass in a snapshot sequence number
// in order to construct the LookupKeys. The start_key and num_keys specify
// the range of keys in the sorted_keys vector for a single column family.
void MultiGetImpl(
const ReadOptions& read_options, size_t start_key, size_t num_keys,
autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE>* sorted_keys,
SuperVersion* sv, SequenceNumber snap_seqnum, ReadCallback* callback,
bool* is_blob_index);
// table_cache_ provides its own synchronization // table_cache_ provides its own synchronization
std::shared_ptr<Cache> table_cache_; std::shared_ptr<Cache> table_cache_;
......
...@@ -777,7 +777,8 @@ std::string DBTestBase::Get(int cf, const std::string& k, ...@@ -777,7 +777,8 @@ std::string DBTestBase::Get(int cf, const std::string& k,
std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs, std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs,
const std::vector<std::string>& k, const std::vector<std::string>& k,
const Snapshot* snapshot) { const Snapshot* snapshot,
const bool batched) {
ReadOptions options; ReadOptions options;
options.verify_checksums = true; options.verify_checksums = true;
options.snapshot = snapshot; options.snapshot = snapshot;
...@@ -789,12 +790,30 @@ std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs, ...@@ -789,12 +790,30 @@ std::vector<std::string> DBTestBase::MultiGet(std::vector<int> cfs,
handles.push_back(handles_[cfs[i]]); handles.push_back(handles_[cfs[i]]);
keys.push_back(k[i]); keys.push_back(k[i]);
} }
std::vector<Status> s = db_->MultiGet(options, handles, keys, &result); std::vector<Status> s;
for (unsigned int i = 0; i < s.size(); ++i) { if (!batched) {
if (s[i].IsNotFound()) { s = db_->MultiGet(options, handles, keys, &result);
result[i] = "NOT_FOUND"; for (unsigned int i = 0; i < s.size(); ++i) {
} else if (!s[i].ok()) { if (s[i].IsNotFound()) {
result[i] = s[i].ToString(); result[i] = "NOT_FOUND";
} else if (!s[i].ok()) {
result[i] = s[i].ToString();
}
}
} else {
std::vector<PinnableSlice> pin_values(cfs.size());
result.resize(cfs.size());
s.resize(cfs.size());
db_->MultiGet(options, cfs.size(), handles.data(), keys.data(),
pin_values.data(), s.data());
for (unsigned int i = 0; i < s.size(); ++i) {
if (s[i].IsNotFound()) {
result[i] = "NOT_FOUND";
} else if (!s[i].ok()) {
result[i] = s[i].ToString();
} else {
result[i].assign(pin_values[i].data(), pin_values[i].size());
}
} }
} }
return result; return result;
......
...@@ -850,7 +850,8 @@ class DBTestBase : public testing::Test { ...@@ -850,7 +850,8 @@ class DBTestBase : public testing::Test {
std::vector<std::string> MultiGet(std::vector<int> cfs, std::vector<std::string> MultiGet(std::vector<int> cfs,
const std::vector<std::string>& k, const std::vector<std::string>& k,
const Snapshot* snapshot = nullptr); const Snapshot* snapshot,
const bool batched);
std::vector<std::string> MultiGet(const std::vector<std::string>& k, std::vector<std::string> MultiGet(const std::vector<std::string>& k,
const Snapshot* snapshot = nullptr); const Snapshot* snapshot = nullptr);
......
...@@ -490,6 +490,47 @@ class DB { ...@@ -490,6 +490,47 @@ class DB {
values++; values++;
} }
} }
// Overloaded MultiGet API that improves performance by batching operations
// in the read path for greater efficiency. Currently, only the block based
// table format with full filters are supported. Other table formats such
// as plain table, block based table with block based filters and
// partitioned indexes will still work, but will not get any performance
// benefits.
// Parameters -
// options - ReadOptions
// column_family - ColumnFamilyHandle* that the keys belong to. All the keys
// passed to the API are restricted to a single column family
// num_keys - Number of keys to lookup
// keys - Pointer to C style array of key Slices with num_keys elements
// values - Pointer to C style array of PinnableSlices with num_keys elements
// statuses - Pointer to C style array of Status with num_keys elements
// sorted_input - If true, it means the input keys are already sorted by key
// order, so the MultiGet() API doesn't have to sort them
// again. If false, the keys will be copied and sorted
// internally by the API - the input array will not be
// modified
virtual void MultiGet(const ReadOptions& options, const size_t num_keys,
ColumnFamilyHandle** column_families, const Slice* keys,
PinnableSlice* values, Status* statuses,
const bool /*sorted_input*/ = false) {
std::vector<ColumnFamilyHandle*> cf;
std::vector<Slice> user_keys;
std::vector<Status> status;
std::vector<std::string> vals;
for (size_t i = 0; i < num_keys; ++i) {
cf.emplace_back(column_families[i]);
user_keys.emplace_back(keys[i]);
}
status = MultiGet(options, cf, user_keys, &vals);
std::copy(status.begin(), status.end(), statuses);
for (auto& value : vals) {
values->PinSelf(value);
values++;
}
}
// If the key definitely does not exist in the database, then this method // If the key definitely does not exist in the database, then this method
// returns false, else true. If the caller wants to obtain value when the key // returns false, else true. If the caller wants to obtain value when the key
// is found in memory, a bool for 'value_found' must be passed. 'value_found' // is found in memory, a bool for 'value_found' must be passed. 'value_found'
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <array>
#include <string> #include <string>
#include "db/lookup_key.h" #include "db/lookup_key.h"
#include "db/merge_context.h" #include "db/merge_context.h"
...@@ -21,6 +22,7 @@ struct KeyContext { ...@@ -21,6 +22,7 @@ struct KeyContext {
LookupKey* lkey; LookupKey* lkey;
Slice ukey; Slice ukey;
Slice ikey; Slice ikey;
ColumnFamilyHandle* column_family;
Status* s; Status* s;
MergeContext merge_context; MergeContext merge_context;
SequenceNumber max_covering_tombstone_seq; SequenceNumber max_covering_tombstone_seq;
...@@ -29,9 +31,11 @@ struct KeyContext { ...@@ -29,9 +31,11 @@ struct KeyContext {
PinnableSlice* value; PinnableSlice* value;
GetContext* get_context; GetContext* get_context;
KeyContext(const Slice& user_key, PinnableSlice* val, Status* stat) KeyContext(ColumnFamilyHandle* col_family, const Slice& user_key,
PinnableSlice* val, Status* stat)
: key(&user_key), : key(&user_key),
lkey(nullptr), lkey(nullptr),
column_family(col_family),
s(stat), s(stat),
max_covering_tombstone_seq(0), max_covering_tombstone_seq(0),
key_exists(false), key_exists(false),
...@@ -85,10 +89,9 @@ class MultiGetContext { ...@@ -85,10 +89,9 @@ class MultiGetContext {
// htat need to be performed // htat need to be performed
static const int MAX_BATCH_SIZE = 32; static const int MAX_BATCH_SIZE = 32;
MultiGetContext(KeyContext** sorted_keys, size_t num_keys, MultiGetContext(autovector<KeyContext*, MAX_BATCH_SIZE>* sorted_keys,
SequenceNumber snapshot) size_t begin, size_t num_keys, SequenceNumber snapshot)
: sorted_keys_(sorted_keys), : num_keys_(num_keys),
num_keys_(num_keys),
value_mask_(0), value_mask_(0),
lookup_key_ptr_(reinterpret_cast<LookupKey*>(lookup_key_stack_buf)) { lookup_key_ptr_(reinterpret_cast<LookupKey*>(lookup_key_stack_buf)) {
int index = 0; int index = 0;
...@@ -100,6 +103,8 @@ class MultiGetContext { ...@@ -100,6 +103,8 @@ class MultiGetContext {
} }
for (size_t iter = 0; iter != num_keys_; ++iter) { for (size_t iter = 0; iter != num_keys_; ++iter) {
// autovector may not be contiguous storage, so make a copy
sorted_keys_[iter] = (*sorted_keys)[begin + iter];
sorted_keys_[iter]->lkey = new (&lookup_key_ptr_[index]) sorted_keys_[iter]->lkey = new (&lookup_key_ptr_[index])
LookupKey(*sorted_keys_[iter]->key, snapshot); LookupKey(*sorted_keys_[iter]->key, snapshot);
sorted_keys_[iter]->ukey = sorted_keys_[iter]->lkey->user_key(); sorted_keys_[iter]->ukey = sorted_keys_[iter]->lkey->user_key();
...@@ -118,7 +123,7 @@ class MultiGetContext { ...@@ -118,7 +123,7 @@ class MultiGetContext {
static const int MAX_LOOKUP_KEYS_ON_STACK = 16; static const int MAX_LOOKUP_KEYS_ON_STACK = 16;
alignas(alignof(LookupKey)) alignas(alignof(LookupKey))
char lookup_key_stack_buf[sizeof(LookupKey) * MAX_LOOKUP_KEYS_ON_STACK]; char lookup_key_stack_buf[sizeof(LookupKey) * MAX_LOOKUP_KEYS_ON_STACK];
KeyContext** sorted_keys_; std::array<KeyContext*, MAX_BATCH_SIZE> sorted_keys_;
size_t num_keys_; size_t num_keys_;
uint64_t value_mask_; uint64_t value_mask_;
std::unique_ptr<char[]> lookup_key_heap_buf; std::unique_ptr<char[]> lookup_key_heap_buf;
......
...@@ -963,6 +963,7 @@ void WriteBatchWithIndex::MultiGetFromBatchAndDB( ...@@ -963,6 +963,7 @@ void WriteBatchWithIndex::MultiGetFromBatchAndDB(
->immutable_db_options(); ->immutable_db_options();
autovector<KeyContext, MultiGetContext::MAX_BATCH_SIZE> key_context; autovector<KeyContext, MultiGetContext::MAX_BATCH_SIZE> key_context;
autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE> sorted_keys;
// To hold merges from the write batch // To hold merges from the write batch
autovector<std::pair<WriteBatchWithIndexInternal::Result, MergeContext>, autovector<std::pair<WriteBatchWithIndexInternal::Result, MergeContext>,
MultiGetContext::MAX_BATCH_SIZE> MultiGetContext::MAX_BATCH_SIZE>
...@@ -1002,14 +1003,17 @@ void WriteBatchWithIndex::MultiGetFromBatchAndDB( ...@@ -1002,14 +1003,17 @@ void WriteBatchWithIndex::MultiGetFromBatchAndDB(
assert(result == WriteBatchWithIndexInternal::Result::kMergeInProgress || assert(result == WriteBatchWithIndexInternal::Result::kMergeInProgress ||
result == WriteBatchWithIndexInternal::Result::kNotFound); result == WriteBatchWithIndexInternal::Result::kNotFound);
key_context.emplace_back(keys[i], &values[i], &statuses[i]); key_context.emplace_back(column_family, keys[i], &values[i], &statuses[i]);
sorted_keys.emplace_back(&key_context.back());
merges.emplace_back(result, std::move(merge_context)); merges.emplace_back(result, std::move(merge_context));
} }
// Did not find key in batch OR could not resolve Merges. Try DB. // Did not find key in batch OR could not resolve Merges. Try DB.
static_cast_with_check<DBImpl, DB>(db->GetRootDB()) static_cast_with_check<DBImpl, DB>(db->GetRootDB())
->MultiGetImpl(read_options, column_family, key_context, sorted_input, ->PrepareMultiGetKeys(key_context.size(), sorted_input, &sorted_keys);
callback); static_cast_with_check<DBImpl, DB>(db->GetRootDB())
->MultiGetWithCallback(read_options, column_family, callback,
&sorted_keys);
ColumnFamilyHandleImpl* cfh = ColumnFamilyHandleImpl* cfh =
reinterpret_cast<ColumnFamilyHandleImpl*>(column_family); reinterpret_cast<ColumnFamilyHandleImpl*>(column_family);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册