Use PinnableSlice in Transactions
Summary: The ::Get from DB is not augmented with an overload method that takes a PinnableSlice instead of a string. Transactions however are not yet upgraded to use the new API. As a result, transaction users such as MyRocks cannot benefit from it. This patch updates the transactional API with a PinnableSlice overload. Closes https://github.com/facebook/rocksdb/pull/2736 Differential Revision: D5645770 Pulled By: maysamyabandeh fbshipit-source-id: f6af520df902f842de1bcf99bed3e8dfc43ad96d
This commit is contained in:
parent
1dfcdb15f9
commit
ccf7f833e3
@ -169,8 +169,26 @@ class Transaction {
|
|||||||
ColumnFamilyHandle* column_family, const Slice& key,
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||||||
std::string* value) = 0;
|
std::string* value) = 0;
|
||||||
|
|
||||||
|
// An overload of the the above method that receives a PinnableSlice
|
||||||
|
// For backward compatiblity a default implementation is provided
|
||||||
|
virtual Status Get(const ReadOptions& options,
|
||||||
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||||||
|
PinnableSlice* pinnable_val) {
|
||||||
|
assert(pinnable_val != nullptr);
|
||||||
|
auto s = Get(options, column_family, key, pinnable_val->GetSelf());
|
||||||
|
pinnable_val->PinSelf();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
virtual Status Get(const ReadOptions& options, const Slice& key,
|
virtual Status Get(const ReadOptions& options, const Slice& key,
|
||||||
std::string* value) = 0;
|
std::string* value) = 0;
|
||||||
|
virtual Status Get(const ReadOptions& options, const Slice& key,
|
||||||
|
PinnableSlice* pinnable_val) {
|
||||||
|
assert(pinnable_val != nullptr);
|
||||||
|
auto s = Get(options, key, pinnable_val->GetSelf());
|
||||||
|
pinnable_val->PinSelf();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
virtual std::vector<Status> MultiGet(
|
virtual std::vector<Status> MultiGet(
|
||||||
const ReadOptions& options,
|
const ReadOptions& options,
|
||||||
@ -212,6 +230,22 @@ class Transaction {
|
|||||||
const Slice& key, std::string* value,
|
const Slice& key, std::string* value,
|
||||||
bool exclusive = true) = 0;
|
bool exclusive = true) = 0;
|
||||||
|
|
||||||
|
// An overload of the the above method that receives a PinnableSlice
|
||||||
|
// For backward compatiblity a default implementation is provided
|
||||||
|
virtual Status GetForUpdate(const ReadOptions& options,
|
||||||
|
ColumnFamilyHandle* column_family,
|
||||||
|
const Slice& key, PinnableSlice* pinnable_val,
|
||||||
|
bool exclusive = true) {
|
||||||
|
if (pinnable_val == nullptr) {
|
||||||
|
std::string* null_str = nullptr;
|
||||||
|
return GetForUpdate(options, key, null_str);
|
||||||
|
} else {
|
||||||
|
auto s = GetForUpdate(options, key, pinnable_val->GetSelf());
|
||||||
|
pinnable_val->PinSelf();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual Status GetForUpdate(const ReadOptions& options, const Slice& key,
|
virtual Status GetForUpdate(const ReadOptions& options, const Slice& key,
|
||||||
std::string* value, bool exclusive = true) = 0;
|
std::string* value, bool exclusive = true) = 0;
|
||||||
|
|
||||||
|
@ -186,10 +186,20 @@ class WriteBatchWithIndex : public WriteBatchBase {
|
|||||||
// regardless).
|
// regardless).
|
||||||
Status GetFromBatchAndDB(DB* db, const ReadOptions& read_options,
|
Status GetFromBatchAndDB(DB* db, const ReadOptions& read_options,
|
||||||
const Slice& key, std::string* value);
|
const Slice& key, std::string* value);
|
||||||
|
|
||||||
|
// An overload of the the above method that receives a PinnableSlice
|
||||||
|
Status GetFromBatchAndDB(DB* db, const ReadOptions& read_options,
|
||||||
|
const Slice& key, PinnableSlice* value);
|
||||||
|
|
||||||
Status GetFromBatchAndDB(DB* db, const ReadOptions& read_options,
|
Status GetFromBatchAndDB(DB* db, const ReadOptions& read_options,
|
||||||
ColumnFamilyHandle* column_family, const Slice& key,
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||||||
std::string* value);
|
std::string* value);
|
||||||
|
|
||||||
|
// An overload of the the above method that receives a PinnableSlice
|
||||||
|
Status GetFromBatchAndDB(DB* db, const ReadOptions& read_options,
|
||||||
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||||||
|
PinnableSlice* value);
|
||||||
|
|
||||||
// Records the state of the batch for future calls to RollbackToSavePoint().
|
// Records the state of the batch for future calls to RollbackToSavePoint().
|
||||||
// May be called multiple times to set multiple save points.
|
// May be called multiple times to set multiple save points.
|
||||||
void SetSavePoint() override;
|
void SetSavePoint() override;
|
||||||
|
@ -181,8 +181,21 @@ Status TransactionBaseImpl::RollbackToSavePoint() {
|
|||||||
Status TransactionBaseImpl::Get(const ReadOptions& read_options,
|
Status TransactionBaseImpl::Get(const ReadOptions& read_options,
|
||||||
ColumnFamilyHandle* column_family,
|
ColumnFamilyHandle* column_family,
|
||||||
const Slice& key, std::string* value) {
|
const Slice& key, std::string* value) {
|
||||||
|
assert(value != nullptr);
|
||||||
|
PinnableSlice pinnable_val(value);
|
||||||
|
assert(!pinnable_val.IsPinned());
|
||||||
|
auto s = Get(read_options, column_family, key, &pinnable_val);
|
||||||
|
if (s.ok() && pinnable_val.IsPinned()) {
|
||||||
|
value->assign(pinnable_val.data(), pinnable_val.size());
|
||||||
|
} // else value is already assigned
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status TransactionBaseImpl::Get(const ReadOptions& read_options,
|
||||||
|
ColumnFamilyHandle* column_family,
|
||||||
|
const Slice& key, PinnableSlice* pinnable_val) {
|
||||||
return write_batch_.GetFromBatchAndDB(db_, read_options, column_family, key,
|
return write_batch_.GetFromBatchAndDB(db_, read_options, column_family, key,
|
||||||
value);
|
pinnable_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status TransactionBaseImpl::GetForUpdate(const ReadOptions& read_options,
|
Status TransactionBaseImpl::GetForUpdate(const ReadOptions& read_options,
|
||||||
@ -192,7 +205,26 @@ Status TransactionBaseImpl::GetForUpdate(const ReadOptions& read_options,
|
|||||||
Status s = TryLock(column_family, key, true /* read_only */, exclusive);
|
Status s = TryLock(column_family, key, true /* read_only */, exclusive);
|
||||||
|
|
||||||
if (s.ok() && value != nullptr) {
|
if (s.ok() && value != nullptr) {
|
||||||
s = Get(read_options, column_family, key, value);
|
assert(value != nullptr);
|
||||||
|
PinnableSlice pinnable_val(value);
|
||||||
|
assert(!pinnable_val.IsPinned());
|
||||||
|
s = Get(read_options, column_family, key, &pinnable_val);
|
||||||
|
if (s.ok() && pinnable_val.IsPinned()) {
|
||||||
|
value->assign(pinnable_val.data(), pinnable_val.size());
|
||||||
|
} // else value is already assigned
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status TransactionBaseImpl::GetForUpdate(const ReadOptions& read_options,
|
||||||
|
ColumnFamilyHandle* column_family,
|
||||||
|
const Slice& key,
|
||||||
|
PinnableSlice* pinnable_val,
|
||||||
|
bool exclusive) {
|
||||||
|
Status s = TryLock(column_family, key, true /* read_only */, exclusive);
|
||||||
|
|
||||||
|
if (s.ok() && pinnable_val != nullptr) {
|
||||||
|
s = Get(read_options, column_family, key, pinnable_val);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -46,18 +46,27 @@ class TransactionBaseImpl : public Transaction {
|
|||||||
|
|
||||||
Status RollbackToSavePoint() override;
|
Status RollbackToSavePoint() override;
|
||||||
|
|
||||||
|
using Transaction::Get;
|
||||||
Status Get(const ReadOptions& options, ColumnFamilyHandle* column_family,
|
Status Get(const ReadOptions& options, ColumnFamilyHandle* column_family,
|
||||||
const Slice& key, std::string* value) override;
|
const Slice& key, std::string* value) override;
|
||||||
|
|
||||||
|
Status Get(const ReadOptions& options, ColumnFamilyHandle* column_family,
|
||||||
|
const Slice& key, PinnableSlice* value) override;
|
||||||
|
|
||||||
Status Get(const ReadOptions& options, const Slice& key,
|
Status Get(const ReadOptions& options, const Slice& key,
|
||||||
std::string* value) override {
|
std::string* value) override {
|
||||||
return Get(options, db_->DefaultColumnFamily(), key, value);
|
return Get(options, db_->DefaultColumnFamily(), key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using Transaction::GetForUpdate;
|
||||||
Status GetForUpdate(const ReadOptions& options,
|
Status GetForUpdate(const ReadOptions& options,
|
||||||
ColumnFamilyHandle* column_family, const Slice& key,
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||||||
std::string* value, bool exclusive) override;
|
std::string* value, bool exclusive) override;
|
||||||
|
|
||||||
|
Status GetForUpdate(const ReadOptions& options,
|
||||||
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||||||
|
PinnableSlice* pinnable_val, bool exclusive) override;
|
||||||
|
|
||||||
Status GetForUpdate(const ReadOptions& options, const Slice& key,
|
Status GetForUpdate(const ReadOptions& options, const Slice& key,
|
||||||
std::string* value, bool exclusive) override {
|
std::string* value, bool exclusive) override {
|
||||||
return GetForUpdate(options, db_->DefaultColumnFamily(), key, value,
|
return GetForUpdate(options, db_->DefaultColumnFamily(), key, value,
|
||||||
|
@ -385,7 +385,7 @@ class WBWIIteratorImpl : public WBWIIterator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct WriteBatchWithIndex::Rep {
|
struct WriteBatchWithIndex::Rep {
|
||||||
Rep(const Comparator* index_comparator, size_t reserved_bytes = 0,
|
explicit Rep(const Comparator* index_comparator, size_t reserved_bytes = 0,
|
||||||
size_t max_bytes = 0, bool _overwrite_key = false)
|
size_t max_bytes = 0, bool _overwrite_key = false)
|
||||||
: write_batch(reserved_bytes, max_bytes),
|
: write_batch(reserved_bytes, max_bytes),
|
||||||
comparator(index_comparator, &write_batch),
|
comparator(index_comparator, &write_batch),
|
||||||
@ -743,8 +743,23 @@ Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
|||||||
const ReadOptions& read_options,
|
const ReadOptions& read_options,
|
||||||
const Slice& key,
|
const Slice& key,
|
||||||
std::string* value) {
|
std::string* value) {
|
||||||
|
assert(value != nullptr);
|
||||||
|
PinnableSlice pinnable_val(value);
|
||||||
|
assert(!pinnable_val.IsPinned());
|
||||||
|
auto s = GetFromBatchAndDB(db, read_options, db->DefaultColumnFamily(), key,
|
||||||
|
&pinnable_val);
|
||||||
|
if (s.ok() && pinnable_val.IsPinned()) {
|
||||||
|
value->assign(pinnable_val.data(), pinnable_val.size());
|
||||||
|
} // else value is already assigned
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
||||||
|
const ReadOptions& read_options,
|
||||||
|
const Slice& key,
|
||||||
|
PinnableSlice* pinnable_val) {
|
||||||
return GetFromBatchAndDB(db, read_options, db->DefaultColumnFamily(), key,
|
return GetFromBatchAndDB(db, read_options, db->DefaultColumnFamily(), key,
|
||||||
value);
|
pinnable_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
||||||
@ -752,19 +767,38 @@ Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
|||||||
ColumnFamilyHandle* column_family,
|
ColumnFamilyHandle* column_family,
|
||||||
const Slice& key,
|
const Slice& key,
|
||||||
std::string* value) {
|
std::string* value) {
|
||||||
|
assert(value != nullptr);
|
||||||
|
PinnableSlice pinnable_val(value);
|
||||||
|
assert(!pinnable_val.IsPinned());
|
||||||
|
auto s =
|
||||||
|
GetFromBatchAndDB(db, read_options, column_family, key, &pinnable_val);
|
||||||
|
if (s.ok() && pinnable_val.IsPinned()) {
|
||||||
|
value->assign(pinnable_val.data(), pinnable_val.size());
|
||||||
|
} // else value is already assigned
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
||||||
|
const ReadOptions& read_options,
|
||||||
|
ColumnFamilyHandle* column_family,
|
||||||
|
const Slice& key,
|
||||||
|
PinnableSlice* pinnable_val) {
|
||||||
Status s;
|
Status s;
|
||||||
MergeContext merge_context;
|
MergeContext merge_context;
|
||||||
const ImmutableDBOptions& immuable_db_options =
|
const ImmutableDBOptions& immuable_db_options =
|
||||||
reinterpret_cast<DBImpl*>(db)->immutable_db_options();
|
reinterpret_cast<DBImpl*>(db)->immutable_db_options();
|
||||||
|
|
||||||
std::string batch_value;
|
// Since the lifetime of the WriteBatch is the same as that of the transaction
|
||||||
|
// we cannot pin it as otherwise the returned value will not be available
|
||||||
|
// after the transaction finishes.
|
||||||
|
std::string& batch_value = *pinnable_val->GetSelf();
|
||||||
WriteBatchWithIndexInternal::Result result =
|
WriteBatchWithIndexInternal::Result result =
|
||||||
WriteBatchWithIndexInternal::GetFromBatch(
|
WriteBatchWithIndexInternal::GetFromBatch(
|
||||||
immuable_db_options, this, column_family, key, &merge_context,
|
immuable_db_options, this, column_family, key, &merge_context,
|
||||||
&rep->comparator, &batch_value, rep->overwrite_key, &s);
|
&rep->comparator, &batch_value, rep->overwrite_key, &s);
|
||||||
|
|
||||||
if (result == WriteBatchWithIndexInternal::Result::kFound) {
|
if (result == WriteBatchWithIndexInternal::Result::kFound) {
|
||||||
value->assign(batch_value.data(), batch_value.size());
|
pinnable_val->PinSelf();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
if (result == WriteBatchWithIndexInternal::Result::kDeleted) {
|
if (result == WriteBatchWithIndexInternal::Result::kDeleted) {
|
||||||
@ -785,7 +819,7 @@ Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
|||||||
result == WriteBatchWithIndexInternal::Result::kNotFound);
|
result == WriteBatchWithIndexInternal::Result::kNotFound);
|
||||||
|
|
||||||
// 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.
|
||||||
s = db->Get(read_options, column_family, key, value);
|
s = db->Get(read_options, column_family, key, pinnable_val);
|
||||||
|
|
||||||
if (s.ok() || s.IsNotFound()) { // DB Get Succeeded
|
if (s.ok() || s.IsNotFound()) { // DB Get Succeeded
|
||||||
if (result == WriteBatchWithIndexInternal::Result::kMergeInProgress) {
|
if (result == WriteBatchWithIndexInternal::Result::kMergeInProgress) {
|
||||||
@ -797,18 +831,18 @@ Status WriteBatchWithIndex::GetFromBatchAndDB(DB* db,
|
|||||||
Env* env = immuable_db_options.env;
|
Env* env = immuable_db_options.env;
|
||||||
Logger* logger = immuable_db_options.info_log.get();
|
Logger* logger = immuable_db_options.info_log.get();
|
||||||
|
|
||||||
Slice db_slice(*value);
|
|
||||||
Slice* merge_data;
|
Slice* merge_data;
|
||||||
if (s.ok()) {
|
if (s.ok()) {
|
||||||
merge_data = &db_slice;
|
merge_data = pinnable_val;
|
||||||
} else { // Key not present in db (s.IsNotFound())
|
} else { // Key not present in db (s.IsNotFound())
|
||||||
merge_data = nullptr;
|
merge_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_operator) {
|
if (merge_operator) {
|
||||||
s = MergeHelper::TimedFullMerge(merge_operator, key, merge_data,
|
s = MergeHelper::TimedFullMerge(
|
||||||
merge_context.GetOperands(), value,
|
merge_operator, key, merge_data, merge_context.GetOperands(),
|
||||||
logger, statistics, env);
|
pinnable_val->GetSelf(), logger, statistics, env);
|
||||||
|
pinnable_val->PinSelf();
|
||||||
} else {
|
} else {
|
||||||
s = Status::InvalidArgument("Options::merge_operator must be set");
|
s = Status::InvalidArgument("Options::merge_operator must be set");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user