mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-23 16:19:35 -05:00
Merge remote-tracking branch 'origin/mdb.master'
This commit is contained in:
commit
4a6adbf589
4 changed files with 163 additions and 120 deletions
|
|
@ -206,6 +206,9 @@ typedef struct MDB_cursor MDB_cursor;
|
|||
* #MDB_MAXKEYSIZE inclusive. This currently defaults to 511. The
|
||||
* same applies to data sizes in databases with the #MDB_DUPSORT flag.
|
||||
* Other data items can in theory be from 0 to 0xffffffff bytes long.
|
||||
*
|
||||
* Values returned from the database are valid only until a subsequent
|
||||
* update operation, or the end of the transaction.
|
||||
*/
|
||||
typedef struct MDB_val {
|
||||
size_t mv_size; /**< size of the data item */
|
||||
|
|
@ -691,8 +694,7 @@ int mdb_env_set_maxdbs(MDB_env *env, MDB_dbi dbs);
|
|||
* @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 #MDB_NOTLS is in use, this does not apply to read-only transactions.
|
||||
* @note Cursors may not span transactions; each cursor must be opened and closed
|
||||
* within a single transaction.
|
||||
* @note Cursors may not span transactions.
|
||||
* @param[in] env An environment handle returned by #mdb_env_create()
|
||||
* @param[in] parent If this parameter is non-NULL, the new transaction
|
||||
* will be a nested transaction, with the transaction indicated by \b parent
|
||||
|
|
@ -723,8 +725,10 @@ int mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **
|
|||
|
||||
/** @brief Commit all the operations of a transaction into the database.
|
||||
*
|
||||
* All cursors opened within the transaction will be closed by this call. The cursors
|
||||
* and transaction handle will be freed and must not be used again after this call.
|
||||
* The transaction handle is freed. It and its cursors must not be used
|
||||
* again after this call, except with #mdb_cursor_renew().
|
||||
* @note Earlier documentation incorrectly said all cursors would be freed.
|
||||
* Only write-transactions free cursors.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
* errors are:
|
||||
|
|
@ -739,8 +743,10 @@ int mdb_txn_commit(MDB_txn *txn);
|
|||
|
||||
/** @brief Abandon all the operations of the transaction instead of saving them.
|
||||
*
|
||||
* All cursors opened within the transaction will be closed by this call. The cursors
|
||||
* and transaction handle will be freed and must not be used again after this call.
|
||||
* The transaction handle is freed. It and its cursors must not be used
|
||||
* again after this call, except with #mdb_cursor_renew().
|
||||
* @note Earlier documentation incorrectly said all cursors would be freed.
|
||||
* Only write-transactions free cursors.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
*/
|
||||
void mdb_txn_abort(MDB_txn *txn);
|
||||
|
|
@ -754,8 +760,8 @@ void mdb_txn_abort(MDB_txn *txn);
|
|||
* lock is released, but the table slot stays tied to its thread or
|
||||
* #MDB_txn. Use mdb_txn_abort() to discard a reset handle, and to free
|
||||
* its lock table slot if MDB_NOTLS is in use.
|
||||
* All cursors opened within the transaction must be closed before the transaction
|
||||
* is reset.
|
||||
* Cursors opened within the transaction must not be used
|
||||
* again after this call, except with #mdb_cursor_renew().
|
||||
* Reader locks generally don't interfere with writers, but they keep old
|
||||
* versions of database pages allocated. Thus they prevent the old pages
|
||||
* from being reused when writers commit new data, and so under heavy load
|
||||
|
|
@ -787,6 +793,8 @@ int mdb_txn_renew(MDB_txn *txn);
|
|||
|
||||
/** @brief Open a database in the environment.
|
||||
*
|
||||
* A database handle denotes the name and parameters of a database,
|
||||
* independently of whether such a database exists.
|
||||
* The database handle may be discarded by calling #mdb_dbi_close().
|
||||
* The old database handle is returned if the database was already open.
|
||||
* The handle must only be closed once.
|
||||
|
|
@ -978,6 +986,8 @@ int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx);
|
|||
* database. The caller need not dispose of the memory, and may not
|
||||
* modify it in any way. For values returned in a read-only transaction
|
||||
* any modification attempts will cause a SIGSEGV.
|
||||
* @note Values returned from the database are valid only until a
|
||||
* subsequent update operation, or the end of the transaction.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @param[in] dbi A database handle returned by #mdb_dbi_open()
|
||||
* @param[in] key The key to search for in the database
|
||||
|
|
@ -1017,7 +1027,8 @@ int mdb_get(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
|
|||
* parameter will be set to point to the existing item.
|
||||
* <li>#MDB_RESERVE - reserve space for data of the given size, but
|
||||
* don't copy the given data. Instead, return a pointer to the
|
||||
* reserved space, which the caller can fill in later. This saves
|
||||
* reserved space, which the caller can fill in later - before
|
||||
* the next update operation or the transaction ends. This saves
|
||||
* an extra memcpy if the data is being generated later.
|
||||
* <li>#MDB_APPEND - append the given key/data pair to the end of the
|
||||
* database. No key comparisons are performed. This option allows
|
||||
|
|
@ -1065,7 +1076,16 @@ int mdb_del(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data);
|
|||
/** @brief Create a cursor handle.
|
||||
*
|
||||
* A cursor is associated with a specific transaction and database.
|
||||
* It must be closed before its transaction ends.
|
||||
* A cursor cannot be used when its database handle is closed. Nor
|
||||
* when its transaction has ended, except with #mdb_cursor_renew().
|
||||
* It can be discarded with #mdb_cursor_close().
|
||||
* A cursor in a write-transaction can be closed before its transaction
|
||||
* ends, and will otherwise be closed when its transaction ends.
|
||||
* A cursor in a read-only transaction must be closed explicitly, before
|
||||
* or after its transaction ends. It can be reused with
|
||||
* #mdb_cursor_renew() before finally closing it.
|
||||
* @note Earlier documentation said that cursors in every transaction
|
||||
* were closed when the transaction committed or aborted.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @param[in] dbi A database handle returned by #mdb_dbi_open()
|
||||
* @param[out] cursor Address where the new #MDB_cursor handle will be stored
|
||||
|
|
@ -1080,6 +1100,7 @@ int mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **cursor);
|
|||
/** @brief Close a cursor handle.
|
||||
*
|
||||
* The cursor handle will be freed and must not be used again after this call.
|
||||
* Its transaction must still be live if it is a write-transaction.
|
||||
* @param[in] cursor A cursor handle returned by #mdb_cursor_open()
|
||||
*/
|
||||
void mdb_cursor_close(MDB_cursor *cursor);
|
||||
|
|
@ -1087,11 +1108,11 @@ void mdb_cursor_close(MDB_cursor *cursor);
|
|||
/** @brief Renew a cursor handle.
|
||||
*
|
||||
* A cursor is associated with a specific transaction and database.
|
||||
* It must be closed before its transaction ends.
|
||||
* Cursors that are only used in read-only
|
||||
* transactions may be re-used, to avoid unnecessary malloc/free overhead.
|
||||
* The cursor may be associated with a new read-only transaction, and
|
||||
* referencing the same database handle as it was created with.
|
||||
* This may be done whether the previous transaction is live or dead.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @param[in] cursor A cursor handle returned by #mdb_cursor_open()
|
||||
* @return A non-zero error value on failure and 0 on success. Some possible
|
||||
|
|
@ -1121,6 +1142,7 @@ MDB_dbi mdb_cursor_dbi(MDB_cursor *cursor);
|
|||
* case of the #MDB_SET option, in which the \b key object is unchanged), and
|
||||
* the address and length of the data are returned in the object to which \b data
|
||||
* refers.
|
||||
* See #mdb_get() for restrictions on using the output values.
|
||||
* @param[in] cursor A cursor handle returned by #mdb_cursor_open()
|
||||
* @param[in,out] key The key for a retrieved item
|
||||
* @param[in,out] data The data of a retrieved item
|
||||
|
|
@ -1230,7 +1252,7 @@ int mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b);
|
|||
/** @brief Compare two data items according to a particular database.
|
||||
*
|
||||
* This returns a comparison as if the two items were data items of
|
||||
* a sorted duplicates #MDB_DUPSORT database.
|
||||
* the specified database. The database must have the #MDB_DUPSORT flag.
|
||||
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
|
||||
* @param[in] dbi A database handle returned by #mdb_dbi_open()
|
||||
* @param[in] a The first item to compare
|
||||
|
|
|
|||
|
|
@ -900,6 +900,7 @@ struct MDB_cursor {
|
|||
#define C_SHADOW 0x08 /**< Cursor is a dup from a parent txn */
|
||||
#define C_ALLOCD 0x10 /**< Cursor was malloc'd */
|
||||
#define C_SPLITTING 0x20 /**< Cursor is in page_split */
|
||||
#define C_UNTRACK 0x40 /**< Un-track cursor when closing */
|
||||
/** @} */
|
||||
unsigned int mc_flags; /**< @ref mdb_cursor */
|
||||
MDB_page *mc_pg[CURSOR_STACK]; /**< stack of pushed pages */
|
||||
|
|
@ -1013,6 +1014,9 @@ static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata,
|
|||
static int mdb_env_read_header(MDB_env *env, MDB_meta *meta);
|
||||
static int mdb_env_pick_meta(const MDB_env *env);
|
||||
static int mdb_env_write_meta(MDB_txn *txn);
|
||||
#if !(defined(_WIN32) || defined(MDB_USE_POSIX_SEM)) /* Drop unused excl arg */
|
||||
# define mdb_env_close0(env, excl) mdb_env_close1(env)
|
||||
#endif
|
||||
static void mdb_env_close0(MDB_env *env, int excl);
|
||||
|
||||
static MDB_node *mdb_node_search(MDB_cursor *mc, MDB_val *key, int *exactp);
|
||||
|
|
@ -1135,7 +1139,7 @@ mdb_dkey(MDB_val *key, char *buf)
|
|||
}
|
||||
|
||||
/** Display all the keys in the page. */
|
||||
static void
|
||||
void
|
||||
mdb_page_list(MDB_page *mp)
|
||||
{
|
||||
MDB_node *node;
|
||||
|
|
@ -1202,9 +1206,8 @@ static void mdb_audit(MDB_txn *txn)
|
|||
|
||||
count = 0;
|
||||
for (i = 0; i<txn->mt_numdbs; i++) {
|
||||
MDB_xcursor mx, *mxp;
|
||||
mxp = (txn->mt_dbs[i].md_flags & MDB_DUPSORT) ? &mx : NULL;
|
||||
mdb_cursor_init(&mc, txn, i, mxp);
|
||||
MDB_xcursor mx;
|
||||
mdb_cursor_init(&mc, txn, i, &mx);
|
||||
if (txn->mt_dbs[i].md_root == P_INVALID)
|
||||
continue;
|
||||
count += txn->mt_dbs[i].md_branch_pages +
|
||||
|
|
@ -1245,10 +1248,7 @@ mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
|
|||
int
|
||||
mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b)
|
||||
{
|
||||
if (txn->mt_dbxs[dbi].md_dcmp)
|
||||
return txn->mt_dbxs[dbi].md_dcmp(a, b);
|
||||
else
|
||||
return EINVAL; /* too bad you can't distinguish this from a valid result */
|
||||
}
|
||||
|
||||
/** Allocate a single page.
|
||||
|
|
@ -1398,6 +1398,7 @@ none:
|
|||
|
||||
mdb_cursor_init(&m2, txn, FREE_DBI, NULL);
|
||||
do {
|
||||
#ifdef MDB_PARANOID /* Seems like we can ignore this now */
|
||||
/* If on freelist, don't try to read more. If what we have
|
||||
* right now isn't enough just use new pages.
|
||||
* TODO: get all of this working. Many circular dependencies...
|
||||
|
|
@ -1406,6 +1407,7 @@ none:
|
|||
retry = 0;
|
||||
readit = 0;
|
||||
}
|
||||
#endif
|
||||
if (readit) {
|
||||
MDB_val key, data;
|
||||
pgno_t *idl, *mop2;
|
||||
|
|
@ -1704,7 +1706,7 @@ mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
|
|||
mc->mc_dbflag = &dst->mt_dbflags[i];
|
||||
mc->mc_snum = m2->mc_snum;
|
||||
mc->mc_top = m2->mc_top;
|
||||
mc->mc_flags = m2->mc_flags | C_SHADOW;
|
||||
mc->mc_flags = m2->mc_flags | (C_SHADOW|C_ALLOCD);
|
||||
for (j=0; j<mc->mc_snum; j++) {
|
||||
mc->mc_pg[j] = m2->mc_pg[j];
|
||||
mc->mc_ki[j] = m2->mc_ki[j];
|
||||
|
|
@ -1740,22 +1742,26 @@ mdb_cursor_shadow(MDB_txn *src, MDB_txn *dst)
|
|||
return MDB_SUCCESS;
|
||||
}
|
||||
|
||||
/** Merge shadow cursors back into parent's */
|
||||
/** Close this write txn's cursors, after optionally merging its shadow
|
||||
* cursors back into parent's.
|
||||
* @param[in] txn the transaction handle.
|
||||
* @param[in] merge 0 to not merge cursors, C_SHADOW to merge.
|
||||
* @return 0 on success, non-zero on failure.
|
||||
*/
|
||||
static void
|
||||
mdb_cursor_merge(MDB_txn *txn)
|
||||
mdb_cursors_close(MDB_txn *txn, unsigned merge)
|
||||
{
|
||||
MDB_dbi i;
|
||||
for (i=0; i<txn->mt_numdbs; i++) {
|
||||
if (txn->mt_cursors[i]) {
|
||||
MDB_cursor *mc;
|
||||
while ((mc = txn->mt_cursors[i])) {
|
||||
txn->mt_cursors[i] = mc->mc_next;
|
||||
if (mc->mc_flags & C_SHADOW) {
|
||||
MDB_cursor **cursors = txn->mt_cursors, *mc, *next;
|
||||
int i, j;
|
||||
|
||||
for (i = txn->mt_numdbs; --i >= 0; ) {
|
||||
for (mc = cursors[i]; mc; mc = next) {
|
||||
next = mc->mc_next;
|
||||
if (mc->mc_flags & merge) {
|
||||
MDB_cursor *m2 = mc->mc_orig;
|
||||
unsigned int j;
|
||||
m2->mc_snum = mc->mc_snum;
|
||||
m2->mc_top = mc->mc_top;
|
||||
for (j=0; j<mc->mc_snum; j++) {
|
||||
for (j = mc->mc_snum; --j >= 0; ) {
|
||||
m2->mc_pg[j] = mc->mc_pg[j];
|
||||
m2->mc_ki[j] = mc->mc_ki[j];
|
||||
}
|
||||
|
|
@ -1763,7 +1769,7 @@ mdb_cursor_merge(MDB_txn *txn)
|
|||
if (mc->mc_flags & C_ALLOCD)
|
||||
free(mc);
|
||||
}
|
||||
}
|
||||
cursors[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1780,7 +1786,7 @@ mdb_txn_renew0(MDB_txn *txn)
|
|||
MDB_env *env = txn->mt_env;
|
||||
unsigned int i;
|
||||
uint16_t x;
|
||||
int rc;
|
||||
int rc, new_notls = 0;
|
||||
|
||||
/* Setup db info */
|
||||
txn->mt_numdbs = env->me_numdbs;
|
||||
|
|
@ -1817,9 +1823,9 @@ mdb_txn_renew0(MDB_txn *txn)
|
|||
env->me_numreaders = env->me_txns->mti_numreaders;
|
||||
UNLOCK_MUTEX_R(env);
|
||||
r = &env->me_txns->mti_readers[i];
|
||||
if (!(env->me_flags & MDB_NOTLS) &&
|
||||
(rc = pthread_setspecific(env->me_txkey, r)) != 0) {
|
||||
env->me_txns->mti_readers[i].mr_pid = 0;
|
||||
new_notls = (env->me_flags & MDB_NOTLS);
|
||||
if (!new_notls && (rc=pthread_setspecific(env->me_txkey, r))) {
|
||||
r->mr_pid = 0;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
|
@ -1858,6 +1864,10 @@ mdb_txn_renew0(MDB_txn *txn)
|
|||
|
||||
if (env->me_maxpg < txn->mt_next_pgno) {
|
||||
mdb_txn_reset0(txn);
|
||||
if (new_notls) {
|
||||
txn->mt_u.reader->mr_pid = 0;
|
||||
txn->mt_u.reader = NULL;
|
||||
}
|
||||
return MDB_MAP_RESIZED;
|
||||
}
|
||||
|
||||
|
|
@ -1869,7 +1879,7 @@ mdb_txn_renew(MDB_txn *txn)
|
|||
{
|
||||
int rc;
|
||||
|
||||
if (!txn || txn->mt_numdbs || !(txn->mt_flags & MDB_TXN_RDONLY))
|
||||
if (!txn || txn->mt_dbxs) /* A reset txn has mt_dbxs==NULL */
|
||||
return EINVAL;
|
||||
|
||||
if (txn->mt_env->me_flags & MDB_FATAL_ERROR) {
|
||||
|
|
@ -1929,14 +1939,11 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
|
|||
|
||||
if (parent) {
|
||||
unsigned int i;
|
||||
txn->mt_free_pgs = mdb_midl_alloc();
|
||||
if (!txn->mt_free_pgs) {
|
||||
free(txn);
|
||||
return ENOMEM;
|
||||
}
|
||||
txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE);
|
||||
if (!txn->mt_u.dirty_list) {
|
||||
free(txn->mt_free_pgs);
|
||||
if (!txn->mt_u.dirty_list ||
|
||||
!(txn->mt_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)))
|
||||
{
|
||||
free(txn->mt_u.dirty_list);
|
||||
free(txn);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
|
@ -1985,6 +1992,32 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/** Export or close DBI handles opened in this txn. */
|
||||
static void
|
||||
mdb_dbis_update(MDB_txn *txn, int keep)
|
||||
{
|
||||
int i;
|
||||
MDB_dbi n = txn->mt_numdbs;
|
||||
MDB_env *env = txn->mt_env;
|
||||
unsigned char *tdbflags = txn->mt_dbflags;
|
||||
|
||||
for (i = n; --i >= 2;) {
|
||||
if (tdbflags[i] & DB_NEW) {
|
||||
if (keep) {
|
||||
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
|
||||
} else {
|
||||
char *ptr = env->me_dbxs[i].md_name.mv_data;
|
||||
env->me_dbxs[i].md_name.mv_data = NULL;
|
||||
env->me_dbxs[i].md_name.mv_size = 0;
|
||||
env->me_dbflags[i] = 0;
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keep && env->me_numdbs < n)
|
||||
env->me_numdbs = n;
|
||||
}
|
||||
|
||||
/** Common code for #mdb_txn_reset() and #mdb_txn_abort().
|
||||
* May be called twice for readonly txns: First reset it, then abort.
|
||||
* @param[in] txn the transaction handle to reset
|
||||
|
|
@ -1996,14 +2029,7 @@ mdb_txn_reset0(MDB_txn *txn)
|
|||
unsigned int i;
|
||||
|
||||
/* Close any DBI handles opened in this txn */
|
||||
for (i=2; i<txn->mt_numdbs; i++) {
|
||||
if (txn->mt_dbflags[i] & DB_NEW) {
|
||||
char *ptr = env->me_dbxs[i].md_name.mv_data;
|
||||
env->me_dbxs[i].md_name.mv_data = NULL;
|
||||
env->me_dbxs[i].md_name.mv_size = 0;
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
mdb_dbis_update(txn, 0);
|
||||
|
||||
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
|
||||
if (txn->mt_u.reader) {
|
||||
|
|
@ -2011,21 +2037,12 @@ mdb_txn_reset0(MDB_txn *txn)
|
|||
if (!(env->me_flags & MDB_NOTLS))
|
||||
txn->mt_u.reader = NULL; /* txn does not own reader */
|
||||
}
|
||||
txn->mt_numdbs = 0; /* mark txn as reset, do not close DBs again */
|
||||
txn->mt_numdbs = 0; /* close nothing if called again */
|
||||
txn->mt_dbxs = NULL; /* mark txn as reset */
|
||||
} else {
|
||||
MDB_page *dp;
|
||||
|
||||
/* close(free) all cursors */
|
||||
for (i=0; i<txn->mt_numdbs; i++) {
|
||||
if (txn->mt_cursors[i]) {
|
||||
MDB_cursor *mc;
|
||||
while ((mc = txn->mt_cursors[i])) {
|
||||
txn->mt_cursors[i] = mc->mc_next;
|
||||
if (mc->mc_flags & C_ALLOCD)
|
||||
free(mc);
|
||||
}
|
||||
}
|
||||
}
|
||||
mdb_cursors_close(txn, 0);
|
||||
|
||||
if (!(env->me_flags & MDB_WRITEMAP)) {
|
||||
/* return all dirty pages to dpage list */
|
||||
|
|
@ -2118,20 +2135,18 @@ mdb_txn_commit(MDB_txn *txn)
|
|||
assert(txn->mt_env != NULL);
|
||||
|
||||
if (txn->mt_child) {
|
||||
mdb_txn_commit(txn->mt_child);
|
||||
rc = mdb_txn_commit(txn->mt_child);
|
||||
txn->mt_child = NULL;
|
||||
if (rc) {
|
||||
mdb_txn_abort(txn);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
env = txn->mt_env;
|
||||
|
||||
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) {
|
||||
/* update the DB flags */
|
||||
for (i = 2; i<txn->mt_numdbs; i++) {
|
||||
if (txn->mt_dbflags[i] & DB_NEW)
|
||||
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
|
||||
}
|
||||
if (txn->mt_numdbs > env->me_numdbs)
|
||||
env->me_numdbs = txn->mt_numdbs;
|
||||
mdb_dbis_update(txn, 1);
|
||||
txn->mt_numdbs = 2; /* so txn_abort() doesn't close any new handles */
|
||||
mdb_txn_abort(txn);
|
||||
return MDB_SUCCESS;
|
||||
|
|
@ -2160,8 +2175,8 @@ mdb_txn_commit(MDB_txn *txn)
|
|||
parent->mt_next_pgno = txn->mt_next_pgno;
|
||||
parent->mt_flags = txn->mt_flags;
|
||||
|
||||
/* Merge (and close) our cursors with parent's */
|
||||
mdb_cursor_merge(txn);
|
||||
/* Merge our cursors into parent's and close them */
|
||||
mdb_cursors_close(txn, C_SHADOW);
|
||||
|
||||
/* Update parent's DB table. */
|
||||
memcpy(parent->mt_dbs, txn->mt_dbs, txn->mt_numdbs * sizeof(MDB_db));
|
||||
|
|
@ -2220,6 +2235,8 @@ mdb_txn_commit(MDB_txn *txn)
|
|||
return EINVAL;
|
||||
}
|
||||
|
||||
mdb_cursors_close(txn, 0);
|
||||
|
||||
if (!txn->mt_u.dirty_list[0].mid && !(txn->mt_flags & MDB_TXN_DIRTY))
|
||||
goto done;
|
||||
|
||||
|
|
@ -2515,13 +2532,7 @@ sync:
|
|||
done:
|
||||
env->me_pglast = 0;
|
||||
env->me_txn = NULL;
|
||||
/* update the DB flags */
|
||||
for (i = 2; i<txn->mt_numdbs; i++) {
|
||||
if (txn->mt_dbflags[i] & DB_NEW)
|
||||
env->me_dbflags[i] = txn->mt_dbs[i].md_flags | MDB_VALID;
|
||||
}
|
||||
if (txn->mt_numdbs > env->me_numdbs)
|
||||
env->me_numdbs = txn->mt_numdbs;
|
||||
mdb_dbis_update(txn, 1);
|
||||
|
||||
UNLOCK_MUTEX_W(env);
|
||||
free(txn);
|
||||
|
|
@ -3461,7 +3472,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
|
|||
/* silently ignore WRITEMAP when we're only getting read access */
|
||||
flags &= ~MDB_WRITEMAP;
|
||||
} else {
|
||||
if (!((env->me_free_pgs = mdb_midl_alloc()) &&
|
||||
if (!((env->me_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)) &&
|
||||
(env->me_dirty_list = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2)))))
|
||||
rc = ENOMEM;
|
||||
}
|
||||
|
|
@ -3538,7 +3549,7 @@ leave:
|
|||
return rc;
|
||||
}
|
||||
|
||||
/** Destroy resources from mdb_env_open() and clear our readers */
|
||||
/** Destroy resources from mdb_env_open(), clear our readers & DBIs */
|
||||
static void
|
||||
mdb_env_close0(MDB_env *env, int excl)
|
||||
{
|
||||
|
|
@ -3547,6 +3558,10 @@ mdb_env_close0(MDB_env *env, int excl)
|
|||
if (!(env->me_flags & MDB_ENV_ACTIVE))
|
||||
return;
|
||||
|
||||
/* Doing this here since me_dbxs may not exist during mdb_env_close */
|
||||
for (i = env->me_maxdbs; --i > MAIN_DBI; )
|
||||
free(env->me_dbxs[i].md_name.mv_data);
|
||||
|
||||
free(env->me_dbflags);
|
||||
free(env->me_dbxs);
|
||||
free(env->me_path);
|
||||
|
|
@ -3741,9 +3756,9 @@ mdb_env_copy(MDB_env *env, const char *path)
|
|||
ptr += wres;
|
||||
}
|
||||
#endif
|
||||
mdb_txn_abort(txn);
|
||||
|
||||
leave:
|
||||
mdb_txn_abort(txn);
|
||||
if (newfd != INVALID_HANDLE_VALUE)
|
||||
close(newfd);
|
||||
|
||||
|
|
@ -3754,14 +3769,10 @@ void
|
|||
mdb_env_close(MDB_env *env)
|
||||
{
|
||||
MDB_page *dp;
|
||||
int i;
|
||||
|
||||
if (env == NULL)
|
||||
return;
|
||||
|
||||
for (i = env->me_numdbs; --i > MAIN_DBI; )
|
||||
free(env->me_dbxs[i].md_name.mv_data);
|
||||
|
||||
VGMEMP_DESTROY(env);
|
||||
while ((dp = env->me_dpages) != NULL) {
|
||||
VGMEMP_DEFINED(&dp->mp_next, sizeof(dp->mp_next));
|
||||
|
|
@ -4922,8 +4933,7 @@ mdb_cursor_touch(MDB_cursor *mc)
|
|||
if (mc->mc_dbi > MAIN_DBI && !(*mc->mc_dbflag & DB_DIRTY)) {
|
||||
MDB_cursor mc2;
|
||||
MDB_xcursor mcx;
|
||||
mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI,
|
||||
mc->mc_txn->mt_dbs[MAIN_DBI].md_flags & MDB_DUPSORT ? &mcx : NULL);
|
||||
mdb_cursor_init(&mc2, mc->mc_txn, MAIN_DBI, &mcx);
|
||||
rc = mdb_page_search(&mc2, &mc->mc_dbx->md_name, MDB_PS_MODIFY);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -5827,7 +5837,6 @@ int
|
|||
mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
|
||||
{
|
||||
MDB_cursor *mc;
|
||||
MDB_xcursor *mx = NULL;
|
||||
size_t size = sizeof(MDB_cursor);
|
||||
|
||||
if (txn == NULL || ret == NULL || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
|
||||
|
|
@ -5841,13 +5850,11 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
|
|||
size += sizeof(MDB_xcursor);
|
||||
|
||||
if ((mc = malloc(size)) != NULL) {
|
||||
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
|
||||
mx = (MDB_xcursor *)(mc + 1);
|
||||
}
|
||||
mdb_cursor_init(mc, txn, dbi, mx);
|
||||
mdb_cursor_init(mc, txn, dbi, (MDB_xcursor *)(mc + 1));
|
||||
if (txn->mt_cursors) {
|
||||
mc->mc_next = txn->mt_cursors[dbi];
|
||||
txn->mt_cursors[dbi] = mc;
|
||||
mc->mc_flags |= C_UNTRACK;
|
||||
}
|
||||
mc->mc_flags |= C_ALLOCD;
|
||||
} else {
|
||||
|
|
@ -5867,7 +5874,7 @@ mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
|
|||
if (txn == NULL || mc == NULL || mc->mc_dbi >= txn->mt_numdbs)
|
||||
return EINVAL;
|
||||
|
||||
if (txn->mt_cursors)
|
||||
if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors)
|
||||
return EINVAL;
|
||||
|
||||
flags = mc->mc_flags;
|
||||
|
|
@ -5907,7 +5914,7 @@ mdb_cursor_close(MDB_cursor *mc)
|
|||
{
|
||||
if (mc != NULL) {
|
||||
/* remove from txn, if tracked */
|
||||
if (mc->mc_txn->mt_cursors) {
|
||||
if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_cursors) {
|
||||
MDB_cursor **prev = &mc->mc_txn->mt_cursors[mc->mc_dbi];
|
||||
while (*prev && *prev != mc) prev = &(*prev)->mc_next;
|
||||
if (*prev == mc)
|
||||
|
|
@ -7224,6 +7231,7 @@ void mdb_dbi_close(MDB_env *env, MDB_dbi dbi)
|
|||
ptr = env->me_dbxs[dbi].md_name.mv_data;
|
||||
env->me_dbxs[dbi].md_name.mv_data = NULL;
|
||||
env->me_dbxs[dbi].md_name.mv_size = 0;
|
||||
env->me_dbflags[dbi] = 0;
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include "midl.h"
|
||||
|
|
@ -117,15 +118,17 @@ int mdb_midl_insert( MDB_IDL ids, MDB_ID id )
|
|||
}
|
||||
#endif
|
||||
|
||||
MDB_IDL mdb_midl_alloc(void)
|
||||
MDB_IDL mdb_midl_alloc(int num)
|
||||
{
|
||||
MDB_IDL ids = malloc((MDB_IDL_UM_MAX+1) * sizeof(MDB_ID));
|
||||
*ids++ = MDB_IDL_UM_MAX;
|
||||
MDB_IDL ids = malloc((num+2) * sizeof(MDB_ID));
|
||||
if (ids)
|
||||
*ids++ = num;
|
||||
return ids;
|
||||
}
|
||||
|
||||
void mdb_midl_free(MDB_IDL ids)
|
||||
{
|
||||
if (ids)
|
||||
free(ids-1);
|
||||
}
|
||||
|
||||
|
|
@ -141,19 +144,26 @@ int mdb_midl_shrink( MDB_IDL *idp )
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mdb_midl_grow( MDB_IDL *idp, int num )
|
||||
{
|
||||
MDB_IDL idn = *idp-1;
|
||||
/* grow it */
|
||||
idn = realloc(idn, (*idn + num + 2) * sizeof(MDB_ID));
|
||||
if (!idn)
|
||||
return ENOMEM;
|
||||
*idn++ += num;
|
||||
*idp = idn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdb_midl_append( MDB_IDL *idp, MDB_ID id )
|
||||
{
|
||||
MDB_IDL ids = *idp;
|
||||
/* Too big? */
|
||||
if (ids[0] >= ids[-1]) {
|
||||
MDB_IDL idn = ids-1;
|
||||
/* grow it */
|
||||
idn = realloc(idn, (*idn + MDB_IDL_UM_MAX + 1) * sizeof(MDB_ID));
|
||||
if (!idn)
|
||||
return -1;
|
||||
*idn++ += MDB_IDL_UM_MAX;
|
||||
ids = idn;
|
||||
*idp = ids;
|
||||
if (mdb_midl_grow(idp, MDB_IDL_UM_MAX))
|
||||
return ENOMEM;
|
||||
ids = *idp;
|
||||
}
|
||||
ids[0]++;
|
||||
ids[ids[0]] = id;
|
||||
|
|
@ -165,14 +175,9 @@ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app )
|
|||
MDB_IDL ids = *idp;
|
||||
/* Too big? */
|
||||
if (ids[0] + app[0] >= ids[-1]) {
|
||||
MDB_IDL idn = ids-1;
|
||||
/* grow it */
|
||||
idn = realloc(idn, (*idn + app[-1]) * sizeof(MDB_ID));
|
||||
if (!idn)
|
||||
return -1;
|
||||
*idn++ += app[-1];
|
||||
ids = idn;
|
||||
*idp = ids;
|
||||
if (mdb_midl_grow(idp, app[0]))
|
||||
return ENOMEM;
|
||||
ids = *idp;
|
||||
}
|
||||
memcpy(&ids[ids[0]+1], &app[1], app[0] * sizeof(MDB_ID));
|
||||
ids[0] += app[0];
|
||||
|
|
|
|||
|
|
@ -115,10 +115,10 @@ int mdb_midl_insert( MDB_IDL ids, MDB_ID id );
|
|||
#endif
|
||||
|
||||
/** Allocate an IDL.
|
||||
* Allocates memory for an IDL of a default size.
|
||||
* Allocates memory for an IDL of the given size.
|
||||
* @return IDL on success, NULL on failure.
|
||||
*/
|
||||
MDB_IDL mdb_midl_alloc(void);
|
||||
MDB_IDL mdb_midl_alloc(int num);
|
||||
|
||||
/** Free an IDL.
|
||||
* @param[in] ids The IDL to free.
|
||||
|
|
@ -132,6 +132,14 @@ void mdb_midl_free(MDB_IDL ids);
|
|||
*/
|
||||
int mdb_midl_shrink(MDB_IDL *idp);
|
||||
|
||||
/** Grow an IDL.
|
||||
* Add room for num additional elements.
|
||||
* @param[in,out] idp Address of the IDL to grow.
|
||||
* @param[i] num Number of elements to add.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int mdb_midl_grow(MDB_IDL *idp, int num);
|
||||
|
||||
/** Append an ID onto an IDL.
|
||||
* @param[in,out] idp Address of the IDL to append to.
|
||||
* @param[in] id The ID to append.
|
||||
|
|
|
|||
Loading…
Reference in a new issue