Fix link error reported in issue 9272 (#9278)

Summary:
As title, Closes https://github.com/facebook/rocksdb/issues/9272
Since TimestampAssigner-related classes needs to access
`WriteBatch::ProtectionInfo` objects which is for internal use only,
it's difficult to make `AssignTimestamp` methods a template and put them
in the same public header, `include/rocksdb/write_batch.h`.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/9278

Test Plan:
```
make check
# Also manually test following the repro-steps in issue 9272
```

Reviewed By: ltamasi

Differential Revision: D33012686

Pulled By: riversand963

fbshipit-source-id: 89f24a86a1170125bd0b94ef3b32e69aa08bd949
This commit is contained in:
Yanqin Jin 2021-12-10 20:32:31 -08:00 committed by Facebook GitHub Bot
parent 297d913275
commit 5455cacd18
3 changed files with 60 additions and 50 deletions

View File

@ -1223,6 +1223,20 @@ Status WriteBatch::PopSavePoint() {
return Status::OK(); return Status::OK();
} }
Status WriteBatch::AssignTimestamp(
const Slice& ts, std::function<Status(uint32_t, size_t&)> checker) {
TimestampAssigner ts_assigner(prot_info_.get(), std::move(checker), ts);
return Iterate(&ts_assigner);
}
Status WriteBatch::AssignTimestamps(
const std::vector<Slice>& ts_list,
std::function<Status(uint32_t, size_t&)> checker) {
SimpleListTimestampAssigner ts_assigner(prot_info_.get(), std::move(checker),
ts_list);
return Iterate(&ts_assigner);
}
class MemTableInserter : public WriteBatch::Handler { class MemTableInserter : public WriteBatch::Handler {
SequenceNumber sequence_; SequenceNumber sequence_;

View File

@ -265,11 +265,12 @@ class LocalSavePoint {
#endif #endif
}; };
template <typename Derived, typename Checker> template <typename Derived>
class TimestampAssignerBase : public WriteBatch::Handler { class TimestampAssignerBase : public WriteBatch::Handler {
public: public:
explicit TimestampAssignerBase(WriteBatch::ProtectionInfo* prot_info, explicit TimestampAssignerBase(
Checker&& checker) WriteBatch::ProtectionInfo* prot_info,
std::function<Status(uint32_t, size_t&)>&& checker)
: prot_info_(prot_info), checker_(std::move(checker)) {} : prot_info_(prot_info), checker_(std::move(checker)) {}
~TimestampAssignerBase() override {} ~TimestampAssignerBase() override {}
@ -360,27 +361,25 @@ class TimestampAssignerBase : public WriteBatch::Handler {
TimestampAssignerBase& operator=(TimestampAssignerBase&&) = delete; TimestampAssignerBase& operator=(TimestampAssignerBase&&) = delete;
WriteBatch::ProtectionInfo* const prot_info_ = nullptr; WriteBatch::ProtectionInfo* const prot_info_ = nullptr;
const Checker checker_{}; const std::function<Status(uint32_t, size_t&)> checker_{};
size_t idx_ = 0; size_t idx_ = 0;
}; };
template <typename Checker>
class SimpleListTimestampAssigner class SimpleListTimestampAssigner
: public TimestampAssignerBase<SimpleListTimestampAssigner<Checker>, : public TimestampAssignerBase<SimpleListTimestampAssigner> {
Checker> {
public: public:
explicit SimpleListTimestampAssigner(WriteBatch::ProtectionInfo* prot_info, explicit SimpleListTimestampAssigner(
Checker checker, WriteBatch::ProtectionInfo* prot_info,
const std::vector<Slice>& timestamps) std::function<Status(uint32_t, size_t&)>&& checker,
: TimestampAssignerBase<SimpleListTimestampAssigner<Checker>, Checker>( const std::vector<Slice>& timestamps)
prot_info, std::move(checker)), : TimestampAssignerBase<SimpleListTimestampAssigner>(prot_info,
std::move(checker)),
timestamps_(timestamps) {} timestamps_(timestamps) {}
~SimpleListTimestampAssigner() override {} ~SimpleListTimestampAssigner() override {}
private: private:
friend class TimestampAssignerBase<SimpleListTimestampAssigner<Checker>, friend class TimestampAssignerBase<SimpleListTimestampAssigner>;
Checker>;
Status AssignTimestampImpl(uint32_t cf, const Slice& key, size_t idx) { Status AssignTimestampImpl(uint32_t cf, const Slice& key, size_t idx) {
if (idx >= timestamps_.size()) { if (idx >= timestamps_.size()) {
@ -398,21 +397,19 @@ class SimpleListTimestampAssigner
const std::vector<Slice>& timestamps_; const std::vector<Slice>& timestamps_;
}; };
template <typename Checker> class TimestampAssigner : public TimestampAssignerBase<TimestampAssigner> {
class TimestampAssigner
: public TimestampAssignerBase<TimestampAssigner<Checker>, Checker> {
public: public:
explicit TimestampAssigner(WriteBatch::ProtectionInfo* prot_info, explicit TimestampAssigner(WriteBatch::ProtectionInfo* prot_info,
Checker checker, const Slice& ts) std::function<Status(uint32_t, size_t&)>&& checker,
: TimestampAssignerBase<TimestampAssigner<Checker>, Checker>( const Slice& ts)
prot_info, std::move(checker)), : TimestampAssignerBase<TimestampAssigner>(prot_info, std::move(checker)),
timestamp_(ts) { timestamp_(ts) {
assert(!timestamp_.empty()); assert(!timestamp_.empty());
} }
~TimestampAssigner() override {} ~TimestampAssigner() override {}
private: private:
friend class TimestampAssignerBase<TimestampAssigner<Checker>, Checker>; friend class TimestampAssignerBase<TimestampAssigner>;
Status AssignTimestampImpl(uint32_t cf, const Slice& key, size_t /*idx*/) { Status AssignTimestampImpl(uint32_t cf, const Slice& key, size_t /*idx*/) {
if (timestamp_.empty()) { if (timestamp_.empty()) {
@ -429,18 +426,4 @@ class TimestampAssigner
const Slice timestamp_; const Slice timestamp_;
}; };
template <typename Checker>
Status WriteBatch::AssignTimestamp(const Slice& ts, Checker checker) {
TimestampAssigner<Checker> ts_assigner(prot_info_.get(), checker, ts);
return Iterate(&ts_assigner);
}
template <typename Checker>
Status WriteBatch::AssignTimestamps(const std::vector<Slice>& ts_list,
Checker checker) {
SimpleListTimestampAssigner<Checker> ts_assigner(prot_info_.get(), checker,
ts_list);
return Iterate(&ts_assigner);
}
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE

View File

@ -342,25 +342,29 @@ class WriteBatch : public WriteBatchBase {
// Returns true if MarkRollback will be called during Iterate // Returns true if MarkRollback will be called during Iterate
bool HasRollback() const; bool HasRollback() const;
struct TimestampChecker final {
Status operator()(uint32_t /*cf*/, size_t& /*ts_sz*/) const {
return Status::OK();
}
};
// Experimental. // Experimental.
// Assign timestamp to write batch. // Assign timestamp to write batch.
// This requires that all keys, if enable timestamp, (possibly from multiple // This requires that all keys, if enable timestamp, (possibly from multiple
// column families) in the write batch have timestamps of the same format. // column families) in the write batch have timestamps of the same format.
//
// checker: callable object to check the timestamp sizes of column families. // checker: callable object to check the timestamp sizes of column families.
//
// in: cf, the column family id.
// in/out: ts_sz. Input as the expected timestamp size of the column
// family, output as the actual timestamp size of the column family.
// ret: OK if assignment succeeds.
// Status checker(uint32_t cf, size_t& ts_sz);
//
// User can call checker(uint32_t cf, size_t& ts_sz) which does the // User can call checker(uint32_t cf, size_t& ts_sz) which does the
// following: // following:
// 1. find out the timestamp size of cf. // 1. find out the timestamp size of the column family whose id equals `cf`.
// 2. if cf's timestamp size is 0, then set ts_sz to 0 and return OK. // 2. if cf's timestamp size is 0, then set ts_sz to 0 and return OK.
// 3. otherwise, compare ts_sz with cf's timestamp size and return // 3. otherwise, compare ts_sz with cf's timestamp size and return
// Status::InvalidArgument() if different. // Status::InvalidArgument() if different.
template <typename Checker = TimestampChecker> Status AssignTimestamp(
Status AssignTimestamp(const Slice& ts, Checker checker = Checker()); const Slice& ts,
std::function<Status(uint32_t, size_t&)> checker =
[](uint32_t /*cf*/, size_t& /*ts_sz*/) { return Status::OK(); });
// Experimental. // Experimental.
// Assign timestamps to write batch. // Assign timestamps to write batch.
@ -369,16 +373,25 @@ class WriteBatch : public WriteBatchBase {
// families can enable timestamp, while others disable the feature. // families can enable timestamp, while others disable the feature.
// If key does not have timestamp, then put an empty Slice in ts_list as // If key does not have timestamp, then put an empty Slice in ts_list as
// a placeholder. // a placeholder.
//
// checker: callable object specified by caller to check the timestamp sizes // checker: callable object specified by caller to check the timestamp sizes
// of column families. // of column families.
//
// in: cf, the column family id.
// in/out: ts_sz. Input as the expected timestamp size of the column
// family, output as the actual timestamp size of the column family.
// ret: OK if assignment succeeds.
// Status checker(uint32_t cf, size_t& ts_sz);
//
// User can call checker(uint32_t cf, size_t& ts_sz) which does the // User can call checker(uint32_t cf, size_t& ts_sz) which does the
// following: // following:
// 1. find out the timestamp size of cf. // 1. find out the timestamp size of the column family whose id equals `cf`.
// 2. compare ts_sz with cf's timestamp size and return // 2. compare ts_sz with cf's timestamp size and return
// Status::InvalidArgument() if different. // Status::InvalidArgument() if different.
template <typename Checker = TimestampChecker> Status AssignTimestamps(
Status AssignTimestamps(const std::vector<Slice>& ts_list, const std::vector<Slice>& ts_list,
Checker checker = Checker()); std::function<Status(uint32_t, size_t&)> checker =
[](uint32_t /*cf*/, size_t& /*ts_sz*/) { return Status::OK(); });
using WriteBatchBase::GetWriteBatch; using WriteBatchBase::GetWriteBatch;
WriteBatch* GetWriteBatch() override { return this; } WriteBatch* GetWriteBatch() override { return this; }