Skip to content

Commit

Permalink
Add IteratorTraceExecutionResult for iterator related trace records…
Browse files Browse the repository at this point in the history
…. (#8687)

Summary:
- Allow to get `Valid()`, `status()`, `key()` and `value()` of an iterator from `IteratorTraceExecutionResult`.
- Move lower bound and upper bound from `IteratorSeekQueryTraceRecord` to `IteratorQueryTraceRecord`.

Added test in `DBTest2.TraceAndReplay`.

Pull Request resolved: facebook/rocksdb#8687

Reviewed By: zhichao-cao

Differential Revision: D30457630

Pulled By: autopear

fbshipit-source-id: be433099a25895b3aa6f0c00f95ad7b1d7489c1d
  • Loading branch information
autopear authored and facebook-github-bot committed Aug 20, 2021
1 parent f35042c commit baf22b4
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 87 deletions.
70 changes: 49 additions & 21 deletions db/db_test2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4256,13 +4256,6 @@ class TraceExecutionResultHandler : public TraceRecordResult::Handler {
writes_++;
break;
}
case kTraceIteratorSeek:
case kTraceIteratorSeekForPrev: {
total_latency_ += result.GetLatency();
cnt_++;
seeks_++;
break;
}
default:
return Status::Corruption("Type mismatch.");
}
Expand Down Expand Up @@ -4309,6 +4302,25 @@ class TraceExecutionResultHandler : public TraceRecordResult::Handler {
return Status::OK();
}

virtual Status Handle(const IteratorTraceExecutionResult& result) override {
if (result.GetStartTimestamp() > result.GetEndTimestamp()) {
return Status::InvalidArgument("Invalid timestamps.");
}
result.GetStatus().PermitUncheckedError();
switch (result.GetTraceType()) {
case kTraceIteratorSeek:
case kTraceIteratorSeekForPrev: {
total_latency_ += result.GetLatency();
cnt_++;
seeks_++;
break;
}
default:
return Status::Corruption("Type mismatch.");
}
return Status::OK();
}

