Skip to content

Commit

Permalink
Comments to document the PostCondition class
Browse files Browse the repository at this point in the history
  • Loading branch information
jseyster committed Jan 25, 2023
1 parent 8de8df4 commit 909105a
Showing 1 changed file with 64 additions and 15 deletions.
79 changes: 64 additions & 15 deletions src/metrics/include/metrics/PostCondition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,35 @@ enum class MetricRequirement {
kBytes,
};

enum class Comparison {
kGT,
};

/**
* A PostCondition added to a CrudActor Operation checks the metrics of the operation immediately
* after it runs, so that it can be marked as failing if it does not meet expectations for the
* intended test scenario. For example, a post-condition ensuring that a find command is returning
* the expected number of documents can quickly identify a spurious performance improvement caused
* by a bug in query evaluation. A post-condition can also check the state of a collection, ensuring
* that it is large enough to appropriately stress target code paths, when attached to a query that
* scans the entire collection.
*
* Example:
* ```yaml
* Actors:
* - Name: InsertOne
* Type: CrudActor
* Database: test
* Phases:
* - Collection: test
* Operations:
* - OperationName: insertOne
* OperationCommand:
* Document: {a: "value"}
* PostCondition:
* - Metric: documents
* EQ: 1
* - Metric: bytes
* LT: 20
* GT: 5
* ```
*/
struct PostCondition {
// The default PostCondition is a tautology.
PostCondition() = default;
Expand All @@ -47,6 +72,10 @@ struct PostCondition {
}
}

/**
* Checks if the 'ops' and 'bytes' metrics for the execution of a CRUD operation meet the
* requirements and throws an exception if they do not.
*/
void check(long long ops, long long bytes) const {
for (const auto& req : requirements) {
long long observedValue = [&]() {
Expand All @@ -70,33 +99,48 @@ struct PostCondition {
}

private:
struct Predicate {
/**
* A binary comparison relation on 'long long' ints (e.g., ==, <)
*/
struct Relation {
// The YAML key used to include this relation in a PostCondition specification.
std::string key;

// The symbol to use when outputting user messages about a comparison result.
std::string symbol;

// Implementation that returns true if the relation holds (meeting the post-condition
// requirement) for a pair of values.
std::function<bool(long long, long long)> evaluateFn;
};

struct Requirement {
MetricRequirement metric;
const Predicate& predicate;
const Relation& relation;
long long requiredValue;

Requirement(MetricRequirement metric, const Predicate& predicate, long long requiredValue)
: metric(metric), predicate(predicate), requiredValue(requiredValue) {}
: metric(metric), relation(relation), requiredValue(requiredValue) {}
};

/**
* Parse one block from the list of blocks in a YAML PostCondition into one or more entries in
* the 'requirements' list.
*/
void addCondition(const Node& node) {
static const char* metricKey = "Metric";
static const char* documentMetric = "documents";
static const char* bytesMetric = "bytes";

static const std::vector<Predicate> predicates = {
// The parser uses this table to translate the YAML key (e.g., "EQ") for a comparison into a
// function that can perform the comparison.
static const std::vector<Relation> relations = {
{"EQ", "==", [](long long left, long long right) { return left == right; }},
{"NE", "!=", [](long long left, long long right) { return left != right; }},
{"LT", "==", [](long long left, long long right) { return left < right; }},
{"LTE", "==", [](long long left, long long right) { return left <= right; }},
{"GT", "==", [](long long left, long long right) { return left > right; }},
{"GTE", "==", [](long long left, long long right) { return left >= right; }},
{"LT", "<", [](long long left, long long right) { return left < right; }},
{"LTE", "<=", [](long long left, long long right) { return left <= right; }},
{"GT", ">", [](long long left, long long right) { return left > right; }},
{"GTE", ">=", [](long long left, long long right) { return left >= right; }},
};

auto metricName = node[metricKey].maybe<std::string>();
Expand All @@ -112,13 +156,18 @@ struct PostCondition {
BOOST_THROW_EXCEPTION(InvalidConfigurationException("Unexpected metric"));
}

for (const auto& predicate : predicates) {
if (auto requiredValue = node[predicate.key].maybe<long long>()) {
requirements.emplace_back(metric, predicate, *requiredValue);
for (const auto& relation : relations) {
if (auto requiredValue = node[relation.key].maybe<long long>()) {
requirements.emplace_back(metric, relation, *requiredValue);
}
}
}

/*
* A list of requirements that must all be met for the post-condition to be fulfilled. Each
* requirement specifies the metric to check, a reference value to compare the metric to, and an
* arithmetic relation (e.g, ==, <) to compare with.
*/
std::vector<Requirement> requirements;
};

Expand Down

0 comments on commit 909105a

Please sign in to comment.