PMDK C++ bindings 1.2.0
This is the C++ bindings documentation for PMDK's libpmemobj.
transaction.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2016-2017, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
38#ifndef LIBPMEMOBJ_TRANSACTION_HPP
39#define LIBPMEMOBJ_TRANSACTION_HPP
40
41#include <functional>
42#include <string>
43
45#include "libpmemobj++/pool.hpp"
46#include "libpmemobj/tx_base.h"
47
48namespace pmem
49{
50
51namespace obj
52{
53
72public:
91 class manual {
92 public:
106 template <typename... L>
107 manual(obj::pool_base &pop, L &... locks)
108 {
109 if (pmemobj_tx_begin(pop.get_handle(), NULL,
110 TX_PARAM_NONE) != 0)
111 throw transaction_error(
112 "failed to start transaction");
113
114 auto err = add_lock(locks...);
115
116 if (err) {
117 pmemobj_tx_abort(EINVAL);
118 throw transaction_error("failed to"
119 " add lock");
120 }
121 }
122
130 ~manual() noexcept
131 {
132 /* normal exit or with an active exception */
133 if (pmemobj_tx_stage() == TX_STAGE_WORK)
134 pmemobj_tx_abort(ECANCELED);
135
136 (void)pmemobj_tx_end();
137 }
138
142 manual(const manual &p) = delete;
143
147 manual(const manual &&p) = delete;
148
152 manual &operator=(const manual &p) = delete;
153
157 manual &operator=(manual &&p) = delete;
158 };
159
160/*
161 * XXX The Microsoft compiler does not follow the ISO SD-6: SG10 Feature
162 * Test Recommendations. "|| _MSC_VER >= 1900" is a workaround.
163 */
164#if __cpp_lib_uncaught_exceptions || _MSC_VER >= 1900
184 class automatic {
185 public:
203 template <typename... L>
204 automatic(obj::pool_base &pop, L &... locks)
205 : tx_worker(pop, locks...)
206 {
207 }
208
219 ~automatic() noexcept(false)
220 {
221 /* active exception, abort handled by tx_worker */
222 if (exceptions.new_uncaught_exception())
223 return;
224
225 /* transaction ended normally */
226 if (pmemobj_tx_stage() == TX_STAGE_WORK)
227 pmemobj_tx_commit();
228 /* transaction aborted, throw an exception */
229 else if (pmemobj_tx_stage() == TX_STAGE_ONABORT ||
230 (pmemobj_tx_stage() == TX_STAGE_FINALLY &&
231 pmemobj_tx_errno() != 0))
232 throw transaction_error("Transaction aborted");
233 }
234
238 automatic(const automatic &p) = delete;
239
243 automatic(const automatic &&p) = delete;
244
248 automatic &operator=(const automatic &p) = delete;
249
254
255 private:
260 public:
268 : count(std::uncaught_exceptions())
269 {
270 }
271
279 bool
281 {
282 return std::uncaught_exceptions() > this->count;
283 }
284
285 private:
289 int count;
290 } exceptions;
291
292 transaction::manual tx_worker;
293 };
294#endif /* __cpp_lib_uncaught_exceptions */
295
296 /*
297 * Deleted default constructor.
298 */
299 transaction() = delete;
300
307 ~transaction() noexcept = delete;
308
323 static void
324 abort(int err)
325 {
326 if (pmemobj_tx_stage() != TX_STAGE_WORK)
327 throw transaction_error("wrong stage for"
328 " abort");
329
330 pmemobj_tx_abort(err);
331 throw manual_tx_abort("explicit abort " + std::to_string(err));
332 }
333
344 static void
346 {
347 if (pmemobj_tx_stage() != TX_STAGE_WORK)
348 throw transaction_error("wrong stage for"
349 " commit");
350
351 pmemobj_tx_commit();
352 }
353
354 static int
355 get_last_tx_error() noexcept
356 {
357 return pmemobj_tx_errno();
358 }
359
391 template <typename... Locks>
392 static void
393 exec_tx(pool_base &pool, std::function<void()> tx, Locks &... locks)
394 {
395 if (pmemobj_tx_begin(pool.get_handle(), NULL, TX_PARAM_NONE) !=
396 0)
397 throw transaction_error("failed to start transaction");
398
399 auto err = add_lock(locks...);
400
401 if (err) {
402 pmemobj_tx_abort(err);
403 (void)pmemobj_tx_end();
404 throw transaction_error("failed to add a lock to the"
405 " transaction");
406 }
407
408 try {
409 tx();
410 } catch (manual_tx_abort &) {
411 (void)pmemobj_tx_end();
412 throw;
413 } catch (...) {
414 /* first exception caught */
415 if (pmemobj_tx_stage() == TX_STAGE_WORK)
416 pmemobj_tx_abort(ECANCELED);
417
418 /* waterfall tx_end for outer tx */
419 (void)pmemobj_tx_end();
420 throw;
421 }
422
423 auto stage = pmemobj_tx_stage();
424
425 if (stage == TX_STAGE_WORK) {
426 pmemobj_tx_commit();
427 } else if (stage == TX_STAGE_ONABORT) {
428 (void)pmemobj_tx_end();
429 throw transaction_error("transaction aborted");
430 } else if (stage == TX_STAGE_NONE) {
431 throw transaction_error("transaction ended"
432 "prematurely");
433 }
434
435 (void)pmemobj_tx_end();
436 }
437
438private:
451 template <typename L, typename... Locks>
452 static int
453 add_lock(L &lock, Locks &... locks) noexcept
454 {
455 auto err =
456 pmemobj_tx_lock(lock.lock_type(), lock.native_handle());
457
458 if (err)
459 return err;
460
461 return add_lock(locks...);
462 }
463
467 static inline int
468 add_lock() noexcept
469 {
470 return 0;
471 }
472};
473
474} /* namespace obj */
475
476} /* namespace pmem */
477
478#endif /* LIBPMEMOBJ_TRANSACTION_HPP */
Custom transaction error class.
Definition: pexceptions.hpp:114
Resides on pmem class.
Definition: p.hpp:64
The non-template pool base class.
Definition: pool.hpp:65
PMEMobj pool class.
Definition: pool.hpp:423
Internal class for counting active exceptions.
Definition: transaction.hpp:259
bool new_uncaught_exception()
Notifies is a new exception is being handled.
Definition: transaction.hpp:280
uncaught_exception_counter()
Default constructor.
Definition: transaction.hpp:267
int count
The number of active exceptions.
Definition: transaction.hpp:289
C++ automatic scope transaction class.
Definition: transaction.hpp:184
automatic(const automatic &&p)=delete
Deleted move constructor.
~automatic() noexcept(false)
Destructor.
Definition: transaction.hpp:219
automatic(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:204
automatic & operator=(automatic &&p)=delete
Deleted move assignment operator.
automatic(const automatic &p)=delete
Deleted copy constructor.
automatic & operator=(const automatic &p)=delete
Deleted assignment operator.
C++ manual scope transaction class.
Definition: transaction.hpp:91
manual & operator=(manual &&p)=delete
Deleted move assignment operator.
manual(const manual &&p)=delete
Deleted move constructor.
~manual() noexcept
Destructor.
Definition: transaction.hpp:130
manual(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:107
manual & operator=(const manual &p)=delete
Deleted assignment operator.
manual(const manual &p)=delete
Deleted copy constructor.
C++ transaction handler class.
Definition: transaction.hpp:71
static void commit()
Manually commit a transaction.
Definition: transaction.hpp:345
static void abort(int err)
Manually abort the current transaction.
Definition: transaction.hpp:324
~transaction() noexcept=delete
Default destructor.
static int add_lock(L &lock, Locks &... locks) noexcept
Recursively add locks to the active transaction.
Definition: transaction.hpp:453
static void exec_tx(pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:393
static int add_lock() noexcept
Method ending the recursive algorithm.
Definition: transaction.hpp:468
Custom transaction error class.
Definition: pexceptions.hpp:63
Custom exceptions.
C++ pmemobj pool.