Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
PMEMOBJ_TX_BEGIN(3)	   PMDK	Programmer's Manual	   PMEMOBJ_TX_BEGIN(3)

NAME
       pmemobj_tx_stage(),

       pmemobj_tx_begin(),   pmemobj_tx_lock(),	  pmemobj_tx_abort(),	pmemo-
       bj_tx_commit(),	  pmemobj_tx_end(),	pmemobj_tx_errno(),	pmemo-
       bj_tx_process(),

       TX_BEGIN_PARAM(),  TX_BEGIN_CB(),  TX_BEGIN(), TX_ONABORT, TX_ONCOMMIT,
       TX_FINALLY, TX_END - transactional object manipulation

SYNOPSIS
	      #include <libpmemobj.h>

	      enum tx_stage pmemobj_tx_stage(void);

	      int pmemobj_tx_begin(PMEMobjpool *pop, jmp_buf *env, enum	pobj_tx_param, ...);
	      int pmemobj_tx_lock(enum tx_lock lock_type, void *lockp);
	      void pmemobj_tx_abort(int	errnum);
	      void pmemobj_tx_commit(void);
	      int pmemobj_tx_end(void);
	      int pmemobj_tx_errno(void);
	      void pmemobj_tx_process(void);

	      TX_BEGIN_PARAM(PMEMobjpool *pop, ...)
	      TX_BEGIN_CB(PMEMobjpool *pop, cb,	arg, ...)
	      TX_BEGIN(PMEMobjpool *pop)
	      TX_ONABORT
	      TX_ONCOMMIT
	      TX_FINALLY
	      TX_END

