libpqxx
transactor.hxx
1/* Transactor framework, a wrapper for safely retryable transactions.
2 *
3 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead.
4 *
5 * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
6 *
7 * See COPYING for copyright license. If you did not receive a file called
8 * COPYING with this source code, please notify the distributor of this mistake,
9 * or contact the author.
10 */
11#ifndef PQXX_H_TRANSACTOR
12#define PQXX_H_TRANSACTOR
13
14#include "pqxx/compiler-public.hxx"
15#include "pqxx/compiler-internal-pre.hxx"
16
17#include "pqxx/connection_base.hxx"
18#include "pqxx/transaction.hxx"
19
20
21// Methods tested in eg. test module test01 are marked with "//[t01]".
22
23namespace pqxx
24{
67
69
98template<typename TRANSACTION_CALLBACK>
99inline auto perform(const TRANSACTION_CALLBACK &callback, int attempts=3)
100 -> decltype(callback())
101{
102 if (attempts <= 0)
103 throw std::invalid_argument{
104 "Zero or negative number of attempts passed to pqxx::perform()."};
105
106 for (; attempts > 0; --attempts)
107 {
108 try
109 {
110 return callback();
111 }
112 catch (const in_doubt_error &)
113 {
114 // Not sure whether transaction went through or not. The last thing in
115 // the world that we should do now is try again!
116 throw;
117 }
118 catch (const statement_completion_unknown &)
119 {
120 // Not sure whether our last statement succeeded. Don't risk running it
121 // again.
122 throw;
123 }
124 catch (const broken_connection &)
125 {
126 // Connection failed. Definitely worth retrying.
127 if (attempts <= 1) throw;
128 continue;
129 }
130 catch (const transaction_rollback &)
131 {
132 // Some error that may well be transient, such as serialization failure
133 // or deadlock. Worth retrying.
134 if (attempts <= 1) throw;
135 continue;
136 }
137 }
138 throw pqxx::internal_error{"No outcome reached on perform()."};
139}
140
142
156template<typename TRANSACTION=transaction<read_committed>> class transactor
157{
158public:
159 using argument_type = TRANSACTION;
160 PQXX_DEPRECATED explicit transactor( //[t04]
161 const std::string &TName="transactor") :
162 m_name{TName} { }
163
165
176 void operator()(TRANSACTION &T); //[t04]
177
178 // Overridable member functions, called by connection_base::perform() if an
179 // attempt to run transaction fails/succeeds, respectively, or if the
180 // connection is lost at just the wrong moment, goes into an indeterminate
181 // state. Use these to patch up runtime state to match events, if needed, or
182 // to report failure conditions.
183
185
193 void on_abort(const char[]) noexcept {} //[t13]
194
196
200 void on_commit() {} //[t07]
201
203
214 void on_doubt() noexcept {} //[t13]
215
217 std::string name() const { return m_name; } //[t13]
218
219private:
220 std::string m_name;
221};
222
223
224template<typename TRANSACTOR>
226 const TRANSACTOR &T,
227 int Attempts)
228{
229 if (Attempts <= 0) return;
230
231 bool Done = false;
232
233 // Make attempts to perform T
234 do
235 {
236 --Attempts;
237
238 // Work on a copy of T2 so we can restore the starting situation if need be
239 TRANSACTOR T2{T};
240 try
241 {
242 typename TRANSACTOR::argument_type X{*this, T2.name()};
243 T2(X);
244 X.commit();
245 Done = true;
246 }
247 catch (const in_doubt_error &)
248 {
249 // Not sure whether transaction went through or not. The last thing in
250 // the world that we should do now is retry.
251 T2.on_doubt();
252 throw;
253 }
254 catch (const std::exception &e)
255 {
256 // Could be any kind of error.
257 T2.on_abort(e.what());
258 if (Attempts <= 0) throw;
259 continue;
260 }
261 catch (...)
262 {
263 // Don't try to forge ahead if we don't even know what happened
264 T2.on_abort("Unknown exception");
265 throw;
266 }
267
268 T2.on_commit();
269 } while (not Done);
270}
271} // namespace pqxx
273#include "pqxx/compiler-internal-post.hxx"
274#endif
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:26
auto perform(const TRANSACTION_CALLBACK &callback, int attempts=3) -> decltype(callback())
Simple way to execute a transaction with automatic retry.
Definition: transactor.hxx:99
void perform(const TRANSACTOR &T, int Attempts)
Definition: transactor.hxx:225
Exception class for lost or failed backend connection.
Definition: except.hxx:119
"Help, I don't know whether transaction was committed successfully!"
Definition: except.hxx:160
The backend saw itself forced to roll back the ongoing transaction.
Definition: except.hxx:168
We can't tell whether our last statement succeeded.
Definition: except.hxx:192
Internal error in libpqxx library.
Definition: except.hxx:209
Definition: transactor.hxx:157
void on_doubt() noexcept
Overridable function to be called when "in doubt" about outcome.
Definition: transactor.hxx:214
transactor(const std::string &TName="transactor")
Definition: transactor.hxx:160
void on_commit()
Optional overridable function to be called after successful commit.
Definition: transactor.hxx:200
void operator()(TRANSACTION &T)
Overridable transaction definition; insert your database code here.
void on_abort(const char[]) noexcept
Optional overridable function to be called if transaction is aborted.
Definition: transactor.hxx:193
TRANSACTION argument_type
Definition: transactor.hxx:159
std::string name() const
The transactor's name.
Definition: transactor.hxx:217