2017-05-26 04:48:44 +08:00
|
|
|
/*
|
|
|
|
* ApiCorrectness.actor.cpp
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
|
|
|
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fdbserver/QuietDatabase.h"
|
|
|
|
|
Clean up and rework the debugMutation API.
As a relatively unknown debugging tool for simulation tests, one could
have simulation print when a particular key is handled in various stages
of the commit process. This functionality was enabled by changing a 0
to a 1 in an #if, and changing a constant to the key in question.
As a proxy and storage server handle mutations, they call debugMutation
or debugKeyRange, which then checks against the mutation against the key
in question, and logs if they match. A mixture of printfs and
TraceEvents would then be emitted, and for this to actually be usable,
one also needs to comment out some particularly spammy debugKeyRange()
calls.
This PR reworks the API of debugMutation/debugKeyRange, pulls it out
into its own file, and trims what is logged by default into something
useful and understandable:
* debugMutation() now returns a TraceEvent, that one can add more details to before it is logged.
* Data distribution and storage server cleanup operations are no longer logged by default
2020-03-27 16:35:26 +08:00
|
|
|
#include "fdbserver/MutationTracking.h"
|
2019-02-18 11:18:30 +08:00
|
|
|
#include "fdbserver/workloads/workloads.actor.h"
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "fdbserver/workloads/ApiWorkload.h"
|
|
|
|
#include "fdbserver/workloads/MemoryKeyValueStore.h"
|
2021-03-11 02:06:03 +08:00
|
|
|
#include "flow/actorcompiler.h" // This must be the last #include.
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// An enum of API operation types used in the random test
|
2020-07-10 06:02:43 +08:00
|
|
|
enum OperationType { SET, GET, GET_RANGE, GET_RANGE_SELECTOR, GET_KEY, CLEAR, CLEAR_RANGE, UNINITIALIZED };
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// A workload that executes the NativeAPIs functions and verifies that their outcomes are correct
|
2017-05-26 04:48:44 +08:00
|
|
|
struct ApiCorrectnessWorkload : ApiWorkload {
|
|
|
|
|
|
|
|
private:
|
2021-03-11 02:06:03 +08:00
|
|
|
// Enable to track the activity on a particular key
|
2017-05-26 04:48:44 +08:00
|
|
|
#if CENABLED(0, NOT_IN_CLEAN)
|
|
|
|
#define targetKey LiteralStringRef( ??? )
|
|
|
|
|
|
|
|
void debugKey(KeyRef key, std::string context) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (key == targetKey)
|
2017-05-26 04:48:44 +08:00
|
|
|
TraceEvent("ApiCorrectnessDebugKey").detail("Context", context).detail("Key", printable(key));
|
|
|
|
}
|
|
|
|
|
|
|
|
void debugKey(KeyRangeRef keyRange, std::string context) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (keyRange.contains(targetKey))
|
|
|
|
TraceEvent("ApiCorrectnessDebugKey")
|
|
|
|
.detail("Context", context)
|
|
|
|
.detail("Key", printable(targetKey))
|
|
|
|
.detail("RangeBegin", printable(keyRange.begin))
|
|
|
|
.detail("RangeEnd", printable(keyRange.end));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2021-03-11 02:06:03 +08:00
|
|
|
void debugKey(KeyRef key, std::string context) {}
|
|
|
|
void debugKey(KeyRangeRef keyRange, std::string context) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
public:
|
2021-03-11 02:06:03 +08:00
|
|
|
// The number of gets that should be performed
|
2017-05-26 04:48:44 +08:00
|
|
|
int numGets;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The number of getRanges that should be performed
|
2017-05-26 04:48:44 +08:00
|
|
|
int numGetRanges;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The number of getRanges using key selectors that should be performed
|
2017-05-26 04:48:44 +08:00
|
|
|
int numGetRangeSelectors;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The number of getKeys that should be performed
|
2017-05-26 04:48:44 +08:00
|
|
|
int numGetKeys;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The number of clears that should be performed
|
2017-05-26 04:48:44 +08:00
|
|
|
int numClears;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The number of clears using key ranges that should be performed
|
2017-05-26 04:48:44 +08:00
|
|
|
int numClearRanges;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The smallest legal size of the database after a clear. A smaller size will trigger a database reset
|
2017-05-26 04:48:44 +08:00
|
|
|
int minSizeAfterClear;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The maximum number of keys that can be in this client's key space when performing the random test
|
2017-05-26 04:48:44 +08:00
|
|
|
int maxRandomTestKeys;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The amount of time to run the random tests
|
2017-05-26 04:48:44 +08:00
|
|
|
double randomTestDuration;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The maximum number of keys operated on in a transaction; used to prevent transaction_too_old errors
|
2017-05-26 04:48:44 +08:00
|
|
|
int maxKeysPerTransaction;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The number of API calls made by the random test
|
2017-05-26 04:48:44 +08:00
|
|
|
PerfIntCounter numRandomOperations;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// The API being used by this client
|
2017-05-26 04:48:44 +08:00
|
|
|
TransactionType transactionType;
|
|
|
|
|
2020-08-27 01:21:17 +08:00
|
|
|
// Maximum time to reset DB to the original state
|
|
|
|
double resetDBTimeout;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ApiCorrectnessWorkload(WorkloadContext const& wcx)
|
|
|
|
: ApiWorkload(wcx), numRandomOperations("Num Random Operations") {
|
2017-05-26 04:48:44 +08:00
|
|
|
numGets = getOption(options, LiteralStringRef("numGets"), 1000);
|
|
|
|
numGetRanges = getOption(options, LiteralStringRef("numGetRanges"), 100);
|
|
|
|
numGetRangeSelectors = getOption(options, LiteralStringRef("numGetRangeSelectors"), 100);
|
|
|
|
numGetKeys = getOption(options, LiteralStringRef("numGetKeys"), 100);
|
|
|
|
numClears = getOption(options, LiteralStringRef("numClears"), 100);
|
|
|
|
numClearRanges = getOption(options, LiteralStringRef("numClearRanges"), 100);
|
|
|
|
minSizeAfterClear = getOption(options, LiteralStringRef("minSizeAfterClear"), (int)(0.1 * numKeys));
|
|
|
|
|
|
|
|
maxRandomTestKeys = getOption(options, LiteralStringRef("maxRandomTestKeys"), numKeys);
|
|
|
|
randomTestDuration = getOption(options, LiteralStringRef("randomTestDuration"), 60.0);
|
|
|
|
|
|
|
|
int maxTransactionBytes = getOption(options, LiteralStringRef("maxTransactionBytes"), 500000);
|
|
|
|
maxKeysPerTransaction = std::max(1, maxTransactionBytes / (maxValueLength + maxLongKeyLength));
|
|
|
|
|
2020-08-27 01:21:17 +08:00
|
|
|
resetDBTimeout = getOption(options, LiteralStringRef("resetDBTimeout"), 1800.0);
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (maxTransactionBytes > 500000) {
|
|
|
|
TraceEvent("RemapEventSeverity")
|
|
|
|
.detail("TargetEvent", "LargePacketSent")
|
|
|
|
.detail("OriginalSeverity", SevWarnAlways)
|
|
|
|
.detail("NewSeverity", SevInfo);
|
|
|
|
TraceEvent("RemapEventSeverity")
|
|
|
|
.detail("TargetEvent", "LargePacketReceived")
|
|
|
|
.detail("OriginalSeverity", SevWarnAlways)
|
|
|
|
.detail("NewSeverity", SevInfo);
|
|
|
|
TraceEvent("RemapEventSeverity")
|
|
|
|
.detail("TargetEvent", "LargeTransaction")
|
|
|
|
.detail("OriginalSeverity", SevWarnAlways)
|
|
|
|
.detail("NewSeverity", SevInfo);
|
|
|
|
TraceEvent("RemapEventSeverity")
|
|
|
|
.detail("TargetEvent", "DiskQueueMemoryWarning")
|
|
|
|
.detail("OriginalSeverity", SevWarnAlways)
|
|
|
|
.detail("NewSeverity", SevInfo);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-26 09:55:43 +08:00
|
|
|
~ApiCorrectnessWorkload() override {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-10-05 13:29:07 +08:00
|
|
|
std::string description() const override { return "ApiCorrectness"; }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-09-17 08:42:34 +08:00
|
|
|
void getMetrics(std::vector<PerfMetric>& m) override {
|
2021-08-31 04:32:58 +08:00
|
|
|
m.emplace_back("Number of Random Operations Performed", numRandomOperations.getValue(), Averaged::False);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR Future<Void> performSetup(Database cx, ApiCorrectnessWorkload* self) {
|
|
|
|
// Choose a random transaction type (NativeAPI, ReadYourWrites, ThreadSafe, MultiVersion)
|
2017-05-26 04:48:44 +08:00
|
|
|
std::vector<TransactionType> types;
|
|
|
|
types.push_back(NATIVE);
|
|
|
|
types.push_back(READ_YOUR_WRITES);
|
|
|
|
types.push_back(THREAD_SAFE);
|
2017-09-01 07:23:55 +08:00
|
|
|
types.push_back(MULTI_VERSION);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(self->chooseTransactionFactory(cx, types));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-01-26 09:55:43 +08:00
|
|
|
Future<Void> performSetup(Database const& cx) override { return performSetup(cx, this); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR Future<Void> performTest(Database cx, Standalone<VectorRef<KeyValueRef>> data, ApiCorrectnessWorkload* self) {
|
|
|
|
// Run the scripted test for a maximum of 10 minutes
|
2018-08-11 08:25:43 +08:00
|
|
|
wait(timeout(self->runScriptedTest(self, data), 600, Void()));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!self->hasFailed()) {
|
2020-08-27 01:21:17 +08:00
|
|
|
// Return database to original state (for a maximum of resetDBTimeout seconds)
|
2017-05-26 04:48:44 +08:00
|
|
|
try {
|
2020-08-27 01:21:17 +08:00
|
|
|
wait(timeoutError(::success(self->runSet(data, self)), self->resetDBTimeout));
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
|
|
|
if (e.code() == error_code_timed_out) {
|
|
|
|
if (!self->hasFailed())
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("Timeout during database reset");
|
|
|
|
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Run the random test for the user-specified duration
|
2018-08-11 08:25:43 +08:00
|
|
|
wait(timeout(self->runRandomTest(self, data), self->randomTestDuration, Void()));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-01-26 09:55:43 +08:00
|
|
|
Future<Void> performTest(Database const& cx, Standalone<VectorRef<KeyValueRef>> const& data) override {
|
2017-05-26 04:48:44 +08:00
|
|
|
return performTest(cx, data, this);
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Run a scripted set of API operations
|
|
|
|
ACTOR Future<Void> runScriptedTest(ApiCorrectnessWorkload* self, VectorRef<KeyValueRef> data) {
|
|
|
|
// Test the set function
|
2017-05-26 04:48:44 +08:00
|
|
|
bool setResult = wait(self->runSet(data, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!setResult)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the get function
|
2019-04-18 07:04:10 +08:00
|
|
|
wait(::success(self->runGet(data, self->numGets, self)));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the getRange function
|
2017-05-26 04:48:44 +08:00
|
|
|
state int i;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (i = 0; i < self->numGetRanges; i++)
|
|
|
|
wait(::success(self->runGetRange(data, self)));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the getRange function using key selectors
|
|
|
|
for (i = 0; i < self->numGetRangeSelectors; i++)
|
|
|
|
wait(::success(self->runGetRangeSelector(data, self)));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the getKey function
|
2019-04-18 07:04:10 +08:00
|
|
|
wait(::success(self->runGetKey(data, self->numGetKeys, self)));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the clear function
|
2017-05-26 04:48:44 +08:00
|
|
|
bool clearResult = wait(self->runClear(data, self->numClears, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!clearResult)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the clear function using keyRanges
|
|
|
|
for (i = 0; i < self->numClearRanges; i++) {
|
|
|
|
// Alternate restoring the database to its original state and clearing a single range
|
|
|
|
if (self->store.size() < self->minSizeAfterClear) {
|
2017-05-26 04:48:44 +08:00
|
|
|
bool resetResult = wait(self->runSet(data, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!resetResult)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool clearRangeResults = wait(self->runClearRange(data, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!clearRangeResults)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Generate and execute a sequence of random operations
|
|
|
|
ACTOR Future<Void> runRandomTest(ApiCorrectnessWorkload* self, Standalone<VectorRef<KeyValueRef>> data) {
|
2017-05-26 04:48:44 +08:00
|
|
|
loop {
|
|
|
|
double setProbability = 1 - ((double)self->store.size()) / self->maxRandomTestKeys;
|
2021-03-11 02:06:03 +08:00
|
|
|
int pdfArray[] = { 0,
|
|
|
|
(int)(100 * setProbability),
|
|
|
|
100,
|
|
|
|
50,
|
|
|
|
50,
|
|
|
|
20,
|
|
|
|
(int)(100 * (1 - setProbability)),
|
|
|
|
(int)(10 * (1 - setProbability)) };
|
2021-09-17 08:42:34 +08:00
|
|
|
std::vector<int> pdf = std::vector<int>(pdfArray, pdfArray + 8);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-07-10 06:02:43 +08:00
|
|
|
OperationType operation = UNINITIALIZED;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Choose a random operation type (SET, GET, GET_RANGE, GET_RANGE_SELECTOR, GET_KEY, CLEAR, CLEAR_RANGE).
|
2017-05-26 04:48:44 +08:00
|
|
|
int totalDensity = 0;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < pdf.size(); i++)
|
2017-05-26 04:48:44 +08:00
|
|
|
totalDensity += pdf[i];
|
|
|
|
|
|
|
|
int cumulativeDensity = 0;
|
2019-05-11 05:01:52 +08:00
|
|
|
int random = deterministicRandom()->randomInt(0, totalDensity);
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < pdf.size() - 1; i++) {
|
|
|
|
if (cumulativeDensity + pdf[i] <= random && random < cumulativeDensity + pdf[i] + pdf[i + 1]) {
|
2017-05-26 04:48:44 +08:00
|
|
|
operation = (OperationType)i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cumulativeDensity += pdf[i];
|
|
|
|
}
|
2020-07-10 06:02:43 +08:00
|
|
|
ASSERT(operation != UNINITIALIZED);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
++self->numRandomOperations;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the set operation
|
|
|
|
if (operation == SET) {
|
2019-05-11 05:01:52 +08:00
|
|
|
bool useShortKeys = deterministicRandom()->randomInt(0, 2) == 1;
|
2017-05-26 04:48:44 +08:00
|
|
|
int minKeyLength = useShortKeys ? self->minShortKeyLength : self->minLongKeyLength;
|
|
|
|
int maxKeyLength = useShortKeys ? self->maxShortKeyLength : self->maxLongKeyLength;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
state Standalone<VectorRef<KeyValueRef>> newData =
|
|
|
|
self->generateData(std::min((uint64_t)100, self->maxRandomTestKeys - self->store.size()),
|
|
|
|
minKeyLength,
|
|
|
|
maxKeyLength,
|
|
|
|
self->minValueLength,
|
|
|
|
self->maxValueLength,
|
|
|
|
self->clientPrefix,
|
|
|
|
true);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
data.append_deep(data.arena(), newData.begin(), newData.size());
|
|
|
|
|
|
|
|
bool result = wait(self->runSet(newData, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the get operation
|
|
|
|
else if (operation == GET) {
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->runGet(data, 10, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the getRange operation
|
|
|
|
else if (operation == GET_RANGE) {
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->runGetRange(data, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the getRange operation with key selectors
|
|
|
|
else if (operation == GET_RANGE_SELECTOR) {
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->runGetRangeSelector(data, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the getKey operation
|
|
|
|
else if (operation == GET_KEY) {
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->runGetKey(data, 10, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the clear operation
|
|
|
|
else if (operation == CLEAR) {
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->runClear(data, 10, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Test the clear operation (using key range)
|
|
|
|
else if (operation == CLEAR_RANGE) {
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->runClearRange(data, self));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Adds the key-value pairs in data to the database and memory store
|
|
|
|
ACTOR Future<bool> runSet(VectorRef<KeyValueRef> data, ApiCorrectnessWorkload* self) {
|
2017-05-26 04:48:44 +08:00
|
|
|
state int currentIndex = 0;
|
2021-03-11 02:06:03 +08:00
|
|
|
while (currentIndex < data.size()) {
|
2017-05-26 04:48:44 +08:00
|
|
|
state Reference<TransactionWrapper> transaction = self->createTransaction();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Set keys in the database
|
2017-05-26 04:48:44 +08:00
|
|
|
loop {
|
|
|
|
try {
|
2021-03-11 02:06:03 +08:00
|
|
|
// For now, make this transaction self-conflicting to avoid commit errors
|
2017-05-26 04:48:44 +08:00
|
|
|
Optional<Value> value = wait(transaction->get(data[currentIndex].key));
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = currentIndex; i < std::min(currentIndex + self->maxKeysPerTransaction, data.size());
|
|
|
|
i++) {
|
2017-05-26 04:48:44 +08:00
|
|
|
transaction->addReadConflictRange(singleKeyRange(data[i].key));
|
|
|
|
transaction->set(data[i].key, data[i].value);
|
|
|
|
}
|
|
|
|
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->commit());
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = currentIndex; i < std::min(currentIndex + self->maxKeysPerTransaction, data.size());
|
|
|
|
i++)
|
|
|
|
DEBUG_MUTATION("ApiCorrectnessSet",
|
|
|
|
transaction->getCommittedVersion(),
|
|
|
|
MutationRef(MutationRef::DebugKey, data[i].key, data[i].value));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
currentIndex += self->maxKeysPerTransaction;
|
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 08:25:43 +08:00
|
|
|
wait(transaction->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Set keys in memory
|
|
|
|
for (int i = 0; i < data.size(); i++) {
|
2017-05-26 04:48:44 +08:00
|
|
|
self->store.set(data[i].key, data[i].value);
|
|
|
|
self->debugKey(data[i].key, "Set");
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Check that the database and memory store are the same
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->compareDatabaseToMemory());
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("Set resulted in incorrect database");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Gets a specified number of values from the database and memory store and compares them, returning true if all
|
|
|
|
// results were the same
|
|
|
|
ACTOR Future<bool> runGet(VectorRef<KeyValueRef> data, int numReads, ApiCorrectnessWorkload* self) {
|
|
|
|
// Generate a set of random keys to get
|
2020-06-22 14:53:41 +08:00
|
|
|
state Standalone<VectorRef<KeyRef>> keys;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < numReads; i++)
|
|
|
|
keys.push_back_deep(keys.arena(), self->selectRandomKey(data, 0.9));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-09-17 08:42:34 +08:00
|
|
|
state std::vector<Optional<Value>> values;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
state int currentIndex = 0;
|
2021-03-11 02:06:03 +08:00
|
|
|
while (currentIndex < keys.size()) {
|
2017-05-26 04:48:44 +08:00
|
|
|
state Reference<TransactionWrapper> transaction = self->createTransaction();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Get the values from the database
|
2017-05-26 04:48:44 +08:00
|
|
|
loop {
|
|
|
|
try {
|
2021-09-17 08:42:34 +08:00
|
|
|
state std::vector<Future<Optional<Value>>> dbValueFutures;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = currentIndex; i < std::min(currentIndex + self->maxKeysPerTransaction, keys.size());
|
|
|
|
i++)
|
2017-05-26 04:48:44 +08:00
|
|
|
dbValueFutures.push_back(transaction->get(keys[i]));
|
|
|
|
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(waitForAll(dbValueFutures));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < dbValueFutures.size(); i++)
|
2017-05-26 04:48:44 +08:00
|
|
|
values.push_back(dbValueFutures[i].get());
|
|
|
|
|
|
|
|
currentIndex += self->maxKeysPerTransaction;
|
|
|
|
|
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool result = true;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Get the values from the memory store and compare them
|
|
|
|
for (int i = 0; i < keys.size(); i++) {
|
|
|
|
if (values[i] != self->store.get(keys[i])) {
|
2017-05-26 04:48:44 +08:00
|
|
|
result = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("Get returned incorrect results");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Gets a single range of values from the database and memory stores and compares them, returning true if the
|
|
|
|
// results were the same
|
|
|
|
ACTOR Future<bool> runGetRange(VectorRef<KeyValueRef> data, ApiCorrectnessWorkload* self) {
|
2021-07-03 12:41:50 +08:00
|
|
|
state Reverse reverse = deterministicRandom()->coinflip();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Generate a random range
|
2017-05-26 04:48:44 +08:00
|
|
|
Key key = self->selectRandomKey(data, 0.5);
|
|
|
|
Key key2 = self->selectRandomKey(data, 0.5);
|
|
|
|
|
|
|
|
state Key start = std::min(key, key2);
|
|
|
|
state Key end = std::max(key, key2);
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Generate a random maximum number of results
|
2019-05-11 05:01:52 +08:00
|
|
|
state int limit = deterministicRandom()->randomInt(0, 101);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Get the range from memory
|
2021-05-04 04:14:16 +08:00
|
|
|
state RangeResult storeResults = self->store.getRange(KeyRangeRef(start, end), limit, reverse);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Get the range from the database
|
2021-05-04 04:14:16 +08:00
|
|
|
state RangeResult dbResults;
|
2017-05-26 04:48:44 +08:00
|
|
|
state Version readVersion;
|
|
|
|
|
|
|
|
state Reference<TransactionWrapper> transaction = self->createTransaction();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
try {
|
|
|
|
Version version = wait(transaction->getReadVersion());
|
|
|
|
readVersion = version;
|
|
|
|
|
|
|
|
KeyRangeRef range(start, end);
|
2021-05-04 04:14:16 +08:00
|
|
|
RangeResult rangeResults = wait(transaction->getRange(range, limit, reverse));
|
2017-05-26 04:48:44 +08:00
|
|
|
dbResults = rangeResults;
|
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Compare the ranges
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = self->compareResults(dbResults, storeResults, readVersion);
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("GetRange returned incorrect results");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Gets a single range of values using key selectors from the database and memory store and compares them, returning
|
|
|
|
// true if the results were the same
|
|
|
|
ACTOR Future<bool> runGetRangeSelector(VectorRef<KeyValueRef> data, ApiCorrectnessWorkload* self) {
|
2021-07-05 03:32:45 +08:00
|
|
|
state Reverse reverse = deterministicRandom()->coinflip();
|
2021-07-03 12:41:50 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
KeySelector selectors[2];
|
|
|
|
Key keys[2];
|
|
|
|
|
|
|
|
int maxSelectorAttempts = 100;
|
|
|
|
int currentSelectorAttempts = 0;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Generate a random pair of key selectors and determine the keys they point to
|
|
|
|
// Don't use key selectors which would return results outside the key-space of this client unless this client
|
|
|
|
// is the first or last client
|
|
|
|
for (int i = 0; i < 2; i++) {
|
2017-05-26 04:48:44 +08:00
|
|
|
loop {
|
2021-03-11 02:06:03 +08:00
|
|
|
// Gradually decrease the maximum offset to increase the likelihood of finding a valid key selector in a
|
|
|
|
// small store
|
|
|
|
selectors[i] =
|
|
|
|
self->generateKeySelector(data, std::min(100, maxSelectorAttempts - currentSelectorAttempts));
|
2017-05-26 04:48:44 +08:00
|
|
|
keys[i] = self->store.getKey(selectors[i]);
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (keys[i].startsWith(StringRef(self->clientPrefix)) ||
|
|
|
|
(keys[i].size() == 0 && self->clientPrefixInt == 0) ||
|
|
|
|
(keys[i].startsWith(LiteralStringRef("\xff")) && self->clientPrefixInt == self->clientCount - 1)) {
|
2017-05-26 04:48:44 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Don't loop forever trying to generate valid key selectors if there are no keys in the store
|
|
|
|
if (++currentSelectorAttempts == maxSelectorAttempts)
|
2017-05-26 04:48:44 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
state KeySelector startSelector;
|
|
|
|
state KeySelector endSelector;
|
|
|
|
|
|
|
|
state Key startKey;
|
|
|
|
state Key endKey;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Make sure startKey is less than endKey
|
|
|
|
if (keys[0] < keys[1]) {
|
2017-05-26 04:48:44 +08:00
|
|
|
startSelector = selectors[0];
|
|
|
|
startKey = keys[0];
|
|
|
|
endSelector = selectors[1];
|
|
|
|
endKey = keys[1];
|
2021-03-11 02:06:03 +08:00
|
|
|
} else {
|
2017-05-26 04:48:44 +08:00
|
|
|
startSelector = selectors[1];
|
|
|
|
startKey = keys[1];
|
|
|
|
endSelector = selectors[0];
|
|
|
|
endKey = keys[0];
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Choose a random maximum number of results
|
2019-05-11 05:01:52 +08:00
|
|
|
state int limit = deterministicRandom()->randomInt(0, 101);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Get the range from the memory store
|
2021-05-04 04:14:16 +08:00
|
|
|
state RangeResult storeResults = self->store.getRange(KeyRangeRef(startKey, endKey), limit, reverse);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Get the range from the database
|
2021-05-04 04:14:16 +08:00
|
|
|
state RangeResult dbResults;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
state Reference<TransactionWrapper> transaction = self->createTransaction();
|
|
|
|
state Version readVersion;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
try {
|
|
|
|
Version version = wait(transaction->getReadVersion());
|
|
|
|
readVersion = version;
|
|
|
|
|
2021-05-04 04:14:16 +08:00
|
|
|
RangeResult range = wait(transaction->getRange(startSelector, endSelector, limit, reverse));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (endKey == self->store.endKey()) {
|
|
|
|
for (int i = 0; i < range.size(); i++) {
|
|
|
|
// Don't include results in the 0xFF key-space
|
|
|
|
if (!range[i].key.startsWith(LiteralStringRef("\xff")))
|
2017-05-26 04:48:44 +08:00
|
|
|
dbResults.push_back_deep(dbResults.arena(), range[i]);
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
if (reverse && dbResults.size() < storeResults.size()) {
|
|
|
|
storeResults.resize(storeResults.arena(), dbResults.size());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
} else
|
2017-05-26 04:48:44 +08:00
|
|
|
dbResults = range;
|
|
|
|
|
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Compare the results
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = self->compareResults(dbResults, storeResults, readVersion);
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("GetRange (KeySelector) returned incorrect results");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Gets a specified number of keys from the database and memory store and compares them, returning true if all
|
|
|
|
// results were the same
|
|
|
|
ACTOR Future<bool> runGetKey(VectorRef<KeyValueRef> data, int numGetKeys, ApiCorrectnessWorkload* self) {
|
|
|
|
// Generate a set of random key selectors
|
2020-06-22 14:53:41 +08:00
|
|
|
state Standalone<VectorRef<KeySelectorRef>> selectors;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < numGetKeys; i++)
|
2020-06-22 14:53:41 +08:00
|
|
|
selectors.push_back_deep(selectors.arena(), self->generateKeySelector(data, 100));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
state Standalone<VectorRef<KeyRef>> keys;
|
|
|
|
|
|
|
|
state int currentIndex = 0;
|
2021-03-11 02:06:03 +08:00
|
|
|
while (currentIndex < selectors.size()) {
|
|
|
|
// Get the keys from the database
|
2017-05-26 04:48:44 +08:00
|
|
|
state Reference<TransactionWrapper> transaction = self->createTransaction();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
try {
|
2021-09-17 08:42:34 +08:00
|
|
|
state std::vector<Future<Standalone<KeyRef>>> dbKeyFutures;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = currentIndex;
|
|
|
|
i < std::min(currentIndex + self->maxKeysPerTransaction, selectors.size());
|
|
|
|
i++)
|
2017-05-26 04:48:44 +08:00
|
|
|
dbKeyFutures.push_back(transaction->getKey(selectors[i]));
|
|
|
|
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(waitForAll(dbKeyFutures));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < dbKeyFutures.size(); i++)
|
2017-05-26 04:48:44 +08:00
|
|
|
keys.push_back_deep(keys.arena(), dbKeyFutures[i].get());
|
|
|
|
|
|
|
|
currentIndex += self->maxKeysPerTransaction;
|
|
|
|
|
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
state bool result = true;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Get the keys from the memory store and compare them
|
2017-05-26 04:48:44 +08:00
|
|
|
state int i;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (i = 0; i < selectors.size(); i++) {
|
2021-03-16 08:34:56 +08:00
|
|
|
Key key = self->store.getKey(selectors[i]);
|
2021-03-11 02:06:03 +08:00
|
|
|
if (keys[i].startsWith(StringRef(self->clientPrefix)) && keys[i] != key)
|
2017-05-26 04:48:44 +08:00
|
|
|
result = false;
|
2021-03-11 02:06:03 +08:00
|
|
|
else if (keys[i] < StringRef(self->clientPrefix) && key != self->store.startKey())
|
2017-05-26 04:48:44 +08:00
|
|
|
result = false;
|
2021-03-11 02:06:03 +08:00
|
|
|
else if (keys[i] > StringRef(self->clientPrefix + "\xff") && key != self->store.endKey())
|
2017-05-26 04:48:44 +08:00
|
|
|
result = false;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// If there was a failure, print some debugging info about the failed key
|
|
|
|
if (!result) {
|
|
|
|
printf("Bad result for key selector %s: db=%s, mem=%s\n",
|
|
|
|
selectors[i].toString().c_str(),
|
|
|
|
printable(keys[i]).c_str(),
|
|
|
|
printable(key).c_str());
|
2017-05-26 04:48:44 +08:00
|
|
|
state int dir = selectors[i].offset > 0 ? 1 : -1;
|
|
|
|
state int j;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (j = 0; j <= abs(selectors[i].offset); j++) {
|
2017-05-26 04:48:44 +08:00
|
|
|
state KeySelector sel = KeySelectorRef(selectors[i].getKey(), selectors[i].orEqual, j * dir);
|
|
|
|
state Key storeKey = self->store.getKey(sel);
|
|
|
|
|
|
|
|
state Reference<TransactionWrapper> tr = self->createTransaction();
|
|
|
|
|
|
|
|
state Key dbKey;
|
|
|
|
loop {
|
|
|
|
try {
|
|
|
|
Key key = wait(tr->getKey(sel));
|
|
|
|
dbKey = key;
|
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(tr->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!(storeKey == self->store.startKey() && dbKey < StringRef(self->clientPrefix)) &&
|
|
|
|
!(storeKey == self->store.endKey() && dbKey > StringRef(self->clientPrefix + "\xff")))
|
|
|
|
printf("Offset %d: db=%s, mem=%s\n",
|
|
|
|
j * dir,
|
|
|
|
printable(dbKey).c_str(),
|
|
|
|
printable(storeKey).c_str());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("GetKey returned incorrect results");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Clears a specified number of keys from the database and memory store
|
|
|
|
ACTOR Future<bool> runClear(VectorRef<KeyValueRef> data, int numClears, ApiCorrectnessWorkload* self) {
|
|
|
|
// Generate a random set of keys to clear
|
2020-06-22 14:53:41 +08:00
|
|
|
state Standalone<VectorRef<KeyRef>> keys;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < numClears; i++)
|
|
|
|
keys.push_back_deep(keys.arena(), self->selectRandomKey(data, 0.9));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
state int currentIndex = 0;
|
2021-03-11 02:06:03 +08:00
|
|
|
while (currentIndex < keys.size()) {
|
|
|
|
// Clear the keys from the database
|
2017-05-26 04:48:44 +08:00
|
|
|
state Reference<TransactionWrapper> transaction = self->createTransaction();
|
|
|
|
loop {
|
|
|
|
try {
|
2021-03-11 02:06:03 +08:00
|
|
|
// For now, make this transaction self-conflicting to avoid commit errors
|
2017-05-26 04:48:44 +08:00
|
|
|
Optional<Value> value = wait(transaction->get(keys[0]));
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = currentIndex; i < std::min(currentIndex + self->maxKeysPerTransaction, keys.size());
|
|
|
|
i++) {
|
2017-05-26 04:48:44 +08:00
|
|
|
transaction->addReadConflictRange(singleKeyRange(keys[i]));
|
|
|
|
transaction->clear(keys[i]);
|
|
|
|
}
|
|
|
|
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->commit());
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = currentIndex; i < std::min(currentIndex + self->maxKeysPerTransaction, keys.size());
|
|
|
|
i++)
|
|
|
|
DEBUG_MUTATION("ApiCorrectnessClear",
|
|
|
|
transaction->getCommittedVersion(),
|
|
|
|
MutationRef(MutationRef::DebugKey, keys[i], StringRef()));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
currentIndex += self->maxKeysPerTransaction;
|
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Clear the keys from the memory store
|
|
|
|
for (int i = 0; i < keys.size(); i++) {
|
2017-05-26 04:48:44 +08:00
|
|
|
self->store.clear(keys[i]);
|
|
|
|
self->debugKey(keys[i], "Clear");
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Check that the database and memory store are the same
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->compareDatabaseToMemory());
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("Clear resulted in incorrect database");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Clears a single range of keys from the database and memory store
|
|
|
|
ACTOR Future<bool> runClearRange(VectorRef<KeyValueRef> data, ApiCorrectnessWorkload* self) {
|
|
|
|
// Generate a random range to clear
|
2017-05-26 04:48:44 +08:00
|
|
|
Key key = self->selectRandomKey(data, 0.5);
|
|
|
|
Key key2 = self->selectRandomKey(data, 0.5);
|
|
|
|
|
|
|
|
state Key start = std::min(key, key2);
|
|
|
|
state Key end = std::max(key, key2);
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Clear the range in memory
|
2017-05-26 04:48:44 +08:00
|
|
|
self->store.clear(KeyRangeRef(start, end));
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Clear the range in the database
|
2017-05-26 04:48:44 +08:00
|
|
|
state Reference<TransactionWrapper> transaction = self->createTransaction();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
try {
|
2021-03-11 02:06:03 +08:00
|
|
|
// For now, make this transaction self-conflicting to avoid commit errors
|
2017-05-26 04:48:44 +08:00
|
|
|
Optional<Value> value = wait(transaction->get(start));
|
|
|
|
|
|
|
|
state KeyRangeRef range(start, end);
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!range.empty()) {
|
2017-05-26 04:48:44 +08:00
|
|
|
transaction->addReadConflictRange(range);
|
|
|
|
}
|
|
|
|
transaction->clear(range);
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->commit());
|
2020-05-14 05:28:04 +08:00
|
|
|
DEBUG_KEY_RANGE("ApiCorrectnessClear", transaction->getCommittedVersion(), range);
|
2017-05-26 04:48:44 +08:00
|
|
|
break;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(transaction->onError(e));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self->debugKey(KeyRangeRef(start, end), "ClearRange");
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Check that the database and memory store are the same
|
2017-05-26 04:48:44 +08:00
|
|
|
bool result = wait(self->compareDatabaseToMemory());
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!result)
|
2017-05-26 04:48:44 +08:00
|
|
|
self->testFailure("Clear (range) resulted in incorrect database");
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
WorkloadFactory<ApiCorrectnessWorkload> ApiCorrectnessWorkloadFactory("ApiCorrectness");
|