DESCRIPTION
       The non-transactional functions and  macros  described  in  pmemobj_al-
       loc(3), pmemobj_list_insert(3) and POBJ_LIST_HEAD(3) only guarantee the
       atomicity of a single operation on an object.  In case of more  complex
       changes	involving  multiple operations on an object, or	allocation and
       modification of multiple	objects, data consistency and fail-safety  may
       be provided only	by using atomic	transactions.

       A  transaction  is defined as series of operations on persistent	memory
       objects that either all occur, or nothing occurs.   In  particular,  if
       the  execution  of a transaction	is interrupted by a power failure or a
       system crash, it	is guaranteed  that  after  system  restart,  all  the
       changes	made  as  a part of the	uncompleted transaction	will be	rolled
       back, restoring the consistent state of the memory pool from the	moment
       when the	transaction was	started.

       Note  that  transactions	do not provide atomicity with respect to other
       threads.	 All the modifications performed within	the  transactions  are
       immediately visible to other threads.  Therefore	it is the responsibil-
       ity of the application to implement  a  proper  thread  synchronization
       mechanism.

       Each  thread  may  have	only  one transaction open at a	time, but that
       transaction may be nested.  Nested transactions are flattened.  Commit-
       ting the	nested transaction does	not commit the outer transaction; how-
       ever, errors in the nested transaction are propagated up	to the	outer-
       most level, resulting in	the interruption of the	entire transaction.

       Each  transaction  is  visible only for the thread that started it.  No
       other threads can add operations, commit	or abort the transaction  ini-
       tiated  by another thread.  Multiple threads may	have transactions open
       on a given memory pool at the same time.

       Please see the CAVEATS section  below  for  known  limitations  of  the
       transactional API.

       The  pmemobj_tx_stage()	function returns the current transaction stage
       for a thread.  Stages are changed only by the pmemobj_tx_*() functions.
       Transaction stages are defined as follows:

       o TX_STAGE_NONE - no open transaction in	this thread

       o TX_STAGE_WORK - transaction in	progress

       o TX_STAGE_ONCOMMIT - successfully committed

       o TX_STAGE_ONABORT  -  starting	the  transaction failed	or transaction
	 aborted

       o TX_STAGE_FINALLY - ready for clean up

       The pmemobj_tx_begin() function starts a	new transaction	in the current
       thread.	 If  called  within  an	 open  transaction, it starts a	nested
       transaction.  The caller	may use	the env	argument to provide a  pointer
       to  a  calling environment to be	restored in case of transaction	abort.
       This information	must be	provided by the	 caller	 using	the  setjmp(3)
       macro.

       A  new  transaction  may	 be  started  only  if	the  current  stage is
       TX_STAGE_NONE or	TX_STAGE_WORK.	If successful, the  transaction	 stage
       changes	 to   TX_STAGE_WORK.   Otherwise,  the	stage  is  changed  to
       TX_STAGE_ONABORT.

       Optionally, a list of parameters	for the	transaction may	 be  provided.
       Each parameter consists of a type followed by a type-specific number of
       values.	Currently there	are 4 types:

       o TX_PARAM_NONE,	used as	a termination marker.  No following value.

       o TX_PARAM_MUTEX, followed by one value,	a pmem-resident	PMEMmutex

       o TX_PARAM_RWLOCK, followed by one value, a pmem-resident PMEMrwlock

       o TX_PARAM_CB, followed by two values:  a  callback  function  of  type
	 pmemobj_tx_callback, and a void pointer

       Using TX_PARAM_MUTEX or TX_PARAM_RWLOCK causes the specified lock to be
       acquired	at the beginning of the	transaction.  TX_PARAM_RWLOCK acquires
       the  lock  for  writing.	 It is guaranteed that pmemobj_tx_begin() will
       acquire all locks prior to successful completion, and they will be held
       by  the	current	 thread	 until	the outermost transaction is finished.
       Locks are taken in order	from left to right.  To	avoid  deadlocks,  the
       user is responsible for proper lock ordering.

       TX_PARAM_CB registers the specified callback function to	be executed at
       each transaction	stage.	For TX_STAGE_WORK, the	callback  is  executed
       prior to	commit.	 For all other stages, the callback is executed	as the
       first operation after a stage change.  It will  also  be	 called	 after
       each  transaction;  in  this  case  the	stage parameter	will be	set to
       TX_STAGE_NONE.  pmemobj_tx_callback must	be compatible with:

       void func(PMEMobjpool *pop, enum	pobj_tx_stage stage, void *arg)

       pop is a	pool identifier	used in	pmemobj_tx_begin(), stage is a current
       transaction  stage  and	arg  is	 the  second parameter of TX_PARAM_CB.
       Without considering transaction nesting,	this mechanism can be  consid-
       ered  an	 alternative method for	executing code between stages (instead
       of TX_ONCOMMIT, TX_ONABORT, etc).  However,  there  are	2  significant
       differences when	nested transactions are	used:

       o The  registered  function  is executed	only in	the outermost transac-
	 tion, even if registered in an	inner transaction.

       o There can be only one callback	in the entire  transaction,  that  is,
	 the callback cannot be	changed	in an inner transaction.

       Note  that  TX_PARAM_CB	does  not replace the TX_ONCOMMIT, TX_ONABORT,
       etc.  macros.  They can be used together: the callback will be executed
       before a	TX_ONCOMMIT, TX_ONABORT, etc.  section.

       TX_PARAM_CB  can	 be  used when the code	dealing	with transaction stage
       changes is shared between multiple users	or when	it  must  be  executed
       only  in	the outer transaction.	For example it can be very useful when
       the application must synchronize	persistent and transient state.

       The  pmemobj_tx_lock()  function	 acquires  the	lock  lockp  of	  type
       lock_type  and  adds  it	 to the	current	transaction.  lock_type	may be
       TX_LOCK_MUTEX or	TX_LOCK_RWLOCK;	lockp must be  of  type	 PMEMmutex  or
       PMEMrwlock,  respectively.   If lock_type is TX_LOCK_RWLOCK the lock is
       acquired	for writing.  If the lock is not  successfully	acquired,  the
       function	 returns an error number.  This	function must be called	during
       TX_STAGE_WORK.

       pmemobj_tx_abort() aborts the current transaction and causes a  transi-
       tion to TX_STAGE_ONABORT.  If errnum is equal to	0, the transaction er-
       ror code	is set to ECANCELED; otherwise,	it is  set  to	errnum.	  This
       function	must be	called during TX_STAGE_WORK.

       The  pmemobj_tx_commit()	 function commits the current open transaction
       and causes a transition to TX_STAGE_ONCOMMIT.  If called	in the context
       of  the	outermost  transaction,	 all  the changes may be considered as
       durably written upon successful	completion.   This  function  must  be
       called during TX_STAGE_WORK.

       The  pmemobj_tx_end() function performs a cleanup of the	current	trans-
       action.	If called in the context of the	outermost transaction, it  re-
       leases all the locks acquired by	pmemobj_tx_begin() for outer and nest-
       ed transactions.	 If called in the context of a nested transaction,  it
       returns to the context of the outer transaction in TX_STAGE_WORK, with-
       out releasing any locks.	 The pmemobj_tx_end() function can  be	called
       during  TX_STAGE_NONE  if  transitioned	to  this  stage	 using	pmemo-
       bj_tx_process().	 If not	already	in TX_STAGE_NONE, it causes the	 tran-
       sition to TX_STAGE_NONE.	 pmemobj_tx_end	must always be called for each
       pmemobj_tx_begin(), even	if  starting  the  transaction	failed.	  This
       function	must not be called during TX_STAGE_WORK.

       The  pmemobj_tx_errno()	function  returns  the	error code of the last
       transaction.

       The pmemobj_tx_process()	function performs the actions associated  with
       the  current  stage of the transaction, and makes the transition	to the
       next stage.  It must be called in a  transaction.   The	current	 stage
       must  always  be	 obtained  by  a  call	to pmemobj_tx_stage().	pmemo-
       bj_tx_process() performs	the following transitions in  the  transaction
       stage flow:

       o TX_STAGE_WORK -> TX_STAGE_ONCOMMIT

       o TX_STAGE_ONABORT -> TX_STAGE_FINALLY

       o TX_STAGE_ONCOMMIT -> TX_STAGE_FINALLY

       o TX_STAGE_FINALLY -> TX_STAGE_NONE

       o TX_STAGE_NONE -> TX_STAGE_NONE

       pmemobj_tx_process()  must not be called	after calling pmemobj_tx_end()
       for the outermost transaction.

       In addition to the above	API, libpmemobj(7)  offers  a  more  intuitive
       method  of  building transactions using the set of macros described be-
       low.  When using	these macros, the complete transaction flow looks like
       this:

	      TX_BEGIN(Pop) {
		  /* the actual	transaction code goes here... */
	      }	TX_ONCOMMIT {
		  /*
		   * optional -	executed only if the above block
		   * successfully completes
		   */
	      }	TX_ONABORT {
		  /*
		   * optional -	executed only if starting the transaction fails,
		   * or	if transaction is aborted by an	error or a call	to
		   * pmemobj_tx_abort()
		   */
	      }	TX_FINALLY {
		  /*
		   * optional -	if exists, it is executed after
		   * TX_ONCOMMIT or TX_ONABORT block
		   */
	      }	TX_END /* mandatory */

	      TX_BEGIN_PARAM(PMEMobjpool *pop, ...)
	      TX_BEGIN_CB(PMEMobjpool *pop, cb,	arg, ...)
	      TX_BEGIN(PMEMobjpool *pop)

       The  TX_BEGIN_PARAM(),  TX_BEGIN_CB() and TX_BEGIN() macros start a new
       transaction in the same way as pmemobj_tx_begin(), except that  instead
       of  the	environment buffer provided by a caller, they set up the local
       jmp_buf buffer and use it to catch the transaction abort.   The	TX_BE-
       GIN()  macro  starts a transaction without any options.	TX_BEGIN_PARAM
       may be used when	there is a need	to acquire locks prior to  starting  a
       transaction (such as for	a multi-threaded program) or set up a transac-
       tion stage callback.  TX_BEGIN_CB  is  just  a  wrapper	around	TX_BE-
       GIN_PARAM  that	validates  the callback	signature.  (For compatibility
       there is	also a TX_BEGIN_LOCK macro,  which  is	an  alias  for	TX_BE-
       GIN_PARAM).   Each  of these macros must	be followed by a block of code
       with all	the operations that are	to be performed	atomically.

       The TX_ONABORT macro starts a block of code that	will be	executed  only
       if  starting  the  transaction  fails due to an error in	pmemobj_tx_be-
       gin(), or if the	transaction is aborted.	 This block is	optional,  but
       in  practice it should not be omitted.  If it is	desirable to crash the
       application when	a transaction aborts and there is no  TX_ONABORT  sec-
       tion,  the application can define the POBJ_TX_CRASH_ON_NO_ONABORT macro
       before inclusion	of <libpmemobj.h>.  This provides a default TX_ONABORT
       section which just calls	abort(3).

       The TX_ONCOMMIT macro starts a block of code that will be executed only
       if the transaction is successfully committed, which means that the exe-
       cution  of  code	in the TX_BEGIN() block	has not	been interrupted by an
       error or	by a call to pmemobj_tx_abort().  This block is	optional.

       The TX_FINALLY macro starts a block of code that	will be	 executed  re-
       gardless	 of  whether  the  transaction	is committed or	aborted.  This
       block is	optional.

       The TX_END macro	cleans up and closes the transaction  started  by  the
       TX_BEGIN()  / TX_BEGIN_PARAM() /	TX_BEGIN_CB() macros.  It is mandatory
       to terminate each transaction with this macro.  If the transaction  was
       aborted,	errno is set appropriately.

