Added `transaction_option_setter<DB>` to determine if a DB-like thing has a `->setOptions(tr)` method. This method is called in `runTransaction()` templates at the top of the retry loop and in the manual retry loops in KeyBackedTypes. Added `if constexpr(` support to the ActorCompiler to support this.

This commit is contained in:
Steve Atherton 2023-04-22 11:10:20 -07:00
parent 893faf7d5a
commit dd334f1b02
6 changed files with 39 additions and 12 deletions

View File

@ -1684,6 +1684,9 @@ struct transaction_creator_traits : std::false_type {};
template <typename T>
struct transaction_creator_traits<T, std::void_t<typename T::TransactionT>> : std::true_type {};
template <typename T>
struct transaction_creator_traits<Reference<T>> : transaction_creator_traits<T> {};
template <typename T>
constexpr bool is_transaction_creator = transaction_creator_traits<T>::value;

View File

@ -26,14 +26,13 @@
#elif !defined(FDBCLIENT_KEYBACKEDTYPES_ACTOR_H)
#define FDBCLIENT_KEYBACKEDTYPES_ACTOR_H
#include "fdbclient/KeyBackedTypes.actor.h"
#include <utility>
#include <vector>
#include <ranges>
#include "fdbclient/ClientBooleanParams.h"
#include "fdbclient/CommitTransaction.h"
#include "fdbclient/RunTransaction.actor.h"
#include "fdbclient/FDBOptions.g.h"
#include "fdbclient/FDBTypes.h"
#include "fdbclient/GenericTransactionHelper.h"
@ -282,11 +281,10 @@ Future<Version> WatchableTrigger::onChangeActor(WatchableTrigger self,
state Reference<typename DB::TransactionT> tr = db->createTransaction();
loop {
if constexpr (can_set_transaction_options<DB>) {
db->setOptions(tr);
}
try {
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
// If the initialVersion is not set yet, then initialize it with the read version
if (!initialVersion.present()) {
wait(store(initialVersion, safeThreadFutureToFuture(tr->getReadVersion())));

View File

@ -34,12 +34,25 @@
#include "fdbclient/FDBOptions.g.h"
#include "flow/actorcompiler.h" // This must be the last #include.
template <typename, typename = void>
struct transaction_option_setter : std::false_type {};
template <typename T>
struct transaction_option_setter<Reference<T>> : transaction_option_setter<T> {};
template <typename T>
constexpr bool can_set_transaction_options = transaction_option_setter<T>::value;
ACTOR template <class Function, class DB>
Future<decltype(std::declval<Function>()(Reference<typename DB::TransactionT>()).getValue())> runTransaction(
Reference<DB> db,
Function func) {
state Reference<typename DB::TransactionT> tr = db->createTransaction();
loop {
if constexpr (can_set_transaction_options<DB>) {
db->setOptions(tr);
}
try {
// func should be idempotent; otherwise, retry will get undefined result
state decltype(std::declval<Function>()(Reference<typename DB::TransactionT>()).getValue()) result =
@ -56,6 +69,9 @@ ACTOR template <class Function, class DB>
Future<Void> runTransactionVoid(Reference<DB> db, Function func) {
state Reference<typename DB::TransactionT> tr = db->createTransaction();
loop {
if constexpr (can_set_transaction_options<DB>) {
db->setOptions(tr);
}
try {
// func should be idempotent; otherwise, retry will get undefined result
wait(func(tr));
@ -77,9 +93,9 @@ struct SystemTransactionGenerator : ReferenceCounted<SystemTransactionGenerator<
SystemTransactionGenerator(Reference<DB> db, bool write, bool lockAware, bool immediate)
: db(db), write(write), lockAware(lockAware), immediate(immediate) {}
Reference<TransactionT> createTransaction() const {
Reference<TransactionT> tr = db->createTransaction();
Reference<TransactionT> createTransaction() const { return db->createTransaction(); }
void setOptions(Reference<TransactionT> tr) const {
if (write) {
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
} else {
@ -93,7 +109,6 @@ struct SystemTransactionGenerator : ReferenceCounted<SystemTransactionGenerator<
if (lockAware) {
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
}
return tr;
}
Reference<DB> db;
@ -102,6 +117,9 @@ struct SystemTransactionGenerator : ReferenceCounted<SystemTransactionGenerator<
bool immediate;
};
template <typename DB>
struct transaction_option_setter<SystemTransactionGenerator<DB>> : std::true_type {};
// Convenient wrapper for creating SystemTransactionGenerators.
template <typename DB>
auto SystemDB(Reference<DB> db, bool write = false, bool lockAware = false, bool immediate = false) {

View File

@ -1047,7 +1047,7 @@ namespace actorcompiler
bool useContinuation = WillContinue(stmt.ifBody) || WillContinue(stmt.elseBody);
LineNumber(cx.target, stmt.FirstSourceLine);
cx.target.WriteLine("if ({0})", stmt.expression);
cx.target.WriteLine("if {1}({0})", stmt.expression, stmt.constexpr ? "constexpr " : "");
cx.target.WriteLine("{");
cx.target.Indent(+1);
Function ifTarget = Compile(AsCodeBlock(stmt.ifBody), cx, useContinuation).target;

View File

@ -836,12 +836,19 @@ namespace actorcompiler
Statement ParseIfStatement(TokenRange toks)
{
var expr = toks.Consume("if")
.First(NonWhitespace)
toks = toks.Consume("if");
toks = toks.SkipWhile(Whitespace);
bool constexpr = toks.First().Value == "constexpr";
if(constexpr) {
toks = toks.Consume("constexpr").SkipWhile(Whitespace);
}
var expr = toks.First(NonWhitespace)
.Assert("Expected (", t => t.Value == "(")
.GetMatchingRangeIn(toks);
return new IfStatement {
expression = str(NormalizeWhitespace(expr)),
constexpr = constexpr,
ifBody = ParseCompoundStatement(range(expr.End+1, toks.End))
// elseBody will be filled in later if necessary by ParseElseStatement
};

View File

@ -112,6 +112,7 @@ namespace actorcompiler
class IfStatement : Statement
{
public string expression;
public bool constexpr;
public Statement ifBody;
public Statement elseBody; // might be null
public override bool containsWait()