PMDK C++ bindings  1.5.2
This is the C++ bindings documentation for PMDK's libpmemobj.
transaction.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-2018, 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_CPP_TRANSACTION_HPP
39 #define LIBPMEMOBJ_CPP_TRANSACTION_HPP
40 
41 #include <functional>
42 #include <string>
43 
46 #include <libpmemobj++/pool.hpp>
47 #include <libpmemobj/tx_base.h>
48 
49 namespace pmem
50 {
51 
52 namespace obj
53 {
54 
72 class transaction {
73 public:
92  class manual {
93  public:
107  template <typename... L>
108  manual(obj::pool_base &pop, L &... locks)
109  {
110  if (pmemobj_tx_begin(pop.handle(), nullptr,
111  TX_PARAM_NONE) != 0)
112  throw transaction_error(
113  "failed to start transaction");
114 
115  auto err = add_lock(locks...);
116 
117  if (err) {
118  pmemobj_tx_abort(EINVAL);
119  (void)pmemobj_tx_end();
120  throw transaction_error("failed to"
121  " add lock");
122  }
123  }
124 
132  ~manual() noexcept
133  {
134  /* normal exit or with an active exception */
135  if (pmemobj_tx_stage() == TX_STAGE_WORK)
136  pmemobj_tx_abort(ECANCELED);
137 
138  (void)pmemobj_tx_end();
139  }
140 
144  manual(const manual &p) = delete;
145 
149  manual(const manual &&p) = delete;
150 
154  manual &operator=(const manual &p) = delete;
155 
159  manual &operator=(manual &&p) = delete;
160  };
161 
162 /*
163  * XXX The Microsoft compiler does not follow the ISO SD-6: SG10 Feature
164  * Test Recommendations. "|| _MSC_VER >= 1900" is a workaround.
165  */
166 #if __cpp_lib_uncaught_exceptions || _MSC_VER >= 1900
167 
186  class automatic {
187  public:
205  template <typename... L>
206  automatic(obj::pool_base &pop, L &... locks)
207  : tx_worker(pop, locks...)
208  {
209  }
210 
221  ~automatic() noexcept(false)
222  {
223  /* active exception, abort handled by tx_worker */
224  if (exceptions.new_uncaught_exception())
225  return;
226 
227  /* transaction ended normally */
228  if (pmemobj_tx_stage() == TX_STAGE_WORK)
229  pmemobj_tx_commit();
230  /* transaction aborted, throw an exception */
231  else if (pmemobj_tx_stage() == TX_STAGE_ONABORT ||
232  (pmemobj_tx_stage() == TX_STAGE_FINALLY &&
233  pmemobj_tx_errno() != 0))
234  throw transaction_error("Transaction aborted");
235  }
236 
240  automatic(const automatic &p) = delete;
241 
245  automatic(const automatic &&p) = delete;
246 
250  automatic &operator=(const automatic &p) = delete;
251 
256 
257  private:
262  public:
270  : count(std::uncaught_exceptions())
271  {
272  }
273 
281  bool
283  {
284  return std::uncaught_exceptions() > this->count;
285  }
286 
287  private:
291  int count;
292  } exceptions;
293 
294  transaction::manual tx_worker;
295  };
296 #endif /* __cpp_lib_uncaught_exceptions */
297 
298  /*
299  * Deleted default constructor.
300  */
301  transaction() = delete;
302 
309  ~transaction() noexcept = delete;
310 
325  static void
326  abort(int err)
327  {
328  if (pmemobj_tx_stage() != TX_STAGE_WORK)
329  throw transaction_error("wrong stage for"
330  " abort");
331 
332  pmemobj_tx_abort(err);
333  throw manual_tx_abort("explicit abort " + std::to_string(err));
334  }
335 
346  static void
348  {
349  if (pmemobj_tx_stage() != TX_STAGE_WORK)
350  throw transaction_error("wrong stage for"
351  " commit");
352 
353  pmemobj_tx_commit();
354  }
355 
356  static int
357  error() noexcept
358  {
359  return pmemobj_tx_errno();
360  }
361 
362  POBJ_CPP_DEPRECATED static int
363  get_last_tx_error() noexcept
364  {
365  return transaction::error();
366  }
367 
399  template <typename... Locks>
400  static void
401  run(pool_base &pool, std::function<void()> tx, Locks &... locks)
402  {
403  if (pmemobj_tx_begin(pool.handle(), nullptr, TX_PARAM_NONE) !=
404  0)
405  throw transaction_error("failed to start transaction");
406 
407  auto err = add_lock(locks...);
408 
409  if (err) {
410  pmemobj_tx_abort(err);
411  (void)pmemobj_tx_end();
412  throw transaction_error("failed to add a lock to the"
413  " transaction");
414  }
415 
416  try {
417  tx();
418  } catch (manual_tx_abort &) {
419  (void)pmemobj_tx_end();
420  throw;
421  } catch (...) {
422  /* first exception caught */
423  if (pmemobj_tx_stage() == TX_STAGE_WORK)
424  pmemobj_tx_abort(ECANCELED);
425 
426  /* waterfall tx_end for outer tx */
427  (void)pmemobj_tx_end();
428  throw;
429  }
430 
431  auto stage = pmemobj_tx_stage();
432 
433  if (stage == TX_STAGE_WORK) {
434  pmemobj_tx_commit();
435  } else if (stage == TX_STAGE_ONABORT) {
436  (void)pmemobj_tx_end();
437  throw transaction_error("transaction aborted");
438  } else if (stage == TX_STAGE_NONE) {
439  throw transaction_error("transaction ended"
440  "prematurely");
441  }
442 
443  (void)pmemobj_tx_end();
444  }
445 
446  template <typename... Locks>
447  POBJ_CPP_DEPRECATED static void
448  exec_tx(pool_base &pool, std::function<void()> tx, Locks &... locks)
449  {
450  transaction::run(pool, tx, locks...);
451  }
452 
453 private:
466  template <typename L, typename... Locks>
467  static int
468  add_lock(L &lock, Locks &... locks) noexcept
469  {
470  auto err =
471  pmemobj_tx_lock(lock.lock_type(), lock.native_handle());
472 
473  if (err)
474  return err;
475 
476  return add_lock(locks...);
477  }
478 
482  static inline int
483  add_lock() noexcept
484  {
485  return 0;
486  }
487 };
488 
489 } /* namespace obj */
490 
491 } /* namespace pmem */
492 
493 #endif /* LIBPMEMOBJ_CPP_TRANSACTION_HPP */
pmem::obj::transaction::automatic::automatic
automatic(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:206
pmem::obj::transaction::automatic::uncaught_exception_counter::count
int count
The number of active exceptions.
Definition: transaction.hpp:291
pmem::obj::transaction::commit
static void commit()
Manually commit a transaction.
Definition: transaction.hpp:347
pmem::obj::transaction::manual::operator=
manual & operator=(manual &&p)=delete
Deleted move assignment operator.
pmem::transaction_error
Custom transaction error class.
Definition: pexceptions.hpp:63
pmem::obj::transaction::automatic::operator=
automatic & operator=(const automatic &p)=delete
Deleted assignment operator.
common.hpp
Commonly used functionality.
pmem::obj::transaction::add_lock
static int add_lock(L &lock, Locks &... locks) noexcept
Recursively add locks to the active transaction.
Definition: transaction.hpp:468
pmem::obj::transaction::manual::~manual
~manual() noexcept
Destructor.
Definition: transaction.hpp:132
pexceptions.hpp
Custom exceptions.
pmem::obj::p
Resides on pmem class.
Definition: p.hpp:64
pmem::obj::transaction::manual::manual
manual(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:108
pool.hpp
C++ pmemobj pool.
pmem::obj::transaction::run
static void run(pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:401
pmem::obj::transaction::add_lock
static int add_lock() noexcept
Method ending the recursive algorithm.
Definition: transaction.hpp:483
pmem::obj::transaction::automatic::operator=
automatic & operator=(automatic &&p)=delete
Deleted move assignment operator.
pmem::obj::transaction::automatic::automatic
automatic(const automatic &p)=delete
Deleted copy constructor.
pmem::obj::transaction::automatic
C++ automatic scope transaction class.
Definition: transaction.hpp:186
pmem::obj::transaction::automatic::uncaught_exception_counter
Internal class for counting active exceptions.
Definition: transaction.hpp:261
pmem::obj::transaction::automatic::uncaught_exception_counter::new_uncaught_exception
bool new_uncaught_exception()
Notifies is a new exception is being handled.
Definition: transaction.hpp:282
pmem::obj::transaction::automatic::uncaught_exception_counter::uncaught_exception_counter
uncaught_exception_counter()
Default constructor.
Definition: transaction.hpp:269
pmem::obj::pool
PMEMobj pool class.
Definition: pool.hpp:430
pmem::obj::transaction::manual::operator=
manual & operator=(const manual &p)=delete
Deleted assignment operator.
pmem::obj::transaction::~transaction
~transaction() noexcept=delete
Default destructor.
pmem::obj::transaction::automatic::~automatic
~automatic() noexcept(false)
Destructor.
Definition: transaction.hpp:221
pmem::obj::transaction::manual::manual
manual(const manual &p)=delete
Deleted copy constructor.
pmem::obj::transaction
C++ transaction handler class.
Definition: transaction.hpp:72
pmem::manual_tx_abort
Custom transaction error class.
Definition: pexceptions.hpp:114
pmem::obj::pool_base
The non-template pool base class.
Definition: pool.hpp:66
pmem::obj::transaction::automatic::automatic
automatic(const automatic &&p)=delete
Deleted move constructor.
pmem::obj::transaction::abort
static void abort(int err)
Manually abort the current transaction.
Definition: transaction.hpp:326
pmem::obj::transaction::manual
C++ manual scope transaction class.
Definition: transaction.hpp:92
pmem::obj::transaction::manual::manual
manual(const manual &&p)=delete
Deleted move constructor.