NVML C++ bindings  0.1 experimental
This is the C++ bindings documentation for NVML's libpmemobj.
transaction.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016, 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 nvml
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_LOCK_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  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  {
206  if (pmemobj_tx_begin(pop.get_handle(), NULL,
207  TX_LOCK_NONE) != 0)
208  throw transaction_error(
209  "failed to start transaction");
210 
211  auto err = add_lock(locks...);
212 
213  if (err) {
214  pmemobj_tx_abort(EINVAL);
215  throw transaction_error("failed to add"
216  " lock");
217  }
218  }
219 
227  ~automatic() noexcept
228  {
229  /* manual abort or commit end transaction */
230  if (pmemobj_tx_stage() != TX_STAGE_WORK) {
231  pmemobj_tx_end();
232  return;
233  }
234 
235  if (this->exceptions.new_uncaught_exception())
236  /* exit with an active exception */
237  pmemobj_tx_abort(ECANCELED);
238  else
239  /* normal exit commit tx */
240  pmemobj_tx_commit();
241 
242  pmemobj_tx_end();
243  }
244 
248  automatic(const automatic &p) = delete;
249 
253  automatic(const automatic &&p) = delete;
254 
258  automatic &operator=(const automatic &p) = delete;
259 
263  automatic &operator=(automatic &&p) = delete;
264 
265  private:
270  public:
278  : count(std::uncaught_exceptions())
279  {
280  }
281 
289  bool
291  {
292  return std::uncaught_exceptions() > this->count;
293  }
294 
295  private:
299  int count;
300  } exceptions;
301  };
302 #endif /* __cpp_lib_uncaught_exceptions */
303 
304  /*
305  * Deleted default constructor.
306  */
307  transaction() = delete;
308 
315  ~transaction() noexcept = delete;
316 
331  static void
332  abort(int err)
333  {
334  if (pmemobj_tx_stage() != TX_STAGE_WORK)
335  throw transaction_error("wrong stage for"
336  " abort");
337 
338  pmemobj_tx_abort(err);
339  throw manual_tx_abort("explicit abort " + std::to_string(err));
340  }
341 
352  static void
354  {
355  if (pmemobj_tx_stage() != TX_STAGE_WORK)
356  throw transaction_error("wrong stage for"
357  " commit");
358 
359  pmemobj_tx_commit();
360  }
361 
362  static int
363  get_last_tx_error() noexcept
364  {
365  return pmemobj_tx_errno();
366  }
367 
399  template <typename... Locks>
400  static void
401  exec_tx(pool_base &pool, std::function<void()> tx, Locks &... locks)
402  {
403  if (pmemobj_tx_begin(pool.get_handle(), NULL, TX_LOCK_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  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  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  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  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  pmemobj_tx_end();
444  }
445 
446 private:
459  template <typename L, typename... Locks>
460  static int
461  add_lock(L &lock, Locks &... locks) noexcept
462  {
463  auto err =
464  pmemobj_tx_lock(lock.lock_type(), lock.native_handle());
465 
466  if (err)
467  return err;
468 
469  return add_lock(locks...);
470  }
471 
475  static inline int
476  add_lock() noexcept
477  {
478  return 0;
479  }
480 };
481 
482 } /* namespace obj */
483 
484 } /* namespace nvml */
485 
486 #endif /* LIBPMEMOBJ_TRANSACTION_HPP */
static int add_lock(L &lock, Locks &...locks) noexcept
Recursively add locks to the active transaction.
Definition: transaction.hpp:461
C++ automatic scope transaction class.
Definition: transaction.hpp:184
static int add_lock() noexcept
Method ending the recursive algorithm.
Definition: transaction.hpp:476
static void abort(int err)
Manually abort the current transaction.
Definition: transaction.hpp:332
Internal class for counting active exceptions.
Definition: transaction.hpp:269
manual & operator=(const manual &p)=delete
Deleted assignment operator.
The non-template pool base class.
Definition: pool.hpp:64
bool new_uncaught_exception()
Notifies is a new exception is being handled.
Definition: transaction.hpp:290
Custom transaction error class.
Definition: pexceptions.hpp:104
Custom exceptions.
manual(obj::pool_base &pop, L &...locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:107
Custom transaction error class.
Definition: pexceptions.hpp:63
~transaction() noexcept=delete
Default destructor.
~automatic() noexcept
Destructor.
Definition: transaction.hpp:227
PMEMobj pool class.
Definition: persistent_ptr.hpp:55
C++ manual scope transaction class.
Definition: transaction.hpp:91
int count
The number of active exceptions.
Definition: transaction.hpp:299
Resides on pmem class.
Definition: p.hpp:64
static void exec_tx(pool_base &pool, std::function< void()> tx, Locks &...locks)
Execute a closure-like transaction and lock locks.
Definition: transaction.hpp:401
automatic(obj::pool_base &pop, L &...locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:204
Definition: condition_variable.hpp:48
~manual() noexcept
Destructor.
Definition: transaction.hpp:130
C++ transaction handler class.
Definition: transaction.hpp:71
uncaught_exception_counter()
Default constructor.
Definition: transaction.hpp:277
static void commit()
Manually commit a transaction.
Definition: transaction.hpp:353
C++ pmemobj pool.