From 6294e1710a764d1e02885c8e565497c151bf0f5a Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Tue, 29 Sep 2020 14:41:44 +0300 Subject: [PATCH] mdbx: support for user-settable transaction context. Change-Id: Ib4a345628e2c1ca2f95ac7615ea53d94911e5198 --- ChangeLog.md | 1 + mdbx.h | 91 +++++++++++++++++++++++++++++++++++++++++++++++-- src/core.c | 21 ++++++++++++ src/internals.h | 1 + 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 699efdd4..8bd49fcc 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -29,6 +29,7 @@ Added features: - Improved DB corruption detection by checking parent-page-txnid. - Improved opening large DB (> 4Gb) from 32-bit code. - Provided `pure-function` and `const-function` attributes to C API. + - Support for user-settable transaction context. Deprecated functions and flags: diff --git a/mdbx.h b/mdbx.h index 9f5100cd..40b809ec 100644 --- a/mdbx.h +++ b/mdbx.h @@ -2569,7 +2569,8 @@ LIBMDBX_API int mdbx_env_set_userctx(MDBX_env *env, void *ctx); * \see mdbx_env_set_userctx() * * \param [in] env An environment handle returned by \ref mdbx_env_create() - * \returns The pointer set by \ref mdbx_env_set_userctx(). */ + * \returns The pointer set by \ref mdbx_env_set_userctx() + * or `NULL` if something wrong. */ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void * mdbx_env_get_userctx(const MDBX_env *env); @@ -2578,6 +2579,7 @@ mdbx_env_get_userctx(const MDBX_env *env); * * The transaction handle may be discarded using \ref mdbx_txn_abort() * or \ref mdbx_txn_commit(). + * \see mdbx_txn_begin_ex() * * \note A transaction and its cursors must only be used by a single thread, * and a thread may only have a single transaction at a time. If \ref MDBX_NOTLS @@ -2607,7 +2609,7 @@ mdbx_env_get_userctx(const MDBX_env *env); * to \ref MDBX_NOMETASYNC or \ref MDBX_SAFE_NOSYNC * description. \see sync_modes * - * \param [out] txn Address where the new MDBX_txn handle will be stored + * \param [out] txn Address where the new MDBX_txn handle will be stored. * * \returns A non-zero error value on failure and 0 on success, * some possible errors are: @@ -2626,6 +2628,91 @@ mdbx_env_get_userctx(const MDBX_env *env); LIBMDBX_API int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, MDBX_txn **txn); +/** \brief Create a transaction with a user provided context pointer + * for use with the environment. + * \ingroup c_transactions + * + * The transaction handle may be discarded using \ref mdbx_txn_abort() + * or \ref mdbx_txn_commit(). + * \see mdbx_txn_begin() + * + * \note A transaction and its cursors must only be used by a single thread, + * and a thread may only have a single transaction at a time. If \ref MDBX_NOTLS + * is in use, this does not apply to read-only transactions. + * + * \note Cursors may not span transactions. + * + * \param [in] env An environment handle returned by \ref mdbx_env_create(). + * + * \param [in] parent If this parameter is non-NULL, the new transaction will + * be a nested transaction, with the transaction indicated + * by parent as its parent. Transactions may be nested + * to any level. A parent transaction and its cursors may + * not issue any other operations than mdbx_txn_commit and + * \ref mdbx_txn_abort() while it has active child + * transactions. + * + * \param [in] flags Special options for this transaction. This parameter + * must be set to 0 or by bitwise OR'ing together one + * or more of the values described here: + * - \ref MDBX_RDONLY This transaction will not perform + * any write operations. + * + * - \ref MDBX_TXN_TRY Do not block when starting + * a write transaction. + * + * - \ref MDBX_SAFE_NOSYNC, \ref MDBX_NOMETASYNC. + * Do not sync data to disk corresponding + * to \ref MDBX_NOMETASYNC or \ref MDBX_SAFE_NOSYNC + * description. \see sync_modes + * + * \param [out] txn Address where the new MDBX_txn handle will be stored. + * + * \param [in] context A pointer to application context to be associated with + * created transaction and could be retrieved by + * \ref mdbx_txn_get_userctx() until transaction finished. + * + * \returns A non-zero error value on failure and 0 on success, + * some possible errors are: + * \retval MDBX_PANIC A fatal error occurred earlier and the + * environment must be shut down. + * \retval MDBX_UNABLE_EXTEND_MAPSIZE Another process wrote data beyond + * this MDBX_env's mapsize and this + * environment map must be resized as well. + * See \ref mdbx_env_set_mapsize(). + * \retval MDBX_READERS_FULL A read-only transaction was requested and + * the reader lock table is full. + * See \ref mdbx_env_set_maxreaders(). + * \retval MDBX_ENOMEM Out of memory. + * \retval MDBX_BUSY The write transaction is already started by the + * current thread. */ +LIBMDBX_API int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, + MDBX_txn_flags_t flags, MDBX_txn **txn, + void *context); + +/** \brief Set application information associated with the \ref MDBX_txn. + * \ingroup c_transactions + * \see mdbx_txn_get_userctx() + * + * \param [in] txn An transaction handle returned by \ref mdbx_txn_begin_ex() + * or \ref mdbx_txn_begin(). + * \param [in] ctx An arbitrary pointer for whatever the application needs. + * + * \returns A non-zero error value on failure and 0 on success. */ +LIBMDBX_API int mdbx_txn_set_userctx(MDBX_txn *txn, void *ctx); + +/** \brief Get the application information associated with the MDBX_txn. + * \ingroup c_transactions + * \see mdbx_txn_set_userctx() + * + * \param [in] txn An transaction handle returned by \ref mdbx_txn_begin_ex() + * or \ref mdbx_txn_begin(). + * \returns The pointer which was passed via the `context` parameter + * of `mdbx_txn_begin_ex()` or set by \ref mdbx_txn_set_userctx(), + * or `NULL` if something wrong. */ +MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void * +mdbx_txn_get_userctx(const MDBX_txn *txn); + /** \brief Information about the transaction * \ingroup c_statinfo * \see mdbx_txn_info */ diff --git a/src/core.c b/src/core.c index 9d19f183..eafef68d 100644 --- a/src/core.c +++ b/src/core.c @@ -6447,6 +6447,26 @@ int mdbx_txn_renew(MDBX_txn *txn) { int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, MDBX_txn **ret) { + return mdbx_txn_begin_ex(env, parent, flags, ret, nullptr); +} + +int mdbx_txn_set_userctx(MDBX_txn *txn, void *ctx) { + int rc = check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_HAS_CHILD); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + txn->mt_userctx = ctx; + return MDBX_SUCCESS; +} + +void *mdbx_txn_get_userctx(const MDBX_txn *txn) { + return check_txn(txn, MDBX_TXN_BLOCKED - MDBX_TXN_HAS_CHILD) + ? nullptr + : txn->mt_userctx; +} + +int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, + MDBX_txn **ret, void *context) { MDBX_txn *txn; unsigned size, tsize; @@ -6582,6 +6602,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, (txn->mt_flags & ~(MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED | MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC)) == 0); txn->mt_signature = MDBX_MT_SIGNATURE; + txn->mt_userctx = context; *ret = txn; mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO "/%" PRIaPGNO, diff --git a/src/internals.h b/src/internals.h index 5cf80e15..cd9311c6 100644 --- a/src/internals.h +++ b/src/internals.h @@ -798,6 +798,7 @@ struct MDBX_txn { MDBX_dbi mt_numdbs; size_t mt_owner; /* thread ID that owns this transaction */ MDBX_canary mt_canary; + void *mt_userctx; /* User-settable context */ union { struct {