PMDK C++ bindings  1.8.2
This is the C++ bindings documentation for PMDK's libpmemobj.
transaction.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-2019, 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)
113  "failed to start transaction")
114  .with_pmemobj_errormsg();
115 
116  auto err = add_lock(locks...);
117 
118  if (err) {
119  pmemobj_tx_abort(EINVAL);
120  (void)pmemobj_tx_end();
122  "failed to add lock")
123  .with_pmemobj_errormsg();
124  }
125  }
126 
134  ~manual() noexcept
135  {
136  /* normal exit or with an active exception */
137  if (pmemobj_tx_stage() == TX_STAGE_WORK)
138  pmemobj_tx_abort(ECANCELED);
139 
140  (void)pmemobj_tx_end();
141  }
142 
146  manual(const manual &p) = delete;
147 
151  manual(const manual &&p) = delete;
152 
156  manual &operator=(const manual &p) = delete;
157 
161  manual &operator=(manual &&p) = delete;
162  };
163 
164 /*
165  * XXX The Microsoft compiler does not follow the ISO SD-6: SG10 Feature
166  * Test Recommendations. "|| _MSC_VER >= 1900" is a workaround.
167  */
168 #if __cpp_lib_uncaught_exceptions || _MSC_VER >= 1900
169 
188  class automatic {
189  public:
207  template <typename... L>
208  automatic(obj::pool_base &pop, L &... locks)
209  : tx_worker(pop, locks...)
210  {
211  }
212 
223  ~automatic() noexcept(false)
224  {
225  /* active exception, abort handled by tx_worker */
226  if (exceptions.new_uncaught_exception())
227  return;
228 
229  /* transaction ended normally */
230  if (pmemobj_tx_stage() == TX_STAGE_WORK)
231  pmemobj_tx_commit();
232  /* transaction aborted, throw an exception */
233  else if (pmemobj_tx_stage() == TX_STAGE_ONABORT ||
234  (pmemobj_tx_stage() == TX_STAGE_FINALLY &&
235  pmemobj_tx_errno() != 0))
237  "Transaction aborted");
238  }
239 
243  automatic(const automatic &p) = delete;
244 
248  automatic(const automatic &&p) = delete;
249 
253  automatic &operator=(const automatic &p) = delete;
254 
258  automatic &operator=(automatic &&p) = delete;
259 
260  private:
265  public:
273  : count(std::uncaught_exceptions())
274  {
275  }
276 
284  bool
286  {
287  return std::uncaught_exceptions() > this->count;
288  }
289 
290  private:
294  int count;
295  } exceptions;
296 
297  transaction::manual tx_worker;
298  };
299 #endif /* __cpp_lib_uncaught_exceptions */
300 
301  /*
302  * Deleted default constructor.
303  */
304  transaction() = delete;
305 
312  ~transaction() noexcept = delete;
313 
328  static void
329  abort(int err)
330  {
331  if (pmemobj_tx_stage() != TX_STAGE_WORK)
332  throw pmem::transaction_error("wrong stage for abort");
333 
334  pmemobj_tx_abort(err);
335  throw pmem::manual_tx_abort("explicit abort " +
336  std::to_string(err));
337  }
338 
349  static void
351  {
352  if (pmemobj_tx_stage() != TX_STAGE_WORK)
353  throw pmem::transaction_error("wrong stage for commit");
354 
355  pmemobj_tx_commit();
356  }
357 
358  static int
359  error() noexcept
360  {
361  return pmemobj_tx_errno();
362  }
363 
364  POBJ_CPP_DEPRECATED static int
365  get_last_tx_error() noexcept
366  {
367  return transaction::error();
368  }
369 
401  template <typename... Locks>
402  static void
403  run(pool_base &pool, std::function<void()> tx, Locks &... locks)
404  {
405  if (pmemobj_tx_begin(pool.handle(), nullptr, TX_PARAM_NONE) !=
406  0)
408  "failed to start transaction")
409  .with_pmemobj_errormsg();
410 
411  auto err = add_lock(locks...);
412 
413  if (err) {
414  pmemobj_tx_abort(err);
415  (void)pmemobj_tx_end();
417  "failed to add a lock to the transaction")
418  .with_pmemobj_errormsg();
419  }
420 
421  try {
422  tx();
423  } catch (manual_tx_abort &) {
424  (void)pmemobj_tx_end();
425  throw;
426  } catch (...) {
427  /* first exception caught */
428  if (pmemobj_tx_stage() == TX_STAGE_WORK)
429  pmemobj_tx_abort(ECANCELED);
430 
431  /* waterfall tx_end for outer tx */
432  (void)pmemobj_tx_end();
433  throw;
434  }
435 
436  auto stage = pmemobj_tx_stage();
437 
438  if (stage == TX_STAGE_WORK) {
439  pmemobj_tx_commit();
440  } else if (stage == TX_STAGE_ONABORT) {
441  (void)pmemobj_tx_end();
442  throw pmem::transaction_error("transaction aborted");
443  } else if (stage == TX_STAGE_NONE) {
445  "transaction ended prematurely");
446  }
447 
448  (void)pmemobj_tx_end();
449  }
450 
451  template <typename... Locks>
452  POBJ_CPP_DEPRECATED static void
453  exec_tx(pool_base &pool, std::function<void()> tx, Locks &... locks)
454  {
455  transaction::run(pool, tx, locks...);
456  }
457 
478  template <
479  typename T,
480  typename std::enable_if<LIBPMEMOBJ_CPP_IS_TRIVIALLY_COPYABLE(T),
481  T>::type * = nullptr>
482  static void
483  snapshot(const T *addr, size_t num = 1)
484  {
485  if (TX_STAGE_WORK != pmemobj_tx_stage())
487  "wrong stage for taking a snapshot.");
488 
489  if (pmemobj_tx_add_range_direct(addr, sizeof(*addr) * num)) {
490  if (errno == ENOMEM)
492  "Could not take a snapshot of given memory range.")
493  .with_pmemobj_errormsg();
494  else
496  "Could not take a snapshot of given memory range.")
497  .with_pmemobj_errormsg();
498  }
499  }
500 
501 private:
514  template <typename L, typename... Locks>
515  static int
516  add_lock(L &lock, Locks &... locks) noexcept
517  {
518  auto err =
519  pmemobj_tx_lock(lock.lock_type(), lock.native_handle());
520 
521  if (err)
522  return err;
523 
524  return add_lock(locks...);
525  }
526 
530  static inline int
531  add_lock() noexcept
532  {
533  return 0;
534  }
535 };
536 
537 } /* namespace obj */
538 
539 } /* namespace pmem */
540 
541 #endif /* LIBPMEMOBJ_CPP_TRANSACTION_HPP */
int count
The number of active exceptions.
Definition: transaction.hpp:294
static int add_lock() noexcept
Method ending the recursive algorithm.
Definition: transaction.hpp:531
The non-template pool base class.
Definition: pool.hpp:67
Internal class for counting active exceptions.
Definition: transaction.hpp:264
~manual() noexcept
Destructor.
Definition: transaction.hpp:134
~automatic() noexcept(false)
Destructor.
Definition: transaction.hpp:223
C++ transaction handler class.
Definition: transaction.hpp:72
Custom transaction error class.
Definition: pexceptions.hpp:195
A persistent version of concurrent hash map implementation Ref: https://arxiv.org/abs/1509....
Definition: concurrent_hash_map.hpp:65
static void snapshot(const T *addr, size_t num=1)
Takes a “snapshot” of given elements of type T number (1 by default), located at the given address pt...
Definition: transaction.hpp:483
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.
PMEMobjpool * handle() noexcept
Gets the C style handle to the pool.
Definition: pool.hpp:403
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:350
static void abort(int err)
Manually abort the current transaction.
Definition: transaction.hpp:329
~transaction() noexcept=delete
Default destructor.
C++ automatic scope transaction class.
Definition: transaction.hpp:188
Custom transaction error class.
Definition: pexceptions.hpp:90
Custom out of memory error class.
Definition: pexceptions.hpp:146
static int add_lock(L &lock, Locks &... locks) noexcept
Recursively add locks to the active transaction.
Definition: transaction.hpp:516
bool new_uncaught_exception()
Notifies is a new exception is being handled.
Definition: transaction.hpp:285
automatic(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:208
uncaught_exception_counter()
Default constructor.
Definition: transaction.hpp:272
Resides on pmem class.
Definition: p.hpp:64
A persistent version of concurrent hash map implementation Ref: https://arxiv.org/abs/1509....
Definition: allocation_flag.hpp:43
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:403
automatic & operator=(const automatic &p)=delete
Deleted assignment operator.