RETURN VALUE
       The pmemobj_tx_stage() function returns the stage of the	current	trans-
       action stage for	a thread.

       On success, pmemobj_tx_begin() returns 0.  Otherwise, an	 error	number
       is returned.

       The  pmemobj_tx_begin()	and pmemobj_tx_lock() functions	return zero if
       lockp is	successfully added to the transaction.	 Otherwise,  an	 error
       number is returned.

       The pmemobj_tx_abort() and pmemobj_tx_commit() functions	return no val-
       ue.

       The pmemobj_tx_end() function returns 0 if the transaction was success-
       ful.   Otherwise	 it  returns the error code set	by pmemobj_tx_abort().
       Note that pmemobj_tx_abort() can	be called internally by	the library.

       The pmemobj_tx_errno() function returns the  error  code	 of  the  last
       transaction.

       The pmemobj_tx_process()	function returns no value.

CAVEATS
       Transaction  flow  control  is governed by the setjmp(3)	and longjmp(3)
       macros, and they	are used in both the macro and function	flavors	of the
       API.   The transaction will longjmp on transaction abort.  This has one
       major drawback, which is	described in the  ISO  C  standard  subsection
       7.13.2.1.   It says that	the values of objects of automatic storage du-
       ration that are local to	the function containing	the setjmp  invocation
       that  do	not have volatile-qualified type and have been changed between
       the setjmp invocation and longjmp call are indeterminate.

       The following example illustrates the issue described above.

	      int *bad_example_1 = (int	*)0xBAADF00D;
	      int *bad_example_2 = (int	*)0xBAADF00D;
	      int *bad_example_3 = (int	*)0xBAADF00D;
	      int * volatile good_example = (int *)0xBAADF00D;

	      TX_BEGIN(pop) {
		  bad_example_1	= malloc(sizeof(int));
		  bad_example_2	= malloc(sizeof(int));
		  bad_example_3	= malloc(sizeof(int));
		  good_example = malloc(sizeof(int));

		  /* manual or library abort called here */
		  pmemobj_tx_abort(EINVAL);
	      }	TX_ONCOMMIT {
		  /*
		   * This section is longjmp-safe
		   */
	      }	TX_ONABORT {
		  /*
		   * This section is not longjmp-safe
		   */
		  free(good_example); /* OK */
		  free(bad_example_1); /* undefined behavior */
	      }	TX_FINALLY {
		  /*
		   * This section is not longjmp-safe on transaction abort only
		   */
		  free(bad_example_2); /* undefined behavior */
	      }	TX_END

	      free(bad_example_3); /* undefined	behavior */

       Objects which are not volatile-qualified, are of	automatic storage  du-
       ration  and  have been changed between the invocations of setjmp(3) and
       longjmp(3) (that	also means within the work section of the  transaction
       after  TX_BEGIN())  should  not	be  used after a transaction abort, or
       should be used with utmost care.	 This also  includes  code  after  the
       TX_END macro.

       libpmemobj(7)  is  not  cancellation-safe.  The pool will never be cor-
       rupted because of a canceled thread, but	other threads may stall	 wait-
       ing  on	locks  taken  by that thread.  If the application wants	to use
       pthread_cancel(3), it must  disable  cancellation  before  calling  any
       libpmemobj(7)  APIs  (see  pthread_setcancelstate(3)  with PTHREAD_CAN-
       CEL_DISABLE), and  re-enable  it	 afterwards.   Deferring  cancellation
       (pthread_setcanceltype(3)  with	PTHREAD_CANCEL_DEFERRED)  is  not safe
       enough, because libpmemobj(7) internally	may call  functions  that  are
       specified as cancellation points	in POSIX.

       libpmemobj(7)  relies  on  the library destructor being called from the
       main thread.  For this reason, all functions  that  might  trigger  de-
       struction (e.g.	dlclose(3)) should be called in	the main thread.  Oth-
       erwise some of the resources associated with that thread	might  not  be
       cleaned up properly.

SEE ALSO
       dlclose(3),  longjmp(3),	 pmemobj_tx_add_range(3), pmemobj_tx_alloc(3),
       pthread_setcancelstate(3), pthread_setcanceltype(3),  setjmp(3),	 libp-
       memobj(7) and <http://pmem.io>

PMDK - pmemobj API version 2.3	  2019-07-10		   PMEMOBJ_TX_BEGIN(3)

NAME | SYNOPSIS | DESCRIPTION | RETURN VALUE | CAVEATS | SEE ALSO

Want to link to this manual page? Use this URL:
<https://www.freebsd.org/cgi/man.cgi?query=pmemobj_tx_begin&sektion=3&manpath=FreeBSD+13.0-RELEASE+and+Ports>

home | help