transaction.hpp
Go to the documentation of this file.
/*
* Copyright 2016-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBPMEMOBJ_TRANSACTION_HPP
#define LIBPMEMOBJ_TRANSACTION_HPP
#include <functional>
#include <string>
#include "libpmemobj++/detail/pexceptions.hpp"
#include "libpmemobj++/pool.hpp"
#include "libpmemobj/tx_base.h"
namespace pmem
{
namespace obj
{
class transaction {
public:
class manual {
public:
template <typename... L>
manual(obj::pool_base &pop, L &... locks)
{
if (pmemobj_tx_begin(pop.get_handle(), NULL,
TX_PARAM_NONE) != 0)
throw transaction_error(
"failed to start transaction");
auto err = add_lock(locks...);
if (err) {
pmemobj_tx_abort(EINVAL);
throw transaction_error("failed to"
" add lock");
}
}
~manual() noexcept
{
/* normal exit or with an active exception */
if (pmemobj_tx_stage() == TX_STAGE_WORK)
pmemobj_tx_abort(ECANCELED);
(void)pmemobj_tx_end();
}
manual(const manual &p) = delete;
manual(const manual &&p) = delete;
manual &operator=(const manual &p) = delete;
manual &operator=(manual &&p) = delete;
};
/*
* XXX The Microsoft compiler does not follow the ISO SD-6: SG10 Feature
* Test Recommendations. "|| _MSC_VER >= 1900" is a workaround.
*/
#if __cpp_lib_uncaught_exceptions || _MSC_VER >= 1900
class automatic {
public:
template <typename... L>
automatic(obj::pool_base &pop, L &... locks)
: tx_worker(pop, locks...)
{
}
~automatic() noexcept(false)
{
/* active exception, abort handled by tx_worker */
if (exceptions.new_uncaught_exception())
return;
/* transaction ended normally */
if (pmemobj_tx_stage() == TX_STAGE_WORK)
pmemobj_tx_commit();
/* transaction aborted, throw an exception */
else if (pmemobj_tx_stage() == TX_STAGE_ONABORT ||
(pmemobj_tx_stage() == TX_STAGE_FINALLY &&
pmemobj_tx_errno() != 0))
throw transaction_error("Transaction aborted");
}
automatic(const automatic &p) = delete;
automatic(const automatic &&p) = delete;
automatic &operator=(const automatic &p) = delete;
automatic &operator=(automatic &&p) = delete;
private:
class uncaught_exception_counter {
public:
uncaught_exception_counter()
: count(std::uncaught_exceptions())
{
}
bool
new_uncaught_exception()
{
return std::uncaught_exceptions() > this->count;
}
private:
int count;
} exceptions;
transaction::manual tx_worker;
};
#endif /* __cpp_lib_uncaught_exceptions */
/*
* Deleted default constructor.
*/
transaction() = delete;
~transaction() noexcept = delete;
static void
abort(int err)
{
if (pmemobj_tx_stage() != TX_STAGE_WORK)
throw transaction_error("wrong stage for"
" abort");
pmemobj_tx_abort(err);
throw manual_tx_abort("explicit abort " + std::to_string(err));
}
static void
commit()
{
if (pmemobj_tx_stage() != TX_STAGE_WORK)
throw transaction_error("wrong stage for"
" commit");
pmemobj_tx_commit();
}
static int
get_last_tx_error() noexcept
{
return pmemobj_tx_errno();
}
template <typename... Locks>
static void
exec_tx(pool_base &pool, std::function<void()> tx, Locks &... locks)
{
if (pmemobj_tx_begin(pool.get_handle(), NULL, TX_PARAM_NONE) !=
0)
throw transaction_error("failed to start transaction");
auto err = add_lock(locks...);
if (err) {
pmemobj_tx_abort(err);
(void)pmemobj_tx_end();
throw transaction_error("failed to add a lock to the"
" transaction");
}
try {
tx();
} catch (manual_tx_abort &) {
(void)pmemobj_tx_end();
throw;
} catch (...) {
/* first exception caught */
if (pmemobj_tx_stage() == TX_STAGE_WORK)
pmemobj_tx_abort(ECANCELED);
/* waterfall tx_end for outer tx */
(void)pmemobj_tx_end();
throw;
}
auto stage = pmemobj_tx_stage();
if (stage == TX_STAGE_WORK) {
pmemobj_tx_commit();
} else if (stage == TX_STAGE_ONABORT) {
(void)pmemobj_tx_end();
throw transaction_error("transaction aborted");
} else if (stage == TX_STAGE_NONE) {
throw transaction_error("transaction ended"
"prematurely");
}
(void)pmemobj_tx_end();
}
private:
template <typename L, typename... Locks>
static int
add_lock(L &lock, Locks &... locks) noexcept
{
auto err =
pmemobj_tx_lock(lock.lock_type(), lock.native_handle());
if (err)
return err;
return add_lock(locks...);
}
static inline int
add_lock() noexcept
{
return 0;
}
};
} /* namespace obj */
} /* namespace pmem */
#endif /* LIBPMEMOBJ_TRANSACTION_HPP */
pmem::obj::transaction::automatic::uncaught_exception_counter::count
int count
The number of active exceptions.
Definition: transaction.hpp:289
pmem::obj::transaction::add_lock
static int add_lock() noexcept
Method ending the recursive algorithm.
Definition: transaction.hpp:468
pmem::obj::pool_base
The non-template pool base class.
Definition: pool.hpp:65
pmem::obj::transaction::automatic::uncaught_exception_counter
Internal class for counting active exceptions.
Definition: transaction.hpp:259
pmem::obj::transaction::manual::~manual
~manual() noexcept
Destructor.
Definition: transaction.hpp:130
pmem::obj::transaction::automatic::~automatic
~automatic() noexcept(false)
Destructor.
Definition: transaction.hpp:219
pmem::obj::transaction
C++ transaction handler class.
Definition: transaction.hpp:71
pmem::manual_tx_abort
Custom transaction error class.
Definition: pexceptions.hpp:114
std
Definition: pext.hpp:338
pmem::obj::transaction::manual
C++ manual scope transaction class.
Definition: transaction.hpp:91
pmem::obj::pool
PMEMobj pool class.
Definition: persistent_ptr.hpp:59
pmem::obj::transaction::manual::operator=
manual & operator=(const manual &p)=delete
Deleted assignment operator.
pmem::obj::transaction::exec_tx
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
pmem::obj::transaction::manual::manual
manual(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:107
pexceptions.hpp
Custom exceptions.
pmem::obj::transaction::commit
static void commit()
Manually commit a transaction.
Definition: transaction.hpp:345
pmem::obj::transaction::abort
static void abort(int err)
Manually abort the current transaction.
Definition: transaction.hpp:324
pmem::obj::transaction::~transaction
~transaction() noexcept=delete
Default destructor.
pmem::obj::transaction::automatic
C++ automatic scope transaction class.
Definition: transaction.hpp:184
pmem::transaction_error
Custom transaction error class.
Definition: pexceptions.hpp:63
pmem::obj::transaction::add_lock
static int add_lock(L &lock, Locks &... locks) noexcept
Recursively add locks to the active transaction.
Definition: transaction.hpp:453
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:280
pmem::obj::transaction::automatic::automatic
automatic(obj::pool_base &pop, L &... locks)
RAII constructor with pmem resident locks.
Definition: transaction.hpp:204
pmem::obj::transaction::automatic::uncaught_exception_counter::uncaught_exception_counter
uncaught_exception_counter()
Default constructor.
Definition: transaction.hpp:267
pmem::obj::p
Resides on pmem class.
Definition: p.hpp:64
pmem
Definition: allocator.hpp:48
pool.hpp
C++ pmemobj pool.