From f6850f53672f0c016c14efc03c6a5cf9e69ee750 Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Tue, 29 Sep 2020 20:58:09 +0300 Subject: [PATCH] mdbx: Support for user-settable cursor context. Change-Id: I9bd60c432924e39020b2d3af3280f13c44d6cd91 --- ChangeLog.md | 2 +- mdbx.h | 29 ++++++++++++++++++++++++++++- mdbx.h++ | 2 +- src/core.c | 30 ++++++++++++++++++++++++++++-- src/internals.h | 1 + 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 4d3e1de7..7d2b5e92 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -29,7 +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. + - Support for user-settable context for transactions & cursors. - Revised API and documentation related to Handle-Slow-Readers callback feature. Deprecated functions and flags: diff --git a/mdbx.h b/mdbx.h index 27057342..f27fad39 100644 --- a/mdbx.h +++ b/mdbx.h @@ -3562,8 +3562,35 @@ LIBMDBX_API int mdbx_del(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, * which helps to avoid errors such as: use-after-free, double-free, i.e. * memory corruption and segfaults. * + * \param [in] context A pointer to application context to be associated with + * created cursor and could be retrieved by + * \ref mdbx_cursor_get_userctx() until cursor closed. + * * \returns Created cursor handle or NULL in case out of memory. */ -LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void); +LIBMDBX_API MDBX_cursor *mdbx_cursor_create(void *context); + +/** \brief Set application information associated with the \ref MDBX_cursor. + * \ingroup c_crud + * \see mdbx_cursor_get_userctx() + * + * \param [in] cursor An cursor handle returned by \ref mdbx_cursor_create() + * or \ref mdbx_cursor_open(). + * \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_cursor_set_userctx(MDBX_cursor *cursor, void *ctx); + +/** \brief Get the application information associated with the MDBX_cursor. + * \ingroup c_crud + * \see mdbx_cursor_set_userctx() + * + * \param [in] cursor An cursor handle returned by \ref mdbx_cursor_create() + * or \ref mdbx_cursor_open(). + * \returns The pointer which was passed via the `context` parameter + * of `mdbx_cursor_create()` or set by \ref mdbx_cursor_set_userctx(), + * or `NULL` if something wrong. */ +MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void * +mdbx_cursor_get_userctx(const MDBX_cursor *cursor); /** \brief Bind cursor to specified transaction and DBI handle. * \ingroup c_cursors diff --git a/mdbx.h++ b/mdbx.h++ index 0d20ff5e..095ff9ab 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4396,7 +4396,7 @@ inline bool cursor::erase(bool whole_multivalue) { //------------------------------------------------------------------------------ inline cursor_managed::cursor_managed() - : cursor_managed(::mdbx_cursor_create()) { + : cursor_managed(::mdbx_cursor_create(nullptr)) { if (MDBX_UNLIKELY(!handle_)) MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_ENOMEM); } diff --git a/src/core.c b/src/core.c index 6f82ce33..2fa44cae 100644 --- a/src/core.c +++ b/src/core.c @@ -13805,16 +13805,42 @@ static int mdbx_cursor_init(MDBX_cursor *mc, MDBX_txn *txn, MDBX_dbi dbi) { &txn->mt_dbistate[dbi]); } -MDBX_cursor *mdbx_cursor_create(void) { +MDBX_cursor *mdbx_cursor_create(void *context) { MDBX_cursor_couple *couple = mdbx_calloc(1, sizeof(MDBX_cursor_couple)); if (unlikely(!couple)) return nullptr; couple->outer.mc_signature = MDBX_MC_READY4CLOSE; couple->outer.mc_dbi = UINT_MAX; + couple->mc_userctx = context; return &couple->outer; } +int mdbx_cursor_set_userctx(MDBX_cursor *mc, void *ctx) { + if (unlikely(!mc)) + return MDBX_EINVAL; + + if (unlikely(mc->mc_signature != MDBX_MC_READY4CLOSE && + mc->mc_signature != MDBX_MC_LIVE)) + return MDBX_EINVAL; + + MDBX_cursor_couple *couple = container_of(mc, MDBX_cursor_couple, outer); + couple->mc_userctx = ctx; + return MDBX_SUCCESS; +} + +void *mdbx_cursor_get_userctx(const MDBX_cursor *mc) { + if (unlikely(!mc)) + return nullptr; + + if (unlikely(mc->mc_signature != MDBX_MC_READY4CLOSE && + mc->mc_signature != MDBX_MC_LIVE)) + return nullptr; + + MDBX_cursor_couple *couple = container_of(mc, MDBX_cursor_couple, outer); + return couple->mc_userctx; +} + int mdbx_cursor_bind(MDBX_txn *txn, MDBX_cursor *mc, MDBX_dbi dbi) { if (unlikely(!mc)) return MDBX_EINVAL; @@ -13868,7 +13894,7 @@ int mdbx_cursor_open(MDBX_txn *txn, MDBX_dbi dbi, MDBX_cursor **ret) { return MDBX_EINVAL; *ret = NULL; - MDBX_cursor *const mc = mdbx_cursor_create(); + MDBX_cursor *const mc = mdbx_cursor_create(nullptr); if (unlikely(!mc)) return MDBX_ENOMEM; diff --git a/src/internals.h b/src/internals.h index f9d359d7..6754ab15 100644 --- a/src/internals.h +++ b/src/internals.h @@ -917,6 +917,7 @@ typedef struct MDBX_xcursor { typedef struct MDBX_cursor_couple { MDBX_cursor outer; + void *mc_userctx; /* User-settable context */ MDBX_xcursor inner; } MDBX_cursor_couple;