Merge pull request #3562 from sfc-gh-anoyes/anoyes/memory-error

Fix memory error in report conflicting keys special keys
This commit is contained in:
Meng Xu 2020-07-24 21:11:42 -07:00 committed by GitHub
commit 9d3b1cc4e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 27 deletions

View File

@ -338,13 +338,10 @@ Future<Standalone<RangeResultRef>> ConflictingKeysImpl::getRange(ReadYourWritesT
if (beginIter->begin() != kr.begin) ++beginIter;
auto endIter = krMapPtr->rangeContaining(kr.end);
for (auto it = beginIter; it != endIter; ++it) {
// it->begin() is stored in the CoalescedKeyRangeMap in TransactionInfo
// it->value() is always constants in SystemData.cpp
// Thus, push_back() can be used
result.push_back(result.arena(), KeyValueRef(it->begin(), it->value()));
result.push_back_deep(result.arena(), KeyValueRef(it->begin(), it->value()));
}
if (endIter->begin() != kr.end)
result.push_back(result.arena(), KeyValueRef(endIter->begin(), endIter->value()));
result.push_back_deep(result.arena(), KeyValueRef(endIter->begin(), endIter->value()));
}
return result;
}

View File

@ -123,7 +123,7 @@ struct ReportConflictingKeysWorkload : TestWorkload {
} while (deterministicRandom()->random01() < addWriteConflictRangeProb);
}
void emptyConflictingKeysTest(Reference<ReadYourWritesTransaction> ryw) {
void emptyConflictingKeysTest(const Reference<ReadYourWritesTransaction>& ryw) {
// This test is called when you want to make sure there is no conflictingKeys,
// which means you will get an empty result form getRange(\xff\xff/transaction/conflicting_keys/,
// \xff\xff/transaction/conflicting_keys0)
@ -134,42 +134,42 @@ struct ReportConflictingKeysWorkload : TestWorkload {
ACTOR Future<Void> conflictingClient(Database cx, ReportConflictingKeysWorkload* self) {
state ReadYourWritesTransaction tr1(cx);
state ReadYourWritesTransaction tr2(cx);
state Reference<ReadYourWritesTransaction> tr1(new ReadYourWritesTransaction(cx));
state Reference<ReadYourWritesTransaction> tr2(new ReadYourWritesTransaction(cx));
state std::vector<KeyRange> readConflictRanges;
state std::vector<KeyRange> writeConflictRanges;
loop {
try {
// set the flag for empty key range testing
tr1.setOption(FDBTransactionOptions::REPORT_CONFLICTING_KEYS);
tr1->setOption(FDBTransactionOptions::REPORT_CONFLICTING_KEYS);
// tr1 should never have conflicting keys, the result should always be empty
self->emptyConflictingKeysTest(Reference<ReadYourWritesTransaction>::addRef(&tr1));
self->emptyConflictingKeysTest(tr1);
tr2.setOption(FDBTransactionOptions::REPORT_CONFLICTING_KEYS);
tr2->setOption(FDBTransactionOptions::REPORT_CONFLICTING_KEYS);
// If READ_YOUR_WRITES_DISABLE set, it behaves like native transaction object
// where overlapped conflict ranges are not merged.
if (deterministicRandom()->coinflip()) tr1.setOption(FDBTransactionOptions::READ_YOUR_WRITES_DISABLE);
if (deterministicRandom()->coinflip()) tr2.setOption(FDBTransactionOptions::READ_YOUR_WRITES_DISABLE);
if (deterministicRandom()->coinflip()) tr1->setOption(FDBTransactionOptions::READ_YOUR_WRITES_DISABLE);
if (deterministicRandom()->coinflip()) tr2->setOption(FDBTransactionOptions::READ_YOUR_WRITES_DISABLE);
// We have the two tx with same grv, then commit the first
// If the second one is not able to commit due to conflicts, verify the returned conflicting keys
// Otherwise, there is no conflicts between tr1's writeConflictRange and tr2's readConflictRange
Version readVersion = wait(tr1.getReadVersion());
tr2.setVersion(readVersion);
self->addRandomReadConflictRange(&tr1, nullptr);
self->addRandomWriteConflictRange(&tr1, &writeConflictRanges);
Version readVersion = wait(tr1->getReadVersion());
tr2->setVersion(readVersion);
self->addRandomReadConflictRange(tr1.getPtr(), nullptr);
self->addRandomWriteConflictRange(tr1.getPtr(), &writeConflictRanges);
++self->commits;
wait(tr1.commit());
wait(tr1->commit());
++self->xacts;
// tr1 should never have conflicting keys, test again after the commit
self->emptyConflictingKeysTest(Reference<ReadYourWritesTransaction>::addRef(&tr1));
self->emptyConflictingKeysTest(tr1);
state bool foundConflict = false;
try {
self->addRandomReadConflictRange(&tr2, &readConflictRanges);
self->addRandomWriteConflictRange(&tr2, nullptr);
self->addRandomReadConflictRange(tr2.getPtr(), &readConflictRanges);
self->addRandomWriteConflictRange(tr2.getPtr(), nullptr);
++self->commits;
wait(tr2.commit());
wait(tr2->commit());
++self->xacts;
} catch (Error& e) {
if (e.code() != error_code_not_committed) throw e;
@ -188,8 +188,11 @@ struct ReportConflictingKeysWorkload : TestWorkload {
// The getRange here using the special key prefix "\xff\xff/transaction/conflicting_keys/" happens
// locally Thus, the error handling is not needed here
Future<Standalone<RangeResultRef>> conflictingKeyRangesFuture =
tr2.getRange(ckr, CLIENT_KNOBS->TOO_MANY);
tr2->getRange(ckr, CLIENT_KNOBS->TOO_MANY);
ASSERT(conflictingKeyRangesFuture.isReady());
tr2 = Reference<ReadYourWritesTransaction>(new ReadYourWritesTransaction(cx));
const Standalone<RangeResultRef> conflictingKeyRanges = conflictingKeyRangesFuture.get();
ASSERT(conflictingKeyRanges.size() &&
(conflictingKeyRanges.size() <= readConflictRanges.size() * 2));
@ -275,13 +278,13 @@ struct ReportConflictingKeysWorkload : TestWorkload {
}
} catch (Error& e) {
state Error e2 = e;
wait(tr1.onError(e2));
wait(tr2.onError(e2));
wait(tr1->onError(e2));
wait(tr2->onError(e2));
}
readConflictRanges.clear();
writeConflictRanges.clear();
tr1.reset();
tr2.reset();
tr1->reset();
tr2->reset();
}
}
};