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:
commit
9d3b1cc4e4
|
@ -338,13 +338,10 @@ Future<Standalone<RangeResultRef>> ConflictingKeysImpl::getRange(ReadYourWritesT
|
||||||
if (beginIter->begin() != kr.begin) ++beginIter;
|
if (beginIter->begin() != kr.begin) ++beginIter;
|
||||||
auto endIter = krMapPtr->rangeContaining(kr.end);
|
auto endIter = krMapPtr->rangeContaining(kr.end);
|
||||||
for (auto it = beginIter; it != endIter; ++it) {
|
for (auto it = beginIter; it != endIter; ++it) {
|
||||||
// it->begin() is stored in the CoalescedKeyRangeMap in TransactionInfo
|
result.push_back_deep(result.arena(), KeyValueRef(it->begin(), it->value()));
|
||||||
// it->value() is always constants in SystemData.cpp
|
|
||||||
// Thus, push_back() can be used
|
|
||||||
result.push_back(result.arena(), KeyValueRef(it->begin(), it->value()));
|
|
||||||
}
|
}
|
||||||
if (endIter->begin() != kr.end)
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ struct ReportConflictingKeysWorkload : TestWorkload {
|
||||||
} while (deterministicRandom()->random01() < addWriteConflictRangeProb);
|
} 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,
|
// 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/,
|
// which means you will get an empty result form getRange(\xff\xff/transaction/conflicting_keys/,
|
||||||
// \xff\xff/transaction/conflicting_keys0)
|
// \xff\xff/transaction/conflicting_keys0)
|
||||||
|
@ -134,42 +134,42 @@ struct ReportConflictingKeysWorkload : TestWorkload {
|
||||||
|
|
||||||
ACTOR Future<Void> conflictingClient(Database cx, ReportConflictingKeysWorkload* self) {
|
ACTOR Future<Void> conflictingClient(Database cx, ReportConflictingKeysWorkload* self) {
|
||||||
|
|
||||||
state ReadYourWritesTransaction tr1(cx);
|
state Reference<ReadYourWritesTransaction> tr1(new ReadYourWritesTransaction(cx));
|
||||||
state ReadYourWritesTransaction tr2(cx);
|
state Reference<ReadYourWritesTransaction> tr2(new ReadYourWritesTransaction(cx));
|
||||||
state std::vector<KeyRange> readConflictRanges;
|
state std::vector<KeyRange> readConflictRanges;
|
||||||
state std::vector<KeyRange> writeConflictRanges;
|
state std::vector<KeyRange> writeConflictRanges;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
try {
|
try {
|
||||||
// set the flag for empty key range testing
|
// 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
|
// 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
|
// If READ_YOUR_WRITES_DISABLE set, it behaves like native transaction object
|
||||||
// where overlapped conflict ranges are not merged.
|
// where overlapped conflict ranges are not merged.
|
||||||
if (deterministicRandom()->coinflip()) tr1.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);
|
if (deterministicRandom()->coinflip()) tr2->setOption(FDBTransactionOptions::READ_YOUR_WRITES_DISABLE);
|
||||||
// We have the two tx with same grv, then commit the first
|
// 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
|
// 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
|
// Otherwise, there is no conflicts between tr1's writeConflictRange and tr2's readConflictRange
|
||||||
Version readVersion = wait(tr1.getReadVersion());
|
Version readVersion = wait(tr1->getReadVersion());
|
||||||
tr2.setVersion(readVersion);
|
tr2->setVersion(readVersion);
|
||||||
self->addRandomReadConflictRange(&tr1, nullptr);
|
self->addRandomReadConflictRange(tr1.getPtr(), nullptr);
|
||||||
self->addRandomWriteConflictRange(&tr1, &writeConflictRanges);
|
self->addRandomWriteConflictRange(tr1.getPtr(), &writeConflictRanges);
|
||||||
++self->commits;
|
++self->commits;
|
||||||
wait(tr1.commit());
|
wait(tr1->commit());
|
||||||
++self->xacts;
|
++self->xacts;
|
||||||
// tr1 should never have conflicting keys, test again after the commit
|
// tr1 should never have conflicting keys, test again after the commit
|
||||||
self->emptyConflictingKeysTest(Reference<ReadYourWritesTransaction>::addRef(&tr1));
|
self->emptyConflictingKeysTest(tr1);
|
||||||
|
|
||||||
state bool foundConflict = false;
|
state bool foundConflict = false;
|
||||||
try {
|
try {
|
||||||
self->addRandomReadConflictRange(&tr2, &readConflictRanges);
|
self->addRandomReadConflictRange(tr2.getPtr(), &readConflictRanges);
|
||||||
self->addRandomWriteConflictRange(&tr2, nullptr);
|
self->addRandomWriteConflictRange(tr2.getPtr(), nullptr);
|
||||||
++self->commits;
|
++self->commits;
|
||||||
wait(tr2.commit());
|
wait(tr2->commit());
|
||||||
++self->xacts;
|
++self->xacts;
|
||||||
} catch (Error& e) {
|
} catch (Error& e) {
|
||||||
if (e.code() != error_code_not_committed) throw 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
|
// The getRange here using the special key prefix "\xff\xff/transaction/conflicting_keys/" happens
|
||||||
// locally Thus, the error handling is not needed here
|
// locally Thus, the error handling is not needed here
|
||||||
Future<Standalone<RangeResultRef>> conflictingKeyRangesFuture =
|
Future<Standalone<RangeResultRef>> conflictingKeyRangesFuture =
|
||||||
tr2.getRange(ckr, CLIENT_KNOBS->TOO_MANY);
|
tr2->getRange(ckr, CLIENT_KNOBS->TOO_MANY);
|
||||||
ASSERT(conflictingKeyRangesFuture.isReady());
|
ASSERT(conflictingKeyRangesFuture.isReady());
|
||||||
|
|
||||||
|
tr2 = Reference<ReadYourWritesTransaction>(new ReadYourWritesTransaction(cx));
|
||||||
|
|
||||||
const Standalone<RangeResultRef> conflictingKeyRanges = conflictingKeyRangesFuture.get();
|
const Standalone<RangeResultRef> conflictingKeyRanges = conflictingKeyRangesFuture.get();
|
||||||
ASSERT(conflictingKeyRanges.size() &&
|
ASSERT(conflictingKeyRanges.size() &&
|
||||||
(conflictingKeyRanges.size() <= readConflictRanges.size() * 2));
|
(conflictingKeyRanges.size() <= readConflictRanges.size() * 2));
|
||||||
|
@ -275,13 +278,13 @@ struct ReportConflictingKeysWorkload : TestWorkload {
|
||||||
}
|
}
|
||||||
} catch (Error& e) {
|
} catch (Error& e) {
|
||||||
state Error e2 = e;
|
state Error e2 = e;
|
||||||
wait(tr1.onError(e2));
|
wait(tr1->onError(e2));
|
||||||
wait(tr2.onError(e2));
|
wait(tr2->onError(e2));
|
||||||
}
|
}
|
||||||
readConflictRanges.clear();
|
readConflictRanges.clear();
|
||||||
writeConflictRanges.clear();
|
writeConflictRanges.clear();
|
||||||
tr1.reset();
|
tr1->reset();
|
||||||
tr2.reset();
|
tr2->reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue