ApiTester: Adding some comments to the headers
This commit is contained in:
parent
1e75ffd880
commit
892538e233
|
@ -32,15 +32,27 @@ using TTaskFct = std::function<void(void)>;
|
|||
|
||||
extern const TTaskFct NO_OP_TASK;
|
||||
|
||||
/**
|
||||
* Scheduler for asynchronous execution of tasks on a pool of threads
|
||||
*/
|
||||
class IScheduler {
|
||||
public:
|
||||
virtual ~IScheduler() {}
|
||||
|
||||
// Create scheduler threads and begin accepting tasks
|
||||
virtual void start() = 0;
|
||||
|
||||
// Schedule a task for asynchronous execution
|
||||
virtual void schedule(TTaskFct task) = 0;
|
||||
|
||||
// Gracefully stop the scheduler. Waits for already running tasks to be finish
|
||||
virtual void stop() = 0;
|
||||
|
||||
// Join with all threads of the scheduler
|
||||
virtual void join() = 0;
|
||||
};
|
||||
|
||||
// create a scheduler using given number of threads
|
||||
std::unique_ptr<IScheduler> createScheduler(int numThreads);
|
||||
|
||||
} // namespace FdbApiTester
|
||||
|
|
|
@ -31,32 +31,58 @@
|
|||
|
||||
namespace FdbApiTester {
|
||||
|
||||
/// Workload specification
|
||||
struct WorkloadSpec {
|
||||
std::string name;
|
||||
std::unordered_map<std::string, std::string> options;
|
||||
};
|
||||
|
||||
// Test speficification loaded from a *.toml file
|
||||
struct TestSpec {
|
||||
// Title of the test
|
||||
std::string title;
|
||||
// api version, using the latest version by default
|
||||
|
||||
// FDB API version, using the latest version by default
|
||||
int apiVersion = FDB_API_VERSION;
|
||||
|
||||
// Use blocking waits on futures instead of scheduling callbacks
|
||||
bool blockOnFutures = false;
|
||||
|
||||
// Use multi-threaded FDB client
|
||||
bool multiThreaded = false;
|
||||
|
||||
// Enable injection of errors in FDB client
|
||||
bool buggify = false;
|
||||
|
||||
// Execute future callbacks on the threads of the external FDB library
|
||||
// rather than on the main thread of the local FDB client library
|
||||
bool fdbCallbacksOnExternalThreads = false;
|
||||
|
||||
// Execute each transaction in a separate database instance
|
||||
bool databasePerTransaction = false;
|
||||
|
||||
// Size of the FDB client thread pool (a random number in the [min,max] range)
|
||||
int minFdbThreads = 1;
|
||||
int maxFdbThreads = 1;
|
||||
|
||||
// Size of the thread pool for test workloads (a random number in the [min,max] range)
|
||||
int minClientThreads = 1;
|
||||
int maxClientThreads = 1;
|
||||
|
||||
// Size of the database instance pool (a random number in the [min,max] range)
|
||||
// Each transaction is assigned randomly to one of the databases in the pool
|
||||
int minDatabases = 1;
|
||||
int maxDatabases = 1;
|
||||
|
||||
// Number of workload clients (a random number in the [min,max] range)
|
||||
int minClients = 1;
|
||||
int maxClients = 10;
|
||||
std::string testFile;
|
||||
|
||||
// List of workloads with their options
|
||||
std::vector<WorkloadSpec> workloads;
|
||||
};
|
||||
|
||||
// Read the test specfication from a *.toml file
|
||||
TestSpec readTomlTestSpec(std::string fileName);
|
||||
|
||||
} // namespace FdbApiTester
|
||||
|
|
|
@ -31,27 +31,55 @@
|
|||
|
||||
namespace FdbApiTester {
|
||||
|
||||
/**
|
||||
* Interface to be used for implementation of a concrete transaction
|
||||
*/
|
||||
class ITransactionContext {
|
||||
public:
|
||||
virtual ~ITransactionContext() {}
|
||||
|
||||
// Current FDB transaction
|
||||
virtual Transaction* tx() = 0;
|
||||
|
||||
// Schedule a continuation to be executed when the future gets ready
|
||||
virtual void continueAfter(Future f, TTaskFct cont) = 0;
|
||||
|
||||
// Commit the transaction
|
||||
virtual void commit() = 0;
|
||||
|
||||
// Mark the transaction as completed without committing it (for read transactions)
|
||||
virtual void done() = 0;
|
||||
|
||||
// A continuation to be executed when all of the given futures get ready
|
||||
virtual void continueAfterAll(std::shared_ptr<std::vector<Future>> futures, TTaskFct cont);
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface of an actor object implementing a concrete transaction
|
||||
*/
|
||||
class ITransactionActor {
|
||||
public:
|
||||
virtual ~ITransactionActor() {}
|
||||
|
||||
// Initialize with the given transaction context
|
||||
virtual void init(ITransactionContext* ctx) = 0;
|
||||
|
||||
// Start execution of the transaction, also called on retries
|
||||
virtual void start() = 0;
|
||||
|
||||
// Reset the transaction state
|
||||
virtual void reset() = 0;
|
||||
|
||||
// Abort the transaction with an unretriable error
|
||||
virtual void setError(fdb_error_t err) { error = err; }
|
||||
|
||||
// Unretriable error, set if the transaction has failed
|
||||
fdb_error_t error = error_code_success;
|
||||
};
|
||||
|
||||
/**
|
||||
* A helper base class for transaction actors
|
||||
*/
|
||||
class TransactionActorBase : public ITransactionActor {
|
||||
public:
|
||||
void init(ITransactionContext* ctx) override { context = ctx; }
|
||||
|
@ -66,8 +94,12 @@ private:
|
|||
ITransactionContext* context = nullptr;
|
||||
};
|
||||
|
||||
// Type of the lambda functions implementing a transaction
|
||||
using TTxStartFct = std::function<void(ITransactionContext*)>;
|
||||
|
||||
/**
|
||||
* A wrapper class for transactions implemented by lambda functions
|
||||
*/
|
||||
class TransactionFct : public TransactionActorBase {
|
||||
public:
|
||||
TransactionFct(TTxStartFct startFct) : startFct(startFct) {}
|
||||
|
@ -77,13 +109,25 @@ private:
|
|||
TTxStartFct startFct;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration of transaction execution mode
|
||||
*/
|
||||
struct TransactionExecutorOptions {
|
||||
std::string prefix = "";
|
||||
// Use blocking waits on futures
|
||||
bool blockOnFutures = false;
|
||||
|
||||
// Create each transaction in a separate database instance
|
||||
bool databasePerTransaction = false;
|
||||
|
||||
// The size of the database instance pool
|
||||
int numDatabases = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transaction executor provides an interface for executing transactions
|
||||
* It is responsible for instantiating FDB databases and transactions and managing their lifecycle
|
||||
* according to the provided options
|
||||
*/
|
||||
class ITransactionExecutor {
|
||||
public:
|
||||
virtual ~ITransactionExecutor() {}
|
||||
|
@ -91,6 +135,7 @@ public:
|
|||
virtual void execute(std::shared_ptr<ITransactionActor> tx, TTaskFct cont) = 0;
|
||||
};
|
||||
|
||||
// Create a transaction executor for the given options
|
||||
std::unique_ptr<ITransactionExecutor> createTransactionExecutor(const TransactionExecutorOptions& options);
|
||||
|
||||
} // namespace FdbApiTester
|
||||
|
|
|
@ -34,19 +34,33 @@ namespace FdbApiTester {
|
|||
|
||||
class WorkloadManager;
|
||||
|
||||
// Workoad interface
|
||||
class IWorkload {
|
||||
public:
|
||||
virtual ~IWorkload() {}
|
||||
|
||||
// Intialize the workload
|
||||
virtual void init(WorkloadManager* manager) = 0;
|
||||
|
||||
// Start executing the workload
|
||||
virtual void start() = 0;
|
||||
};
|
||||
|
||||
// Workload configuration
|
||||
struct WorkloadConfig {
|
||||
// Workoad name
|
||||
std::string name;
|
||||
|
||||
// Client ID assigned to the workload (a number from 0 to numClients-1)
|
||||
int clientId;
|
||||
|
||||
// Total number of clients
|
||||
int numClients;
|
||||
|
||||
// Workload options: as key-value pairs
|
||||
std::unordered_map<std::string, std::string> options;
|
||||
|
||||
// Get option of a certain type by name. Throws an exception if the values is of a wrong type
|
||||
int getIntOption(const std::string& name, int defaultVal) const;
|
||||
double getFloatOption(const std::string& name, double defaultVal) const;
|
||||
};
|
||||
|
@ -56,6 +70,8 @@ struct WorkloadConfig {
|
|||
class WorkloadBase : public IWorkload {
|
||||
public:
|
||||
WorkloadBase(const WorkloadConfig& config);
|
||||
|
||||
// Initialize the workload
|
||||
void init(WorkloadManager* manager) override;
|
||||
|
||||
protected:
|
||||
|
@ -65,12 +81,12 @@ protected:
|
|||
// Execute a transaction within the workload
|
||||
void execTransaction(std::shared_ptr<ITransactionActor> tx, TTaskFct cont, bool failOnError = true);
|
||||
|
||||
// Execute a transaction within the workload, a convenience method for tranasactions defined by a single lambda
|
||||
// Execute a transaction within the workload, a convenience method for a tranasaction defined by a lambda function
|
||||
void execTransaction(TTxStartFct start, TTaskFct cont, bool failOnError = true) {
|
||||
execTransaction(std::make_shared<TransactionFct>(start), cont, failOnError);
|
||||
}
|
||||
|
||||
// Log an error message
|
||||
// Log an error message, increase error counter
|
||||
void error(const std::string& msg);
|
||||
|
||||
// Log an info message
|
||||
|
@ -85,13 +101,24 @@ private:
|
|||
// Keep track of tasks scheduled by the workload
|
||||
// End workload when this number falls to 0
|
||||
std::atomic<int> tasksScheduled;
|
||||
|
||||
// Number of errors logged
|
||||
std::atomic<int> numErrors;
|
||||
|
||||
protected:
|
||||
// Client ID assigned to the workload (a number from 0 to numClients-1)
|
||||
int clientId;
|
||||
|
||||
// Total number of clients
|
||||
int numClients;
|
||||
|
||||
// The maximum number of errors before stoppoing the workload
|
||||
int maxErrors;
|
||||
|
||||
// Workload identifier, consisting of workload name and client ID
|
||||
std::string workloadId;
|
||||
|
||||
// Workload is failed, no further transactions or continuations will be scheduled by the workload
|
||||
std::atomic<bool> failed;
|
||||
};
|
||||
|
||||
|
@ -109,6 +136,7 @@ public:
|
|||
// Run all workloads. Blocks until all workloads complete
|
||||
void run();
|
||||
|
||||
// True if at least one workload has failed
|
||||
bool failed() {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
return numWorkloadsFailed > 0;
|
||||
|
@ -117,29 +145,52 @@ public:
|
|||
private:
|
||||
friend WorkloadBase;
|
||||
|
||||
// Info about a running workload
|
||||
struct WorkloadInfo {
|
||||
// Reference to the workoad for ownership
|
||||
std::shared_ptr<IWorkload> ref;
|
||||
// Continuation to be executed after completing the workload
|
||||
TTaskFct cont;
|
||||
};
|
||||
|
||||
// To be called by a workload to notify that it is done
|
||||
void workloadDone(IWorkload* workload, bool failed);
|
||||
|
||||
// Transaction executor to be used by the workloads
|
||||
ITransactionExecutor* txExecutor;
|
||||
|
||||
// A scheduler to be used by the workloads
|
||||
IScheduler* scheduler;
|
||||
|
||||
// Mutex protects access to workloads & numWorkloadsFailed
|
||||
std::mutex mutex;
|
||||
|
||||
// A map of currently running workloads
|
||||
std::unordered_map<IWorkload*, WorkloadInfo> workloads;
|
||||
|
||||
// Number of workloads failed
|
||||
int numWorkloadsFailed;
|
||||
};
|
||||
|
||||
// A workload factory
|
||||
struct IWorkloadFactory {
|
||||
// create a workload by name
|
||||
static std::shared_ptr<IWorkload> create(std::string const& name, const WorkloadConfig& config);
|
||||
|
||||
// a singleton registry of workload factories
|
||||
static std::unordered_map<std::string, IWorkloadFactory*>& factories();
|
||||
|
||||
// Interface to be implemented by a workload factory
|
||||
virtual ~IWorkloadFactory() = default;
|
||||
virtual std::shared_ptr<IWorkload> create(const WorkloadConfig& config) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* A template for a workload factory for creating workloads of a certain type
|
||||
*
|
||||
* Declare a global instance of the factory for a workload type as follows:
|
||||
* WorkloadFactory<MyWorkload> MyWorkloadFactory("myWorkload");
|
||||
*/
|
||||
template <class WorkloadType>
|
||||
struct WorkloadFactory : IWorkloadFactory {
|
||||
WorkloadFactory(const char* name) { factories()[name] = this; }
|
||||
|
|
Loading…
Reference in New Issue