transactor.hxx
/* Transactor framework, a wrapper for safely retryable transactions.
*
* DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead.
*
* Copyright (c) 2000-2019, Jeroen T. Vermeulen.
*
* See COPYING for copyright license. If you did not receive a file called
* COPYING with this source code, please notify the distributor of this mistake,
* or contact the author.
*/
#ifndef PQXX_H_TRANSACTOR
#define PQXX_H_TRANSACTOR
#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"
#include "pqxx/connection_base.hxx"
#include "pqxx/transaction.hxx"
// Methods tested in eg. test module test01 are marked with "//[t01]".
namespace pqxx
{
template<typename TRANSACTION_CALLBACK>
inline auto perform(const TRANSACTION_CALLBACK &callback, int attempts=3)
-> decltype(callback())
{
if (attempts <= 0)
throw std::invalid_argument{
"Zero or negative number of attempts passed to pqxx::perform()."};
for (; attempts > 0; --attempts)
{
try
{
return callback();
}
catch (const in_doubt_error &)
{
// Not sure whether transaction went through or not. The last thing in
// the world that we should do now is try again!
throw;
}
catch (const statement_completion_unknown &)
{
// Not sure whether our last statement succeeded. Don't risk running it
// again.
throw;
}
catch (const broken_connection &)
{
// Connection failed. Definitely worth retrying.
if (attempts <= 1) throw;
continue;
}
catch (const transaction_rollback &)
{
// Some error that may well be transient, such as serialization failure
// or deadlock. Worth retrying.
if (attempts <= 1) throw;
continue;
}
}
throw pqxx::internal_error{"No outcome reached on perform()."};
}
template<typename TRANSACTION=transaction<read_committed>> class transactor
{
public:
using argument_type = TRANSACTION;
PQXX_DEPRECATED explicit transactor( //[t04]
const std::string &TName="transactor") :
m_name{TName} { }
void operator()(TRANSACTION &T); //[t04]
// Overridable member functions, called by connection_base::perform() if an
// attempt to run transaction fails/succeeds, respectively, or if the
// connection is lost at just the wrong moment, goes into an indeterminate
// state. Use these to patch up runtime state to match events, if needed, or
// to report failure conditions.
void on_abort(const char[]) noexcept {} //[t13]
void on_commit() {} //[t07]
void on_doubt() noexcept {} //[t13]
std::string name() const { return m_name; } //[t13]
private:
std::string m_name;
};
template<typename TRANSACTOR>
inline void connection_base::perform(
const TRANSACTOR &T,
int Attempts)
{
if (Attempts <= 0) return;
bool Done = false;
// Make attempts to perform T
do
{
--Attempts;
// Work on a copy of T2 so we can restore the starting situation if need be
TRANSACTOR T2{T};
try
{
typename TRANSACTOR::argument_type X{*this, T2.name()};
T2(X);
X.commit();
Done = true;
}
catch (const in_doubt_error &)
{
// Not sure whether transaction went through or not. The last thing in
// the world that we should do now is retry.
T2.on_doubt();
throw;
}
catch (const std::exception &e)
{
// Could be any kind of error.
T2.on_abort(e.what());
if (Attempts <= 0) throw;
continue;
}
catch (...)
{
// Don't try to forge ahead if we don't even know what happened
T2.on_abort("Unknown exception");
throw;
}
T2.on_commit();
} while (not Done);
}
} // namespace pqxx
#include "pqxx/compiler-internal-post.hxx"
#endif
pqxx::transactor::operator()
void operator()(TRANSACTION &T)
Overridable transaction definition; insert your database code here.
pqxx::statement_completion_unknown
We can't tell whether our last statement succeeded.
Definition: except.hxx:191
pqxx::transaction_rollback
The backend saw itself forced to roll back the ongoing transaction.
Definition: except.hxx:167
pqxx::transactor
Definition: transactor.hxx:156
pqxx::internal_error
Internal error in libpqxx library.
Definition: except.hxx:207
pqxx::broken_connection
Exception class for lost or failed backend connection.
Definition: except.hxx:118
pqxx::connection_base::perform
void perform(const TRANSACTOR &T, int Attempts)
Definition: transactor.hxx:225
pqxx::transactor::argument_type
TRANSACTION argument_type
Definition: transactor.hxx:159
pqxx::transactor::on_commit
void on_commit()
Optional overridable function to be called after successful commit.
Definition: transactor.hxx:200
pqxx::perform
auto perform(const TRANSACTION_CALLBACK &callback, int attempts=3) -> decltype(callback())
Simple way to execute a transaction with automatic retry.
Definition: transactor.hxx:99
pqxx::transactor::name
std::string name() const
The transactor's name.
Definition: transactor.hxx:217
pqxx::transactor::on_abort
void on_abort(const char[]) noexcept
Optional overridable function to be called if transaction is aborted.
Definition: transactor.hxx:193
pqxx::transactor::on_doubt
void on_doubt() noexcept
Overridable function to be called when "in doubt" about outcome.
Definition: transactor.hxx:214
pqxx::transactor::transactor
transactor(const std::string &TName="transactor")
Definition: transactor.hxx:160
pqxx::in_doubt_error
"Help, I don't know whether transaction was committed successfully!"
Definition: except.hxx:159
pqxx
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:25