mirror of https://github.com/facebook/rocksdb.git
Fix a bug for surfacing write unix time (#13057)
Summary: The write unix time from non L0 files are not surfaced properly because the level's wrapper iterator doesn't have a `write_unix_time` implementation that delegates to the corresponding file. The unit test didn't catch this because it incorrectly destroy the old db and reopen to check write time, instead of just reopen and check. This fix also include a change to support ldb's scan command to get write time for easier debugging. Pull Request resolved: https://github.com/facebook/rocksdb/pull/13057 Test Plan: Updated unit tests Reviewed By: pdillinger Differential Revision: D64015107 Pulled By: jowlyzhang fbshipit-source-id: 244474f78a034f80c9235eea2aa8a0f4e54dff59
This commit is contained in:
parent
d963661d6f
commit
8181dfb1c4
|
@ -2512,6 +2512,7 @@ TEST_P(IteratorWriteTimeTest, ReadFromMemtables) {
|
||||||
start_time + kSecondsPerRecording * (i + 1));
|
start_time + kSecondsPerRecording * (i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ASSERT_EQ(kNumKeys, i);
|
||||||
ASSERT_OK(iter->status());
|
ASSERT_OK(iter->status());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2531,12 +2532,13 @@ TEST_P(IteratorWriteTimeTest, ReadFromMemtables) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT_OK(iter->status());
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_EQ(-1, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reopen the DB and disable the seqno to time recording, data with user
|
// Reopen the DB and disable the seqno to time recording, data with user
|
||||||
// specified write time can still get a write time before it's flushed.
|
// specified write time can still get a write time before it's flushed.
|
||||||
options.preserve_internal_time_seconds = 0;
|
options.preserve_internal_time_seconds = 0;
|
||||||
DestroyAndReopen(options);
|
Reopen(options);
|
||||||
ASSERT_OK(TimedPut(Key(kKeyWithWriteTime), rnd.RandomString(100),
|
ASSERT_OK(TimedPut(Key(kKeyWithWriteTime), rnd.RandomString(100),
|
||||||
kUserSpecifiedWriteTime));
|
kUserSpecifiedWriteTime));
|
||||||
{
|
{
|
||||||
|
@ -2613,6 +2615,7 @@ TEST_P(IteratorWriteTimeTest, ReadFromSstFile) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT_OK(iter->status());
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_EQ(kNumKeys, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backward iteration
|
// Backward iteration
|
||||||
|
@ -2632,12 +2635,13 @@ TEST_P(IteratorWriteTimeTest, ReadFromSstFile) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ASSERT_OK(iter->status());
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_EQ(-1, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reopen the DB and disable the seqno to time recording. Data retrieved from
|
// Reopen the DB and disable the seqno to time recording. Data retrieved from
|
||||||
// SST files still have write time available.
|
// SST files still have write time available.
|
||||||
options.preserve_internal_time_seconds = 0;
|
options.preserve_internal_time_seconds = 0;
|
||||||
DestroyAndReopen(options);
|
Reopen(options);
|
||||||
|
|
||||||
dbfull()->TEST_WaitForPeriodicTaskRun(
|
dbfull()->TEST_WaitForPeriodicTaskRun(
|
||||||
[&] { mock_clock_->MockSleepForSeconds(kSecondsPerRecording); });
|
[&] { mock_clock_->MockSleepForSeconds(kSecondsPerRecording); });
|
||||||
|
@ -2663,6 +2667,7 @@ TEST_P(IteratorWriteTimeTest, ReadFromSstFile) {
|
||||||
start_time + kSecondsPerRecording * (i + 1));
|
start_time + kSecondsPerRecording * (i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ASSERT_EQ(kNumKeys, i);
|
||||||
ASSERT_OK(iter->status());
|
ASSERT_OK(iter->status());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2686,6 +2691,7 @@ TEST_P(IteratorWriteTimeTest, ReadFromSstFile) {
|
||||||
VerifyKeyAndWriteTime(iter.get(), Key(i), 0);
|
VerifyKeyAndWriteTime(iter.get(), Key(i), 0);
|
||||||
}
|
}
|
||||||
ASSERT_OK(iter->status());
|
ASSERT_OK(iter->status());
|
||||||
|
ASSERT_EQ(kNumKeys, i);
|
||||||
}
|
}
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,6 +167,10 @@ class ForwardLevelIterator : public InternalIterator {
|
||||||
assert(valid_);
|
assert(valid_);
|
||||||
return file_iter_->value();
|
return file_iter_->value();
|
||||||
}
|
}
|
||||||
|
uint64_t write_unix_time() const override {
|
||||||
|
assert(valid_);
|
||||||
|
return file_iter_->write_unix_time();
|
||||||
|
}
|
||||||
Status status() const override {
|
Status status() const override {
|
||||||
if (!status_.ok()) {
|
if (!status_.ok()) {
|
||||||
return status_;
|
return status_;
|
||||||
|
|
|
@ -1050,6 +1050,11 @@ class LevelIterator final : public InternalIterator {
|
||||||
return file_iter_.value();
|
return file_iter_.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t write_unix_time() const override {
|
||||||
|
assert(Valid());
|
||||||
|
return file_iter_.write_unix_time();
|
||||||
|
}
|
||||||
|
|
||||||
Status status() const override {
|
Status status() const override {
|
||||||
return file_iter_.iter() ? file_iter_.status() : Status::OK();
|
return file_iter_.iter() ? file_iter_.status() : Status::OK();
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,7 @@ class LDBCommand {
|
||||||
static const std::string ARG_DECODE_BLOB_INDEX;
|
static const std::string ARG_DECODE_BLOB_INDEX;
|
||||||
static const std::string ARG_DUMP_UNCOMPRESSED_BLOBS;
|
static const std::string ARG_DUMP_UNCOMPRESSED_BLOBS;
|
||||||
static const std::string ARG_READ_TIMESTAMP;
|
static const std::string ARG_READ_TIMESTAMP;
|
||||||
|
static const std::string ARG_GET_WRITE_UNIX_TIME;
|
||||||
|
|
||||||
struct ParsedParams {
|
struct ParsedParams {
|
||||||
std::string cmd;
|
std::string cmd;
|
||||||
|
|
|
@ -74,6 +74,10 @@ class EmptyInternalIterator : public InternalIteratorBase<TValue> {
|
||||||
assert(false);
|
assert(false);
|
||||||
return TValue();
|
return TValue();
|
||||||
}
|
}
|
||||||
|
uint64_t write_unix_time() const override {
|
||||||
|
assert(false);
|
||||||
|
return std::numeric_limits<uint64_t>::max();
|
||||||
|
}
|
||||||
Status status() const override { return status_; }
|
Status status() const override { return status_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "db/write_batch_internal.h"
|
#include "db/write_batch_internal.h"
|
||||||
#include "file/filename.h"
|
#include "file/filename.h"
|
||||||
#include "rocksdb/cache.h"
|
#include "rocksdb/cache.h"
|
||||||
|
#include "rocksdb/comparator.h"
|
||||||
#include "rocksdb/experimental.h"
|
#include "rocksdb/experimental.h"
|
||||||
#include "rocksdb/file_checksum.h"
|
#include "rocksdb/file_checksum.h"
|
||||||
#include "rocksdb/filter_policy.h"
|
#include "rocksdb/filter_policy.h"
|
||||||
|
@ -110,6 +111,7 @@ const std::string LDBCommand::ARG_DECODE_BLOB_INDEX = "decode_blob_index";
|
||||||
const std::string LDBCommand::ARG_DUMP_UNCOMPRESSED_BLOBS =
|
const std::string LDBCommand::ARG_DUMP_UNCOMPRESSED_BLOBS =
|
||||||
"dump_uncompressed_blobs";
|
"dump_uncompressed_blobs";
|
||||||
const std::string LDBCommand::ARG_READ_TIMESTAMP = "read_timestamp";
|
const std::string LDBCommand::ARG_READ_TIMESTAMP = "read_timestamp";
|
||||||
|
const std::string LDBCommand::ARG_GET_WRITE_UNIX_TIME = "get_write_unix_time";
|
||||||
|
|
||||||
const char* LDBCommand::DELIM = " ==> ";
|
const char* LDBCommand::DELIM = " ==> ";
|
||||||
|
|
||||||
|
@ -3622,11 +3624,12 @@ void BatchPutCommand::OverrideBaseOptions() {
|
||||||
ScanCommand::ScanCommand(const std::vector<std::string>& /*params*/,
|
ScanCommand::ScanCommand(const std::vector<std::string>& /*params*/,
|
||||||
const std::map<std::string, std::string>& options,
|
const std::map<std::string, std::string>& options,
|
||||||
const std::vector<std::string>& flags)
|
const std::vector<std::string>& flags)
|
||||||
: LDBCommand(options, flags, true,
|
: LDBCommand(
|
||||||
BuildCmdLineOptions(
|
options, flags, true,
|
||||||
{ARG_TTL, ARG_NO_VALUE, ARG_HEX, ARG_KEY_HEX, ARG_TO,
|
BuildCmdLineOptions({ARG_TTL, ARG_NO_VALUE, ARG_HEX, ARG_KEY_HEX,
|
||||||
ARG_VALUE_HEX, ARG_FROM, ARG_TIMESTAMP, ARG_MAX_KEYS,
|
ARG_TO, ARG_VALUE_HEX, ARG_FROM, ARG_TIMESTAMP,
|
||||||
ARG_TTL_START, ARG_TTL_END, ARG_READ_TIMESTAMP})),
|
ARG_MAX_KEYS, ARG_TTL_START, ARG_TTL_END,
|
||||||
|
ARG_READ_TIMESTAMP, ARG_GET_WRITE_UNIX_TIME})),
|
||||||
start_key_specified_(false),
|
start_key_specified_(false),
|
||||||
end_key_specified_(false),
|
end_key_specified_(false),
|
||||||
max_keys_scanned_(-1),
|
max_keys_scanned_(-1),
|
||||||
|
@ -3670,6 +3673,7 @@ ScanCommand::ScanCommand(const std::vector<std::string>& /*params*/,
|
||||||
ARG_MAX_KEYS + " has a value out-of-range");
|
ARG_MAX_KEYS + " has a value out-of-range");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
get_write_unix_time_ = IsFlagPresent(flags_, ARG_GET_WRITE_UNIX_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScanCommand::Help(std::string& ret) {
|
void ScanCommand::Help(std::string& ret) {
|
||||||
|
@ -3683,6 +3687,7 @@ void ScanCommand::Help(std::string& ret) {
|
||||||
ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");
|
ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");
|
||||||
ret.append(" [--" + ARG_NO_VALUE + "]");
|
ret.append(" [--" + ARG_NO_VALUE + "]");
|
||||||
ret.append(" [--" + ARG_READ_TIMESTAMP + "=<uint64_ts>] ");
|
ret.append(" [--" + ARG_READ_TIMESTAMP + "=<uint64_ts>] ");
|
||||||
|
ret.append(" [--" + ARG_GET_WRITE_UNIX_TIME + "]");
|
||||||
ret.append("\n");
|
ret.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3765,6 +3770,22 @@ void ScanCommand::DoCommand() {
|
||||||
fprintf(stdout, "%s\n", str.c_str());
|
fprintf(stdout, "%s\n", str.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (get_write_unix_time_) {
|
||||||
|
std::string write_unix_time;
|
||||||
|
uint64_t write_time_int = std::numeric_limits<uint64_t>::max();
|
||||||
|
Status s =
|
||||||
|
it->GetProperty("rocksdb.iterator.write-time", &write_unix_time);
|
||||||
|
if (s.ok()) {
|
||||||
|
s = DecodeU64Ts(write_unix_time, &write_time_int);
|
||||||
|
}
|
||||||
|
if (!s.ok()) {
|
||||||
|
fprintf(stdout, " Failed to get write unix time: %s\n",
|
||||||
|
s.ToString().c_str());
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, " write unix time: %s\n",
|
||||||
|
std::to_string(write_time_int).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
num_keys_scanned++;
|
num_keys_scanned++;
|
||||||
if (max_keys_scanned_ >= 0 && num_keys_scanned >= max_keys_scanned_) {
|
if (max_keys_scanned_ >= 0 && num_keys_scanned >= max_keys_scanned_) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -511,6 +511,7 @@ class ScanCommand : public LDBCommand {
|
||||||
bool end_key_specified_;
|
bool end_key_specified_;
|
||||||
int max_keys_scanned_;
|
int max_keys_scanned_;
|
||||||
bool no_value_;
|
bool no_value_;
|
||||||
|
bool get_write_unix_time_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeleteCommand : public LDBCommand {
|
class DeleteCommand : public LDBCommand {
|
||||||
|
|
Loading…
Reference in New Issue