void Reset() {
total_latency_ = 0;
cnt_ = 0;
Expand Down Expand Up @@ -4644,23 +4656,39 @@ TEST_F(DBTest2, TraceAndManualReplay) {
continue;
}
if (s.ok()) {
if (record->GetTraceType() == kTraceIteratorSeek ||
record->GetTraceType() == kTraceIteratorSeekForPrev) {
IteratorSeekQueryTraceRecord* iter_r =
dynamic_cast<IteratorSeekQueryTraceRecord*>(record.get());
// Check if lower/upper bounds are correctly saved and decoded.
lower_bound = iter_r->GetLowerBound();
if (!lower_bound.empty()) {
ASSERT_EQ(lower_bound.ToString(), "iter-1");
}
upper_bound = iter_r->GetUpperBound();
if (!upper_bound.empty()) {
ASSERT_EQ(upper_bound.ToString(), "iter-3");
}
}
ASSERT_OK(replayer->Execute(record, &result));
if (result != nullptr) {
ASSERT_OK(result->Accept(&res_handler));
if (record->GetTraceType() == kTraceIteratorSeek ||
record->GetTraceType() == kTraceIteratorSeekForPrev) {
IteratorSeekQueryTraceRecord* iter_rec =
dynamic_cast<IteratorSeekQueryTraceRecord*>(record.get());
IteratorTraceExecutionResult* iter_res =
dynamic_cast<IteratorTraceExecutionResult*>(result.get());
// Check if lower/upper bounds are correctly saved and decoded.
std::string lower_str = iter_rec->GetLowerBound().ToString();
std::string upper_str = iter_rec->GetUpperBound().ToString();
std::string iter_key = iter_res->GetKey().ToString();
std::string iter_value = iter_res->GetValue().ToString();
if (!lower_str.empty() && !upper_str.empty()) {
ASSERT_EQ(lower_str, "iter-1");
ASSERT_EQ(upper_str, "iter-3");
if (iter_res->GetValid()) {
// If iterator is valid, then lower_bound <= key < upper_bound.
ASSERT_GE(iter_key, lower_str);
ASSERT_LT(iter_key, upper_str);
} else {
// If iterator is invalid, then
// key < lower_bound or key >= upper_bound.
ASSERT_TRUE(iter_key < lower_str || iter_key >= upper_str);
}
}
// If iterator is invalid, the key and value should be empty.
if (!iter_res->GetValid()) {
ASSERT_TRUE(iter_key.empty());
ASSERT_TRUE(iter_value.empty());
}
}
result.reset();
}
}
Expand Down
29 changes: 17 additions & 12 deletions include/rocksdb/trace_record.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,15 @@ class TraceRecord {
public:
virtual ~Handler() = default;

// Handle WriteQueryTraceRecord
virtual Status Handle(const WriteQueryTraceRecord& record,
std::unique_ptr<TraceRecordResult>* result) = 0;

// Handle GetQueryTraceRecord
virtual Status Handle(const GetQueryTraceRecord& record,
std::unique_ptr<TraceRecordResult>* result) = 0;

// Handle IteratorSeekQueryTraceRecord
virtual Status Handle(const IteratorSeekQueryTraceRecord& record,
std::unique_ptr<TraceRecordResult>* result) = 0;

// Handle MultiGetQueryTraceRecord
virtual Status Handle(const MultiGetQueryTraceRecord& record,
std::unique_ptr<TraceRecordResult>* result) = 0;
};
Expand Down Expand Up @@ -152,6 +148,23 @@ class GetQueryTraceRecord : public QueryTraceRecord {
class IteratorQueryTraceRecord : public QueryTraceRecord {
public:
explicit IteratorQueryTraceRecord(uint64_t timestamp);

IteratorQueryTraceRecord(PinnableSlice&& lower_bound,
PinnableSlice&& upper_bound, uint64_t timestamp);

IteratorQueryTraceRecord(const std::string& lower_bound,
const std::string& upper_bound, uint64_t timestamp);

virtual ~IteratorQueryTraceRecord() override;

// Get the iterator's lower/upper bound. They may be used in ReadOptions to
// create an Iterator instance.
virtual Slice GetLowerBound() const;
virtual Slice GetUpperBound() const;

private:
PinnableSlice lower_;
PinnableSlice upper_;
};

// Trace record for Iterator::Seek() and Iterator::SeekForPrev() operation.
Expand Down Expand Up @@ -193,21 +206,13 @@ class IteratorSeekQueryTraceRecord : public IteratorQueryTraceRecord {
// Key to seek to.
virtual Slice GetKey() const;

// Iterate lower bound.
virtual Slice GetLowerBound() const;

// Iterate upper bound.
virtual Slice GetUpperBound() const;

Status Accept(Handler* handler,
std::unique_ptr<TraceRecordResult>* result) override;

private:
SeekType type_;
uint32_t cf_id_;
PinnableSlice key_;
PinnableSlice lower_;
PinnableSlice upper_;
};

// Trace record for DB::MultiGet() operation.
Expand Down
79 changes: 44 additions & 35 deletions include/rocksdb/trace_record_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
#include <vector>

#include "rocksdb/rocksdb_namespace.h"
#include "rocksdb/slice.h"
#include "rocksdb/status.h"
#include "rocksdb/trace_record.h"

namespace ROCKSDB_NAMESPACE {

class IteratorTraceExecutionResult;
class MultiValuesTraceExecutionResult;
class SingleValueTraceExecutionResult;
class StatusOnlyTraceExecutionResult;
Expand All @@ -34,42 +36,14 @@ class TraceRecordResult {
public:
virtual ~Handler() = default;

// Handle StatusOnlyTraceExecutionResult
virtual Status Handle(const StatusOnlyTraceExecutionResult& result) = 0;

// Handle SingleValueTraceExecutionResult
virtual Status Handle(const SingleValueTraceExecutionResult& result) = 0;

// Handle MultiValuesTraceExecutionResult
virtual Status Handle(const MultiValuesTraceExecutionResult& result) = 0;
};

/*
* Example handler to just print the trace record execution results.
*
* class ResultPrintHandler : public TraceRecordResult::Handler {
* public:
* ResultPrintHandler();
* ~ResultPrintHandler() override {}
*
* Status Handle(const StatusOnlyTraceExecutionResult& result) override {
* std::cout << "Status: " << result.GetStatus().ToString() << std::endl;
* }
*
* Status Handle(const SingleValueTraceExecutionResult& result) override {
* std::cout << "Status: " << result.GetStatus().ToString()
* << ", value: " << result.GetValue() << std::endl;
* }
*
* Status Handle(const MultiValuesTraceExecutionResult& result) override {
* size_t size = result.GetMultiStatus().size();
* for (size_t i = 0; i < size; i++) {
* std::cout << "Status: " << result.GetMultiStatus()[i].ToString()
* << ", value: " << result.GetValues()[i] << std::endl;
* }
* }
* };
* */
virtual Status Handle(const IteratorTraceExecutionResult& result) = 0;
};

// Accept the handler.
virtual Status Accept(Handler* handler) = 0;
Expand Down Expand Up @@ -106,8 +80,7 @@ class TraceExecutionResult : public TraceRecordResult {
};

// Result for operations that only return a single Status.
// Example operations: DB::Write(), Iterator::Seek() and
// Iterator::SeekForPrev().
// Example operation: DB::Write()
class StatusOnlyTraceExecutionResult : public TraceExecutionResult {
public:
StatusOnlyTraceExecutionResult(Status status, uint64_t start_timestamp,
Expand Down Expand Up @@ -138,7 +111,7 @@ class SingleValueTraceExecutionResult : public TraceExecutionResult {

virtual ~SingleValueTraceExecutionResult() override;

// Return status of DB::Get(), etc.
// Return status of DB::Get().
virtual const Status& GetStatus() const;

// Value for the searched key.
Expand All @@ -151,7 +124,7 @@ class SingleValueTraceExecutionResult : public TraceExecutionResult {
std::string value_;
};

// Result for operations that return multiple Status(es) and values.
// Result for operations that return multiple Status(es) and values as vectors.
// Example operation: DB::MultiGet()
class MultiValuesTraceExecutionResult : public TraceExecutionResult {
public:
Expand All @@ -162,7 +135,7 @@ class MultiValuesTraceExecutionResult : public TraceExecutionResult {

virtual ~MultiValuesTraceExecutionResult() override;

// Returned Status(es) of DB::MultiGet(), etc.
// Returned Status(es) of DB::MultiGet().
virtual const std::vector<Status>& GetMultiStatus() const;

// Returned values for the searched keys.
Expand All @@ -175,4 +148,40 @@ class MultiValuesTraceExecutionResult : public TraceExecutionResult {
std::vector<std::string> values_;
};

// Result for Iterator operations.
// Example operations: Iterator::Seek(), Iterator::SeekForPrev()
class IteratorTraceExecutionResult : public TraceExecutionResult {
public:
IteratorTraceExecutionResult(bool valid, Status status, PinnableSlice&& key,
PinnableSlice&& value, uint64_t start_timestamp,
uint64_t end_timestamp, TraceType trace_type);

IteratorTraceExecutionResult(bool valid, Status status,
const std::string& key, const std::string& value,
uint64_t start_timestamp, uint64_t end_timestamp,
TraceType trace_type);

virtual ~IteratorTraceExecutionResult() override;

// Return if the Iterator is valid.
virtual bool GetValid() const;

// Return the status of the Iterator.
virtual const Status& GetStatus() const;

// Key of the current iterating entry, empty if GetValid() is false.
virtual Slice GetKey() const;

// Value of the current iterating entry, empty if GetValid() is false.
virtual Slice GetValue() const;

virtual Status Accept(Handler* handler) override;

private:
bool valid_;
Status status_;
PinnableSlice key_;
PinnableSlice value_;
};

} // namespace ROCKSDB_NAMESPACE
40 changes: 25 additions & 15 deletions trace_replay/trace_record.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ Status GetQueryTraceRecord::Accept(Handler* handler,
IteratorQueryTraceRecord::IteratorQueryTraceRecord(uint64_t timestamp)
: QueryTraceRecord(timestamp) {}

IteratorQueryTraceRecord::IteratorQueryTraceRecord(PinnableSlice&& lower_bound,
PinnableSlice&& upper_bound,
uint64_t timestamp)
: QueryTraceRecord(timestamp),
lower_(std::move(lower_bound)),
upper_(std::move(upper_bound)) {}

IteratorQueryTraceRecord::IteratorQueryTraceRecord(
const std::string& lower_bound, const std::string& upper_bound,
uint64_t timestamp)
: QueryTraceRecord(timestamp) {
lower_.PinSelf(lower_bound);
upper_.PinSelf(upper_bound);
}

IteratorQueryTraceRecord::~IteratorQueryTraceRecord() {}

Slice IteratorQueryTraceRecord::GetLowerBound() const { return Slice(lower_); }

Slice IteratorQueryTraceRecord::GetUpperBound() const { return Slice(upper_); }

// IteratorSeekQueryTraceRecord
IteratorSeekQueryTraceRecord::IteratorSeekQueryTraceRecord(
SeekType seek_type, uint32_t column_family_id, PinnableSlice&& key,
Expand All @@ -104,23 +125,20 @@ IteratorSeekQueryTraceRecord::IteratorSeekQueryTraceRecord(
SeekType seek_type, uint32_t column_family_id, PinnableSlice&& key,
PinnableSlice&& lower_bound, PinnableSlice&& upper_bound,
uint64_t timestamp)
: IteratorQueryTraceRecord(timestamp),
: IteratorQueryTraceRecord(std::move(lower_bound), std::move(upper_bound),
timestamp),
type_(seek_type),
cf_id_(column_family_id),
key_(std::move(key)),
lower_(std::move(lower_bound)),
upper_(std::move(upper_bound)) {}
key_(std::move(key)) {}

IteratorSeekQueryTraceRecord::IteratorSeekQueryTraceRecord(
SeekType seek_type, uint32_t column_family_id, const std::string& key,
const std::string& lower_bound, const std::string& upper_bound,
uint64_t timestamp)
: IteratorQueryTraceRecord(timestamp),
: IteratorQueryTraceRecord(lower_bound, upper_bound, timestamp),
type_(seek_type),
cf_id_(column_family_id) {
key_.PinSelf(key);
lower_.PinSelf(lower_bound);
upper_.PinSelf(upper_bound);
}

IteratorSeekQueryTraceRecord::~IteratorSeekQueryTraceRecord() { key_.clear(); }
Expand All @@ -140,14 +158,6 @@ uint32_t IteratorSeekQueryTraceRecord::GetColumnFamilyID() const {

Slice IteratorSeekQueryTraceRecord::GetKey() const { return Slice(key_); }

Slice IteratorSeekQueryTraceRecord::GetLowerBound() const {
return Slice(lower_);
}

Slice IteratorSeekQueryTraceRecord::GetUpperBound() const {
return Slice(upper_);
}

Status IteratorSeekQueryTraceRecord::Accept(
Handler* handler, std::unique_ptr<TraceRecordResult>* result) {
assert(handler != nullptr);
Expand Down
17 changes: 13 additions & 4 deletions trace_replay/trace_record_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,21 @@ Status TraceExecutionHandler::Handle(
uint64_t end = clock_->NowMicros();

Status s = single_iter->status();
delete single_iter;

if (s.ok() && result != nullptr) {
result->reset(new StatusOnlyTraceExecutionResult(s, start, end,
record.GetTraceType()));
if (single_iter->Valid()) {
PinnableSlice ps_key;
ps_key.PinSelf(single_iter->key());
PinnableSlice ps_value;
ps_value.PinSelf(single_iter->value());
result->reset(new IteratorTraceExecutionResult(
true, s, std::move(ps_key), std::move(ps_value), start, end,
record.GetTraceType()));
} else {
result->reset(new IteratorTraceExecutionResult(
false, s, "", "", start, end, record.GetTraceType()));
}
}
delete single_iter;

return s;
}
Expand Down
Loading

0 comments on commit baf22b4

Please sign in to comment.