mirror of https://github.com/facebook/rocksdb.git
Fix the handling of PrepareValue failures due to fault injection (#13131)
Summary: Pull Request resolved: https://github.com/facebook/rocksdb/pull/13131 The earlier stress test code did not consider that `PrepareValue()` could fail because of read fault injection, leading to false positives. The patch shuffles the `PrepareValue()` calls around a bit in `TestIterate` / `TestIterateAgainstExpected` in order to prevent this by leveraging the existing code paths that intercept injected faults. Reviewed By: cbi42 Differential Revision: D65731543 fbshipit-source-id: b21c6584ebaa2ff41cd4569098680b91ff7991d1
This commit is contained in:
parent
aa889eb5ed
commit
1f0ccd9a15
|
@ -1748,6 +1748,15 @@ Status StressTest::TestIterateImpl(ThreadState* thread,
|
||||||
op_logs += "S " + key.ToString(true) + " ";
|
op_logs += "S " + key.ToString(true) + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iter->Valid() && ro.allow_unprepared_value) {
|
||||||
|
op_logs += "*";
|
||||||
|
|
||||||
|
if (!iter->PrepareValue()) {
|
||||||
|
assert(!iter->Valid());
|
||||||
|
assert(!iter->status().ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!iter->status().ok() && IsErrorInjectedAndRetryable(iter->status())) {
|
if (!iter->status().ok() && IsErrorInjectedAndRetryable(iter->status())) {
|
||||||
return iter->status();
|
return iter->status();
|
||||||
} else if (!cmp_iter->status().ok() &&
|
} else if (!cmp_iter->status().ok() &&
|
||||||
|
@ -1779,6 +1788,15 @@ Status StressTest::TestIterateImpl(ThreadState* thread,
|
||||||
|
|
||||||
last_op = kLastOpNextOrPrev;
|
last_op = kLastOpNextOrPrev;
|
||||||
|
|
||||||
|
if (iter->Valid() && ro.allow_unprepared_value) {
|
||||||
|
op_logs += "*";
|
||||||
|
|
||||||
|
if (!iter->PrepareValue()) {
|
||||||
|
assert(!iter->Valid());
|
||||||
|
assert(!iter->status().ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!iter->status().ok() && IsErrorInjectedAndRetryable(iter->status())) {
|
if (!iter->status().ok() && IsErrorInjectedAndRetryable(iter->status())) {
|
||||||
return iter->status();
|
return iter->status();
|
||||||
} else if (!cmp_iter->status().ok() &&
|
} else if (!cmp_iter->status().ok() &&
|
||||||
|
@ -1999,30 +2017,11 @@ void StressTest::VerifyIterator(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!*diverged && iter->Valid()) {
|
|
||||||
if (ro.allow_unprepared_value) {
|
|
||||||
// Save key in case PrepareValue fails and invalidates the iterator
|
|
||||||
const std::string prepare_value_key =
|
|
||||||
iter->key().ToString(/* hex */ true);
|
|
||||||
|
|
||||||
if (!iter->PrepareValue()) {
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"Iterator failed to prepare value for key %s %s under specified "
|
|
||||||
"iterator ReadOptions: %s (Empty string or missing field indicates "
|
|
||||||
"default option or value is used): %s\n",
|
|
||||||
prepare_value_key.c_str(), op_logs.c_str(),
|
|
||||||
read_opt_oss.str().c_str(), iter->status().ToString().c_str());
|
|
||||||
*diverged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!*diverged && iter->Valid()) {
|
if (!*diverged && iter->Valid()) {
|
||||||
if (!verify_func(iter)) {
|
if (!verify_func(iter)) {
|
||||||
*diverged = true;
|
*diverged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (*diverged) {
|
if (*diverged) {
|
||||||
fprintf(stderr, "VerifyIterator failed. Control CF %s\n",
|
fprintf(stderr, "VerifyIterator failed. Control CF %s\n",
|
||||||
|
|
|
@ -2300,27 +2300,6 @@ class NonBatchedOpsStressTest : public StressTest {
|
||||||
assert(iter);
|
assert(iter);
|
||||||
assert(iter->Valid());
|
assert(iter->Valid());
|
||||||
|
|
||||||
if (ro.allow_unprepared_value) {
|
|
||||||
// Save key in case PrepareValue fails and invalidates the iterator
|
|
||||||
const std::string prepare_value_key =
|
|
||||||
iter->key().ToString(/* hex */ true);
|
|
||||||
|
|
||||||
if (!iter->PrepareValue()) {
|
|
||||||
shared->SetVerificationFailure();
|
|
||||||
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"Verification failed for key %s: failed to prepare value: %s\n",
|
|
||||||
prepare_value_key.c_str(), iter->status().ToString().c_str());
|
|
||||||
fprintf(stderr, "Column family: %s, op_logs: %s\n",
|
|
||||||
cfh->GetName().c_str(), op_logs.c_str());
|
|
||||||
|
|
||||||
thread->stats.AddErrors(1);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!VerifyWideColumns(iter->value(), iter->columns())) {
|
if (!VerifyWideColumns(iter->value(), iter->columns())) {
|
||||||
shared->SetVerificationFailure();
|
shared->SetVerificationFailure();
|
||||||
|
|
||||||
|
@ -2389,6 +2368,16 @@ class NonBatchedOpsStressTest : public StressTest {
|
||||||
uint64_t curr = 0;
|
uint64_t curr = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
assert(last_key < ub);
|
assert(last_key < ub);
|
||||||
|
|
||||||
|
if (iter->Valid() && ro.allow_unprepared_value) {
|
||||||
|
op_logs += "*";
|
||||||
|
|
||||||
|
if (!iter->PrepareValue()) {
|
||||||
|
assert(!iter->Valid());
|
||||||
|
assert(!iter->status().ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!iter->Valid()) {
|
if (!iter->Valid()) {
|
||||||
if (!iter->status().ok()) {
|
if (!iter->status().ok()) {
|
||||||
if (IsErrorInjectedAndRetryable(iter->status())) {
|
if (IsErrorInjectedAndRetryable(iter->status())) {
|
||||||
|
@ -2451,6 +2440,16 @@ class NonBatchedOpsStressTest : public StressTest {
|
||||||
last_key = ub;
|
last_key = ub;
|
||||||
while (true) {
|
while (true) {
|
||||||
assert(lb < last_key);
|
assert(lb < last_key);
|
||||||
|
|
||||||
|
if (iter->Valid() && ro.allow_unprepared_value) {
|
||||||
|
op_logs += "*";
|
||||||
|
|
||||||
|
if (!iter->PrepareValue()) {
|
||||||
|
assert(!iter->Valid());
|
||||||
|
assert(!iter->status().ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!iter->Valid()) {
|
if (!iter->Valid()) {
|
||||||
if (!iter->status().ok()) {
|
if (!iter->status().ok()) {
|
||||||
if (IsErrorInjectedAndRetryable(iter->status())) {
|
if (IsErrorInjectedAndRetryable(iter->status())) {
|
||||||
|
@ -2589,6 +2588,16 @@ class NonBatchedOpsStressTest : public StressTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int64_t i = 0; i < num_iter && iter->Valid(); ++i) {
|
for (int64_t i = 0; i < num_iter && iter->Valid(); ++i) {
|
||||||
|
if (ro.allow_unprepared_value) {
|
||||||
|
op_logs += "*";
|
||||||
|
|
||||||
|
if (!iter->PrepareValue()) {
|
||||||
|
assert(!iter->Valid());
|
||||||
|
assert(!iter->status().ok());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!check_columns()) {
|
if (!check_columns()) {
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue