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 
48 namespace pmem
49 {
50 
51 namespace obj
52 {
53 
71 class transaction {
72 public:
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
165 
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 
253  automatic &operator=(automatic &&p) = delete;
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 
438 private:
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 */
int count
The number of active exceptions.
Definition: transaction.hpp:289
static int add_lock() noexcept
Method ending the recursive algorithm.
Definition: transaction.hpp:468
The non-template pool base class.
Definition: pool.hpp:65
Internal class for counting active exceptions.
Definition: transaction.hpp:259
~manual() noexcept
Destructor.
Definition: transaction.hpp:130
~automatic() noexcept(false)
Destructor.
Definition: transaction.hpp:219
C++ transaction handler class.
Definition: transaction.hpp:71
Custom transaction error class.
Definition: pexceptions.hpp:114
Definition: pext.hpp:338
C++ manual scope transaction class.
Definition: transaction.hpp:91
PMEMobj pool class.
Definition: persistent_ptr.hpp:59
manual & operator=(const manual &p)=delete
Deleted assignment operator.
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
manual(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:107
Custom exceptions.
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.
C++ automatic scope transaction class.
Definition: transaction.hpp:184
Custom transaction error class.
Definition: pexceptions.hpp:63
static int add_lock(L &lock, Locks &... locks) noexcept
Recursively add locks to the active transaction.
Definition: transaction.hpp:453
bool new_uncaught_exception()
Notifies is a new exception is being handled.
Definition: transaction.hpp:280
automatic(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:204
uncaught_exception_counter()
Default constructor.
Definition: transaction.hpp:267
Resides on pmem class.
Definition: p.hpp:64
Definition: allocator.hpp:48
C++ pmemobj pool.
automatic & operator=(const automatic &p)=delete
Deleted assignment operator.