foundationdb/bindings/c/test/apitester/TesterWatchAndWaitWorkload.cpp

94 lines
3.1 KiB
C++

/*
* TesterWatchAndWaitWorkload.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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 "TesterApiWorkload.h"
#include "test/fdb_api.hpp"
namespace FdbApiTester {
using fdb::Key;
using fdb::Value;
class WatchAndWaitWorkload : public ApiWorkload {
public:
WatchAndWaitWorkload(const WorkloadConfig& config) : ApiWorkload(config) {}
int getMaxSelfBlockingFutures() override {
// One watch future running concurrently waits for a commit of a transaction which sets the value.
return 1;
}
private:
void randomOperation(TTaskFct cont) override {
// This test sets a key to an initial value, sets up a watch for that key, change the key's value to a different
// value, and waits for the watch to be triggered.
Key key(randomKeyName());
Value initialVal = randomValue();
auto newVal = randomValue();
// Ensure that newVal is different from initialVal, otherwise watch may not trigger.
while (initialVal == newVal) {
newVal = randomValue();
}
execTransaction(
[key, initialVal](auto ctx) {
// Set the key to initialVal.
ctx->tx().set(key, initialVal);
ctx->commit();
},
[this, key, newVal, cont]() {
execTransaction(
[key, newVal](auto ctx) {
// Check the value of the key.
auto f = ctx->tx().get(key, false);
ctx->continueAfter(f, [key, f, newVal, ctx] {
ASSERT(f.get().has_value());
if (f.get().value() == newVal) {
// If the key is already at newVal, finish successfully.
ctx->done();
} else {
// Otherwise, create a watch for the key.
auto watchF = ctx->tx().watch(key);
auto commitF = ctx->tx().commit();
ctx->continueAfterAll({ commitF, watchF }, [ctx] {
// Wait for the watch to report a change (to newVal).
ctx->done();
});
}
});
},
[this, cont]() { schedule(cont); });
schedule([this, key, newVal] {
execTransaction(
// Set the key to a newVal which is guaranteed to be different from initialVal, i.e.,
// must trigger the watch.
[key, newVal](auto ctx) {
ctx->tx().set(key, newVal);
ctx->commit();
},
[]() {});
});
});
}
};
WorkloadFactory<WatchAndWaitWorkload> WatchAndWaitWorkloadFactory("WatchAndWait");
} // namespace FdbApiTester