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-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  throw transaction_error("failed to"
120  " add lock");
121  }
122  }
123 
131  ~manual() noexcept
132  {
133  /* normal exit or with an active exception */
134  if (pmemobj_tx_stage() == TX_STAGE_WORK)
135  pmemobj_tx_abort(ECANCELED);
136 
137  (void)pmemobj_tx_end();
138  }
139 
143  manual(const manual &p) = delete;
144 
148  manual(const manual &&p) = delete;
149 
153  manual &operator=(const manual &p) = delete;
154 
158  manual &operator=(manual &&p) = delete;
159  };
160 
161 /*
162  * XXX The Microsoft compiler does not follow the ISO SD-6: SG10 Feature
163  * Test Recommendations. "|| _MSC_VER >= 1900" is a workaround.
164  */
165 #if __cpp_lib_uncaught_exceptions || _MSC_VER >= 1900
166 
185  class automatic {
186  public:
204  template <typename... L>
205  automatic(obj::pool_base &pop, L &... locks)
206  : tx_worker(pop, locks...)
207  {
208  }
209 
220  ~automatic() noexcept(false)
221  {
222  /* active exception, abort handled by tx_worker */
223  if (exceptions.new_uncaught_exception())
224  return;
225 
226  /* transaction ended normally */
227  if (pmemobj_tx_stage() == TX_STAGE_WORK)
228  pmemobj_tx_commit();
229  /* transaction aborted, throw an exception */
230  else if (pmemobj_tx_stage() == TX_STAGE_ONABORT ||
231  (pmemobj_tx_stage() == TX_STAGE_FINALLY &&
232  pmemobj_tx_errno() != 0))
233  throw transaction_error("Transaction aborted");
234  }
235 
239  automatic(const automatic &p) = delete;
240 
244  automatic(const automatic &&p) = delete;
245 
249  automatic &operator=(const automatic &p) = delete;
250 
254  automatic &operator=(automatic &&p) = delete;
255 
256  private:
261  public:
269  : count(std::uncaught_exceptions())
270  {
271  }
272 
280  bool
282  {
283  return std::uncaught_exceptions() > this->count;
284  }
285 
286  private:
290  int count;
291  } exceptions;
292 
293  transaction::manual tx_worker;
294  };
295 #endif /* __cpp_lib_uncaught_exceptions */
296 
297  /*
298  * Deleted default constructor.
299  */
300  transaction() = delete;
301 
308  ~transaction() noexcept = delete;
309 
324  static void
325  abort(int err)
326  {
327  if (pmemobj_tx_stage() != TX_STAGE_WORK)
328  throw transaction_error("wrong stage for"
329  " abort");
330 
331  pmemobj_tx_abort(err);
332  throw manual_tx_abort("explicit abort " + std::to_string(err));
333  }
334 
345  static void
347  {
348  if (pmemobj_tx_stage() != TX_STAGE_WORK)
349  throw transaction_error("wrong stage for"
350  " commit");
351 
352  pmemobj_tx_commit();
353  }
354 
355  static int
356  error() noexcept
357  {
358  return pmemobj_tx_errno();
359  }
360 
361  POBJ_CPP_DEPRECATED static int
362  get_last_tx_error() noexcept
363  {
364  return transaction::error();
365  }
366 
398  template <typename... Locks>
399  static void
400  run(pool_base &pool, std::function<void()> tx, Locks &... locks)
401  {
402  if (pmemobj_tx_begin(pool.handle(), nullptr, TX_PARAM_NONE) !=
403  0)
404  throw transaction_error("failed to start transaction");
405 
406  auto err = add_lock(locks...);
407 
408  if (err) {
409  pmemobj_tx_abort(err);
410  (void)pmemobj_tx_end();
411  throw transaction_error("failed to add a lock to the"
412  " transaction");
413  }
414 
415  try {
416  tx();
417  } catch (manual_tx_abort &) {
418  (void)pmemobj_tx_end();
419  throw;
420  } catch (...) {
421  /* first exception caught */
422  if (pmemobj_tx_stage() == TX_STAGE_WORK)
423  pmemobj_tx_abort(ECANCELED);
424 
425  /* waterfall tx_end for outer tx */
426  (void)pmemobj_tx_end();
427  throw;
428  }
429 
430  auto stage = pmemobj_tx_stage();
431 
432  if (stage == TX_STAGE_WORK) {
433  pmemobj_tx_commit();
434  } else if (stage == TX_STAGE_ONABORT) {
435  (void)pmemobj_tx_end();
436  throw transaction_error("transaction aborted");
437  } else if (stage == TX_STAGE_NONE) {
438  throw transaction_error("transaction ended"
439  "prematurely");
440  }
441 
442  (void)pmemobj_tx_end();
443  }
444 
445  template <typename... Locks>
446  POBJ_CPP_DEPRECATED static void
447  exec_tx(pool_base &pool, std::function<void()> tx, Locks &... locks)
448  {
449  transaction::run(pool, tx, locks...);
450  }
451 
452 private:
465  template <typename L, typename... Locks>
466  static int
467  add_lock(L &lock, Locks &... locks) noexcept
468  {
469  auto err =
470  pmemobj_tx_lock(lock.lock_type(), lock.native_handle());
471 
472  if (err)
473  return err;
474 
475  return add_lock(locks...);
476  }
477 
481  static inline int
482  add_lock() noexcept
483  {
484  return 0;
485  }
486 };
487 
488 } /* namespace obj */
489 
490 } /* namespace pmem */
491 
492 #endif /* LIBPMEMOBJ_CPP_TRANSACTION_HPP */
int count
The number of active exceptions.
Definition: transaction.hpp:290
static int add_lock() noexcept
Method ending the recursive algorithm.
Definition: transaction.hpp:482
The non-template pool base class.
Definition: pool.hpp:66
Internal class for counting active exceptions.
Definition: transaction.hpp:260
~manual() noexcept
Destructor.
Definition: transaction.hpp:131
~automatic() noexcept(false)
Destructor.
Definition: transaction.hpp:220
C++ transaction handler class.
Definition: transaction.hpp:72
Custom transaction error class.
Definition: pexceptions.hpp:114
Definition: pext.hpp:342
C++ manual scope transaction class.
Definition: transaction.hpp:92
PMEMobj pool class.
Definition: persistent_ptr.hpp:59
manual & operator=(const manual &p)=delete
Deleted assignment operator.
manual(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:108
Commonly used functionality.
Custom exceptions.
static void commit()
Manually commit a transaction.
Definition: transaction.hpp:346
static void abort(int err)
Manually abort the current transaction.
Definition: transaction.hpp:325
~transaction() noexcept=delete
Default destructor.
C++ automatic scope transaction class.
Definition: transaction.hpp:185
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:467
bool new_uncaught_exception()
Notifies is a new exception is being handled.
Definition: transaction.hpp:281
automatic(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:205
uncaught_exception_counter()
Default constructor.
Definition: transaction.hpp:268
Resides on pmem class.
Definition: p.hpp:64
Definition: allocator.hpp:48
C++ pmemobj pool.
static void run(pool_base &pool, std::function< void()> tx, Locks &... locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:400