mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-30 22:47:16 +08:00
mdbx: add MDBX_TXN_RDONLY_PREPARE.
Change-Id: I95647d1679b69d1e97514a45f20d7373174244d5
This commit is contained in:
parent
1e7a1da14e
commit
87de3fc25f
8
mdbx.h
8
mdbx.h
@ -1010,6 +1010,14 @@ enum MDBX_txn_flags_t {
|
||||
* block each other and a write transactions. */
|
||||
MDBX_TXN_RDONLY = MDBX_RDONLY,
|
||||
|
||||
/** Prepare but not start readonly transaction.
|
||||
*
|
||||
* Transaction will not be started immediately, but created transaction handle
|
||||
* will be ready for use with \ref mdbx_txn_renew(). This flag allows to
|
||||
* preallocate memory and assign a reader slot, thus avoiding these operations
|
||||
* at the next start of the transaction. */
|
||||
MDBX_TXN_RDONLY_PREPARE = MDBX_TXN_RDONLY | MDBX_NOMEMINIT,
|
||||
|
||||
/** Do not block when starting a write transaction. */
|
||||
MDBX_TXN_TRY = UINT32_C(0x10000000),
|
||||
|
||||
|
59
src/core.c
59
src/core.c
@ -5909,8 +5909,6 @@ typedef struct {
|
||||
|
||||
static bind_rslot_result bind_rslot(MDBX_env *env, const uintptr_t tid) {
|
||||
mdbx_assert(env, env->me_lck);
|
||||
mdbx_assert(env, (env->me_flags & (MDBX_NOTLS | MDBX_ENV_TXKEY)) ==
|
||||
MDBX_ENV_TXKEY);
|
||||
mdbx_assert(env, env->me_lck->mti_magic_and_version == MDBX_LOCK_MAGIC);
|
||||
mdbx_assert(env, env->me_lck->mti_os_and_format == MDBX_LOCK_FORMAT);
|
||||
|
||||
@ -6043,7 +6041,7 @@ __cold int mdbx_thread_unregister(MDBX_env *env) {
|
||||
}
|
||||
|
||||
/* Common code for mdbx_txn_begin() and mdbx_txn_renew(). */
|
||||
static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
||||
static int mdbx_txn_renew0(MDBX_txn *txn, const unsigned flags) {
|
||||
MDBX_env *env = txn->mt_env;
|
||||
int rc;
|
||||
|
||||
@ -6067,10 +6065,9 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
||||
STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_readers) % MDBX_CACHELINE_SIZE ==
|
||||
0);
|
||||
|
||||
mdbx_assert(env, (flags & ~(MDBX_TXN_BEGIN_FLAGS | MDBX_TXN_SPILLS |
|
||||
MDBX_WRITEMAP)) == 0);
|
||||
const uintptr_t tid = mdbx_thread_self();
|
||||
if (flags & MDBX_TXN_RDONLY) {
|
||||
mdbx_assert(env, (flags & ~(MDBX_TXN_RO_BEGIN_FLAGS | MDBX_WRITEMAP)) == 0);
|
||||
txn->mt_flags =
|
||||
MDBX_TXN_RDONLY | (env->me_flags & (MDBX_NOTLS | MDBX_WRITEMAP));
|
||||
MDBX_reader *r = txn->to.reader;
|
||||
@ -6096,6 +6093,17 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
||||
return brs.err;
|
||||
r = brs.rslot;
|
||||
}
|
||||
txn->to.reader = r;
|
||||
if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY)) {
|
||||
mdbx_assert(env, r->mr_txnid.inconsistent >= SAFE64_INVALID_THRESHOLD);
|
||||
mdbx_assert(env, txn->mt_txnid == 0);
|
||||
mdbx_assert(env, txn->mt_owner == 0);
|
||||
mdbx_assert(env, txn->mt_numdbs == 0);
|
||||
mdbx_assert(env, r->mr_snapshot_pages_used == 0);
|
||||
r->mr_snapshot_pages_used = 0;
|
||||
txn->mt_flags = MDBX_TXN_RDONLY | MDBX_TXN_FINISHED;
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Seek & fetch the last meta */
|
||||
while (1) {
|
||||
@ -6142,12 +6150,13 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
||||
goto bailout;
|
||||
}
|
||||
mdbx_assert(env, txn->mt_txnid >= *env->me_oldest);
|
||||
txn->to.reader = r;
|
||||
txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
|
||||
mdbx_ensure(env, txn->mt_txnid >=
|
||||
/* paranoia is appropriate here */ *env->me_oldest);
|
||||
txn->mt_numdbs = env->me_numdbs;
|
||||
} else {
|
||||
mdbx_assert(env, (flags & ~(MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_SPILLS |
|
||||
MDBX_WRITEMAP)) == 0);
|
||||
if (unlikely(txn->mt_owner == tid))
|
||||
return MDBX_BUSY;
|
||||
MDBX_lockinfo *const lck = env->me_lck;
|
||||
@ -6352,24 +6361,21 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
||||
return MDBX_EINVAL;
|
||||
*ret = NULL;
|
||||
|
||||
if (unlikely((flags & ~MDBX_TXN_RW_BEGIN_FLAGS) &&
|
||||
(flags & ~MDBX_TXN_RO_BEGIN_FLAGS)))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
int rc = check_env(env);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
/* Don't check env->me_map until lock to
|
||||
* avoid race with re-mapping for shrinking */
|
||||
if (unlikely(!env->me_map))
|
||||
return MDBX_EPERM;
|
||||
#endif /* Windows */
|
||||
|
||||
if (unlikely(flags & ~MDBX_TXN_BEGIN_FLAGS))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(env->me_flags & MDBX_RDONLY &
|
||||
~flags)) /* write txn in RDONLY env */
|
||||
return MDBX_EACCESS;
|
||||
|
||||
if (unlikely(!env->me_map))
|
||||
return MDBX_EPERM;
|
||||
|
||||
flags |= env->me_flags & MDBX_WRITEMAP;
|
||||
|
||||
if (parent) {
|
||||
@ -6379,12 +6385,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (unlikely(!env->me_map))
|
||||
return MDBX_EPERM;
|
||||
#endif /* Windows */
|
||||
|
||||
flags |= parent->mt_flags & (MDBX_TXN_BEGIN_FLAGS | MDBX_TXN_SPILLS);
|
||||
flags |= parent->mt_flags & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_SPILLS);
|
||||
/* Child txns save MDBX_pgstate and use own copy of cursors */
|
||||
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
|
||||
size += tsize = sizeof(MDBX_txn);
|
||||
@ -6477,10 +6478,16 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
||||
if (txn != env->me_txn0)
|
||||
mdbx_free(txn);
|
||||
} else {
|
||||
mdbx_assert(env,
|
||||
(txn->mt_flags & ~(MDBX_NOTLS | MDBX_TXN_RDONLY |
|
||||
MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED |
|
||||
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC)) == 0);
|
||||
if (flags & (MDBX_TXN_RDONLY_PREPARE - MDBX_TXN_RDONLY))
|
||||
mdbx_assert(env, txn->mt_flags == (MDBX_TXN_RDONLY | MDBX_TXN_FINISHED));
|
||||
else if (flags & MDBX_TXN_RDONLY)
|
||||
mdbx_assert(env, (txn->mt_flags &
|
||||
~(MDBX_NOTLS | MDBX_TXN_RDONLY | MDBX_WRITEMAP |
|
||||
/* Win32: SRWL flag */ MDBX_SHRINK_ALLOWED)) == 0);
|
||||
else
|
||||
mdbx_assert(env,
|
||||
(txn->mt_flags & ~(MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED |
|
||||
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC)) == 0);
|
||||
txn->mt_signature = MDBX_MT_SIGNATURE;
|
||||
*ret = txn;
|
||||
mdbx_debug("begin txn %" PRIaTXN "%c %p on env %p, root page %" PRIaPGNO
|
||||
|
@ -720,8 +720,9 @@ struct MDBX_txn {
|
||||
|
||||
/* Transaction Flags */
|
||||
/* mdbx_txn_begin() flags */
|
||||
#define MDBX_TXN_BEGIN_FLAGS \
|
||||
(MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_RDONLY | MDBX_TXN_TRY)
|
||||
#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
|
||||
#define MDBX_TXN_RW_BEGIN_FLAGS \
|
||||
(MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
|
||||
/* Additional flag for mdbx_sync_locked() */
|
||||
#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
|
||||
|
||||
@ -739,8 +740,9 @@ struct MDBX_txn {
|
||||
(MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS | \
|
||||
MDBX_TXN_HAS_CHILD)
|
||||
|
||||
#if (TXN_FLAGS & MDBX_TXN_BEGIN_FLAGS) || \
|
||||
((MDBX_TXN_BEGIN_FLAGS | TXN_FLAGS) & MDBX_SHRINK_ALLOWED)
|
||||
#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) || \
|
||||
((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) & \
|
||||
MDBX_SHRINK_ALLOWED)
|
||||
#error "Oops, some flags overlapped or wrong"
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user