Use smart pointers to manage TestWorkload objects

This commit is contained in:
sfc-gh-tclinkenbeard 2022-01-06 14:12:16 -08:00
parent 936bf5336a
commit ac8979d624
2 changed files with 21 additions and 28 deletions

View File

@ -256,18 +256,14 @@ Standalone<VectorRef<KeyValueRef>> checkAllOptionsConsumed(VectorRef<KeyValueRef
}
struct CompoundWorkload : TestWorkload {
std::vector<TestWorkload*> workloads;
std::vector<Reference<TestWorkload>> workloads;
CompoundWorkload(WorkloadContext& wcx) : TestWorkload(wcx) {}
CompoundWorkload* add(TestWorkload* w) {
workloads.push_back(w);
CompoundWorkload* add(Reference<TestWorkload>&& w) {
workloads.push_back(std::move(w));
return this;
}
~CompoundWorkload() override {
for (int w = 0; w < workloads.size(); w++)
delete workloads[w];
}
std::string description() const override {
std::string d;
for (int w = 0; w < workloads.size(); w++)
@ -345,9 +341,9 @@ struct CompoundWorkload : TestWorkload {
}
};
TestWorkload* getWorkloadIface(WorkloadRequest work,
VectorRef<KeyValueRef> options,
Reference<AsyncVar<ServerDBInfo> const> dbInfo) {
Reference<TestWorkload> getWorkloadIface(WorkloadRequest work,
VectorRef<KeyValueRef> options,
Reference<AsyncVar<ServerDBInfo> const> dbInfo) {
Value testName = getOption(options, LiteralStringRef("testName"), LiteralStringRef("no-test-specified"));
WorkloadContext wcx;
wcx.clientId = work.clientId;
@ -356,7 +352,7 @@ TestWorkload* getWorkloadIface(WorkloadRequest work,
wcx.options = options;
wcx.sharedRandomNumber = work.sharedRandomNumber;
TestWorkload* workload = IWorkloadFactory::create(testName.toString(), wcx);
auto workload = IWorkloadFactory::create(testName.toString(), wcx);
auto unconsumedOptions = checkAllOptionsConsumed(workload ? workload->options : VectorRef<KeyValueRef>());
if (!workload || unconsumedOptions.size()) {
@ -375,14 +371,13 @@ TestWorkload* getWorkloadIface(WorkloadRequest work,
" '%s' = '%s'\n",
unconsumedOptions[i].key.toString().c_str(),
unconsumedOptions[i].value.toString().c_str());
delete workload;
}
throw test_specification_invalid();
}
return workload;
}
TestWorkload* getWorkloadIface(WorkloadRequest work, Reference<AsyncVar<ServerDBInfo> const> dbInfo) {
Reference<TestWorkload> getWorkloadIface(WorkloadRequest work, Reference<AsyncVar<ServerDBInfo> const> dbInfo) {
if (work.options.size() < 1) {
TraceEvent(SevError, "TestCreationError").detail("Reason", "No options provided");
fprintf(stderr, "ERROR: No options were provided for workload.\n");
@ -397,10 +392,9 @@ TestWorkload* getWorkloadIface(WorkloadRequest work, Reference<AsyncVar<ServerDB
wcx.sharedRandomNumber = work.sharedRandomNumber;
// FIXME: Other stuff not filled in; why isn't this constructed here and passed down to the other
// getWorkloadIface()?
CompoundWorkload* compound = new CompoundWorkload(wcx);
auto compound = makeReference<CompoundWorkload>(wcx);
for (int i = 0; i < work.options.size(); i++) {
TestWorkload* workload = getWorkloadIface(work, work.options[i], dbInfo);
compound->add(workload);
compound->add(getWorkloadIface(work, work.options[i], dbInfo));
}
return compound;
}
@ -526,9 +520,8 @@ void sendResult(ReplyPromise<T>& reply, Optional<ErrorOr<T>> const& result) {
ACTOR Future<Void> runWorkloadAsync(Database cx,
WorkloadInterface workIface,
TestWorkload* workload,
Reference<TestWorkload> workload,
double databasePingDelay) {
state std::unique_ptr<TestWorkload> delw(workload);
state Optional<ErrorOr<Void>> setupResult;
state Optional<ErrorOr<Void>> startResult;
state Optional<ErrorOr<CheckReply>> checkResult;
@ -654,7 +647,7 @@ ACTOR Future<Void> testerServerWorkload(WorkloadRequest work,
// add test for "done" ?
TraceEvent("WorkloadReceived", workIface.id()).detail("Title", work.title);
TestWorkload* workload = getWorkloadIface(work, dbInfo);
auto workload = getWorkloadIface(work, dbInfo);
if (!workload) {
TraceEvent("TestCreationError").detail("Reason", "Workload could not be created");
fprintf(stderr, "ERROR: The workload could not be created.\n");

View File

@ -57,7 +57,7 @@ struct WorkloadContext {
WorkloadContext& operator=(const WorkloadContext&) = delete;
};
struct TestWorkload : NonCopyable, WorkloadContext {
struct TestWorkload : NonCopyable, WorkloadContext, ReferenceCounted<TestWorkload> {
int phases;
// Subclasses are expected to also have a constructor with this signature (to work with WorkloadFactory<>):
@ -103,25 +103,25 @@ struct KVWorkload : TestWorkload {
Key keyForIndex(uint64_t index, bool absent) const;
};
struct IWorkloadFactory {
static TestWorkload* create(std::string const& name, WorkloadContext const& wcx) {
struct IWorkloadFactory : ReferenceCounted<IWorkloadFactory> {
static Reference<TestWorkload> create(std::string const& name, WorkloadContext const& wcx) {
auto it = factories().find(name);
if (it == factories().end())
return nullptr; // or throw?
return {}; // or throw?
return it->second->create(wcx);
}
static std::map<std::string, IWorkloadFactory*>& factories() {
static std::map<std::string, IWorkloadFactory*> theFactories;
static std::map<std::string, Reference<IWorkloadFactory>>& factories() {
static std::map<std::string, Reference<IWorkloadFactory>> theFactories;
return theFactories;
}
virtual TestWorkload* create(WorkloadContext const& wcx) = 0;
virtual Reference<TestWorkload> create(WorkloadContext const& wcx) = 0;
};
template <class WorkloadType>
struct WorkloadFactory : IWorkloadFactory {
WorkloadFactory(const char* name) { factories()[name] = this; }
TestWorkload* create(WorkloadContext const& wcx) override { return new WorkloadType(wcx); }
WorkloadFactory(const char* name) { factories()[name] = Reference<IWorkloadFactory>::addRef(this); }
Reference<TestWorkload> create(WorkloadContext const& wcx) override { return makeReference<WorkloadType>(wcx); }
};
#define REGISTER_WORKLOAD(classname) WorkloadFactory<classname> classname##WorkloadFactory(#classname)