mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-31 11:28:21 +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. */
|
* block each other and a write transactions. */
|
||||||
MDBX_TXN_RDONLY = MDBX_RDONLY,
|
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. */
|
/** Do not block when starting a write transaction. */
|
||||||
MDBX_TXN_TRY = UINT32_C(0x10000000),
|
MDBX_TXN_TRY = UINT32_C(0x10000000),
|
||||||
|
|
||||||
|
55
src/core.c
55
src/core.c
@ -5909,8 +5909,6 @@ typedef struct {
|
|||||||
|
|
||||||
static bind_rslot_result bind_rslot(MDBX_env *env, const uintptr_t tid) {
|
static bind_rslot_result bind_rslot(MDBX_env *env, const uintptr_t tid) {
|
||||||
mdbx_assert(env, env->me_lck);
|
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_magic_and_version == MDBX_LOCK_MAGIC);
|
||||||
mdbx_assert(env, env->me_lck->mti_os_and_format == MDBX_LOCK_FORMAT);
|
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(). */
|
/* 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;
|
MDBX_env *env = txn->mt_env;
|
||||||
int rc;
|
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 ==
|
STATIC_ASSERT(offsetof(MDBX_lockinfo, mti_readers) % MDBX_CACHELINE_SIZE ==
|
||||||
0);
|
0);
|
||||||
|
|
||||||
mdbx_assert(env, (flags & ~(MDBX_TXN_BEGIN_FLAGS | MDBX_TXN_SPILLS |
|
|
||||||
MDBX_WRITEMAP)) == 0);
|
|
||||||
const uintptr_t tid = mdbx_thread_self();
|
const uintptr_t tid = mdbx_thread_self();
|
||||||
if (flags & MDBX_TXN_RDONLY) {
|
if (flags & MDBX_TXN_RDONLY) {
|
||||||
|
mdbx_assert(env, (flags & ~(MDBX_TXN_RO_BEGIN_FLAGS | MDBX_WRITEMAP)) == 0);
|
||||||
txn->mt_flags =
|
txn->mt_flags =
|
||||||
MDBX_TXN_RDONLY | (env->me_flags & (MDBX_NOTLS | MDBX_WRITEMAP));
|
MDBX_TXN_RDONLY | (env->me_flags & (MDBX_NOTLS | MDBX_WRITEMAP));
|
||||||
MDBX_reader *r = txn->to.reader;
|
MDBX_reader *r = txn->to.reader;
|
||||||
@ -6096,6 +6093,17 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
|||||||
return brs.err;
|
return brs.err;
|
||||||
r = brs.rslot;
|
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 */
|
/* Seek & fetch the last meta */
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -6142,12 +6150,13 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
|
|||||||
goto bailout;
|
goto bailout;
|
||||||
}
|
}
|
||||||
mdbx_assert(env, txn->mt_txnid >= *env->me_oldest);
|
mdbx_assert(env, txn->mt_txnid >= *env->me_oldest);
|
||||||
txn->to.reader = r;
|
|
||||||
txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
|
txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */
|
||||||
mdbx_ensure(env, txn->mt_txnid >=
|
mdbx_ensure(env, txn->mt_txnid >=
|
||||||
/* paranoia is appropriate here */ *env->me_oldest);
|
/* paranoia is appropriate here */ *env->me_oldest);
|
||||||
txn->mt_numdbs = env->me_numdbs;
|
txn->mt_numdbs = env->me_numdbs;
|
||||||
} else {
|
} else {
|
||||||
|
mdbx_assert(env, (flags & ~(MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_SPILLS |
|
||||||
|
MDBX_WRITEMAP)) == 0);
|
||||||
if (unlikely(txn->mt_owner == tid))
|
if (unlikely(txn->mt_owner == tid))
|
||||||
return MDBX_BUSY;
|
return MDBX_BUSY;
|
||||||
MDBX_lockinfo *const lck = env->me_lck;
|
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;
|
return MDBX_EINVAL;
|
||||||
*ret = NULL;
|
*ret = NULL;
|
||||||
|
|
||||||
|
if (unlikely((flags & ~MDBX_TXN_RW_BEGIN_FLAGS) &&
|
||||||
|
(flags & ~MDBX_TXN_RO_BEGIN_FLAGS)))
|
||||||
|
return MDBX_EINVAL;
|
||||||
|
|
||||||
int rc = check_env(env);
|
int rc = check_env(env);
|
||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
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 &
|
if (unlikely(env->me_flags & MDBX_RDONLY &
|
||||||
~flags)) /* write txn in RDONLY env */
|
~flags)) /* write txn in RDONLY env */
|
||||||
return MDBX_EACCESS;
|
return MDBX_EACCESS;
|
||||||
|
|
||||||
|
if (unlikely(!env->me_map))
|
||||||
|
return MDBX_EPERM;
|
||||||
|
|
||||||
flags |= env->me_flags & MDBX_WRITEMAP;
|
flags |= env->me_flags & MDBX_WRITEMAP;
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
@ -6379,12 +6385,7 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
|||||||
if (unlikely(rc != MDBX_SUCCESS))
|
if (unlikely(rc != MDBX_SUCCESS))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
flags |= parent->mt_flags & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_SPILLS);
|
||||||
if (unlikely(!env->me_map))
|
|
||||||
return MDBX_EPERM;
|
|
||||||
#endif /* Windows */
|
|
||||||
|
|
||||||
flags |= parent->mt_flags & (MDBX_TXN_BEGIN_FLAGS | MDBX_TXN_SPILLS);
|
|
||||||
/* Child txns save MDBX_pgstate and use own copy of cursors */
|
/* Child txns save MDBX_pgstate and use own copy of cursors */
|
||||||
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
|
size = env->me_maxdbs * (sizeof(MDBX_db) + sizeof(MDBX_cursor *) + 1);
|
||||||
size += tsize = sizeof(MDBX_txn);
|
size += tsize = sizeof(MDBX_txn);
|
||||||
@ -6477,9 +6478,15 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
|
|||||||
if (txn != env->me_txn0)
|
if (txn != env->me_txn0)
|
||||||
mdbx_free(txn);
|
mdbx_free(txn);
|
||||||
} else {
|
} else {
|
||||||
|
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,
|
mdbx_assert(env,
|
||||||
(txn->mt_flags & ~(MDBX_NOTLS | MDBX_TXN_RDONLY |
|
(txn->mt_flags & ~(MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED |
|
||||||
MDBX_WRITEMAP | MDBX_SHRINK_ALLOWED |
|
|
||||||
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC)) == 0);
|
MDBX_NOMETASYNC | MDBX_SAFE_NOSYNC)) == 0);
|
||||||
txn->mt_signature = MDBX_MT_SIGNATURE;
|
txn->mt_signature = MDBX_MT_SIGNATURE;
|
||||||
*ret = txn;
|
*ret = txn;
|
||||||
|
@ -720,8 +720,9 @@ struct MDBX_txn {
|
|||||||
|
|
||||||
/* Transaction Flags */
|
/* Transaction Flags */
|
||||||
/* mdbx_txn_begin() flags */
|
/* mdbx_txn_begin() flags */
|
||||||
#define MDBX_TXN_BEGIN_FLAGS \
|
#define MDBX_TXN_RO_BEGIN_FLAGS (MDBX_TXN_RDONLY | MDBX_TXN_RDONLY_PREPARE)
|
||||||
(MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_RDONLY | MDBX_TXN_TRY)
|
#define MDBX_TXN_RW_BEGIN_FLAGS \
|
||||||
|
(MDBX_TXN_NOMETASYNC | MDBX_TXN_NOSYNC | MDBX_TXN_TRY)
|
||||||
/* Additional flag for mdbx_sync_locked() */
|
/* Additional flag for mdbx_sync_locked() */
|
||||||
#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
|
#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_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS | \
|
||||||
MDBX_TXN_HAS_CHILD)
|
MDBX_TXN_HAS_CHILD)
|
||||||
|
|
||||||
#if (TXN_FLAGS & MDBX_TXN_BEGIN_FLAGS) || \
|
#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) || \
|
||||||
((MDBX_TXN_BEGIN_FLAGS | TXN_FLAGS) & MDBX_SHRINK_ALLOWED)
|
((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) & \
|
||||||
|
MDBX_SHRINK_ALLOWED)
|
||||||
#error "Oops, some flags overlapped or wrong"
|
#error "Oops, some flags overlapped or wrong"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user