]> git.sur5r.net Git - openldap/blobdiff - libraries/liblmdb/mdb.c
ITS#7955, #7671 fix MDB_PREV_DUP
[openldap] / libraries / liblmdb / mdb.c
index 74d3678c45e44e75b10967fb7578ad3d4314a558..a7659a5b3c8217399c37d32fb89d08e31925edf7 100644 (file)
@@ -90,7 +90,7 @@ extern int cacheflush(char *addr, int nbytes, int cache);
 #include <time.h>
 #include <unistd.h>
 
-#if defined(__sun)
+#if defined(__sun) || defined(ANDROID)
 /* Most platforms have posix_memalign, older may only have memalign */
 #define HAVE_MEMALIGN  1
 #include <malloc.h>
@@ -1110,6 +1110,7 @@ struct MDB_env {
        MDB_meta        *me_metas[2];   /**< pointers to the two meta pages */
        void            *me_pbuf;               /**< scratch area for DUPSORT put() */
        MDB_txn         *me_txn;                /**< current write transaction */
+       MDB_txn         *me_txn0;               /**< prealloc'd write transaction */
        size_t          me_mapsize;             /**< size of the data memory map */
        off_t           me_size;                /**< current file size */
        pgno_t          me_maxpg;               /**< me_mapsize / me_psize */
@@ -1117,6 +1118,7 @@ struct MDB_env {
        uint16_t        *me_dbflags;    /**< array of flags from MDB_db.md_flags */
        unsigned int    *me_dbiseqs;    /**< array of dbi sequence numbers */
        pthread_key_t   me_txkey;       /**< thread-key for readers */
+       txnid_t         me_pgoldest;    /**< ID of oldest reader last time we looked */
        MDB_pgstate     me_pgstate;             /**< state of old pages from freeDB */
 #      define          me_pglast       me_pgstate.mf_pglast
 #      define          me_pghead       me_pgstate.mf_pghead
@@ -1946,7 +1948,7 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
 #else
        enum { Paranoid = 0, Max_retries = INT_MAX /*infinite*/ };
 #endif
-       int rc, retry = num * 20;
+       int rc, retry = num * 60;
        MDB_txn *txn = mc->mc_txn;
        MDB_env *env = txn->mt_env;
        pgno_t pgno, *mop = env->me_pghead;
@@ -1955,6 +1957,7 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
        txnid_t oldest = 0, last;
        MDB_cursor_op op;
        MDB_cursor m2;
+       int found_old = 0;
 
        /* If there are any loose pages, just use them */
        if (num == 1 && txn->mt_loose_pgs) {
@@ -1996,8 +1999,8 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
 
                if (op == MDB_FIRST) {  /* 1st iteration */
                        /* Prepare to fetch more and coalesce */
-                       oldest = mdb_find_oldest(txn);
                        last = env->me_pglast;
+                       oldest = env->me_pgoldest;
                        mdb_cursor_init(&m2, txn, FREE_DBI, NULL);
                        if (last) {
                                op = MDB_SET_RANGE;
@@ -2012,8 +2015,15 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
 
                last++;
                /* Do not fetch more if the record will be too recent */
-               if (oldest <= last)
-                       break;
+               if (oldest <= last) {
+                       if (!found_old) {
+                               oldest = mdb_find_oldest(txn);
+                               env->me_pgoldest = oldest;
+                               found_old = 1;
+                       }
+                       if (oldest <= last)
+                               break;
+               }
                rc = mdb_cursor_get(&m2, &key, NULL, op);
                if (rc) {
                        if (rc == MDB_NOTFOUND)
@@ -2021,8 +2031,15 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
                        goto fail;
                }
                last = *(txnid_t*)key.mv_data;
-               if (oldest <= last)
-                       break;
+               if (oldest <= last) {
+                       if (!found_old) {
+                               oldest = mdb_find_oldest(txn);
+                               env->me_pgoldest = oldest;
+                               found_old = 1;
+                       }
+                       if (oldest <= last)
+                               break;
+               }
                np = m2.mc_pg[m2.mc_top];
                leaf = NODEPTR(np, m2.mc_ki[m2.mc_top]);
                if ((rc = mdb_node_read(txn, leaf, &data)) != MDB_SUCCESS)
@@ -2607,6 +2624,11 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
        }
        size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1);
        if (!(flags & MDB_RDONLY)) {
+               if (!parent) {
+                       txn = env->me_txn0;
+                       txn->mt_flags = 0;
+                       goto ok;
+               }
                size += env->me_maxdbs * sizeof(MDB_cursor *);
                /* child txns use parent's dbiseqs */
                if (!parent)
@@ -2634,6 +2656,7 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
        }
        txn->mt_env = env;
 
+ok:
        if (parent) {
                unsigned int i;
                txn->mt_u.dirty_list = malloc(sizeof(MDB_ID2)*MDB_IDL_UM_SIZE);
@@ -2676,9 +2699,10 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret)
        } else {
                rc = mdb_txn_renew0(txn);
        }
-       if (rc)
-               free(txn);
-       else {
+       if (rc) {
+               if (txn != env->me_txn0)
+                       free(txn);
+       } else {
                *ret = txn;
                DPRINTF(("begin txn %"Z"u%c %p on mdbenv %p, root page %"Z"u",
                        txn->mt_txnid, (txn->mt_flags & MDB_TXN_RDONLY) ? 'r' : 'w',
@@ -2750,12 +2774,27 @@ mdb_txn_reset0(MDB_txn *txn, const char *act)
                txn->mt_numdbs = 0;             /* close nothing if called again */
                txn->mt_dbxs = NULL;    /* mark txn as reset */
        } else {
-               mdb_cursors_close(txn, 0);
+               pgno_t *pghead = env->me_pghead;
+               env->me_pghead = NULL;
+               env->me_pglast = 0;
 
                if (!(env->me_flags & MDB_WRITEMAP)) {
                        mdb_dlist_free(txn);
                }
-               mdb_midl_free(env->me_pghead);
+
+               if (!txn->mt_parent) {
+                       if (mdb_midl_shrink(&txn->mt_free_pgs))
+                               env->me_free_pgs = txn->mt_free_pgs;
+
+                       env->me_txn = NULL;
+                       /* The writer mutex was locked in mdb_txn_begin. */
+                       if (env->me_txns)
+                               UNLOCK_MUTEX_W(env);
+               }
+
+               mdb_cursors_close(txn, 0);
+
+               mdb_midl_free(pghead);
 
                if (txn->mt_parent) {
                        txn->mt_parent->mt_child = NULL;
@@ -2763,18 +2802,7 @@ mdb_txn_reset0(MDB_txn *txn, const char *act)
                        mdb_midl_free(txn->mt_free_pgs);
                        mdb_midl_free(txn->mt_spill_pgs);
                        free(txn->mt_u.dirty_list);
-                       return;
                }
-
-               if (mdb_midl_shrink(&txn->mt_free_pgs))
-                       env->me_free_pgs = txn->mt_free_pgs;
-               env->me_pghead = NULL;
-               env->me_pglast = 0;
-
-               env->me_txn = NULL;
-               /* The writer mutex was locked in mdb_txn_begin. */
-               if (env->me_txns)
-                       UNLOCK_MUTEX_W(env);
        }
 }
 
@@ -2805,7 +2833,8 @@ mdb_txn_abort(MDB_txn *txn)
        if ((txn->mt_flags & MDB_TXN_RDONLY) && txn->mt_u.reader)
                txn->mt_u.reader->mr_pid = 0;
 
-       free(txn);
+       if (txn != txn->mt_env->me_txn0)
+               free(txn);
 }
 
 /** Save the freelist as of this transaction to the freeDB.
@@ -3358,7 +3387,8 @@ done:
 
        if (env->me_txns)
                UNLOCK_MUTEX_W(env);
-       free(txn);
+       if (txn != env->me_txn0)
+               free(txn);
 
        return MDB_SUCCESS;
 
@@ -3603,11 +3633,9 @@ fail:
                env->me_flags |= MDB_FATAL_ERROR;
                return rc;
        }
-done:
        /* MIPS has cache coherency issues, this is a no-op everywhere else */
-       if (!(env->me_flags & MDB_WRITEMAP)) {
-               CACHEFLUSH(env->me_map + off, len, DCACHE);
-       }
+       CACHEFLUSH(env->me_map + off, len, DCACHE);
+done:
        /* Memory ordering issues are irrelevant; since the entire writer
         * is wrapped by wmutex, all of these changes will become visible
         * after the wmutex is unlocked. Since the DB is multi-version,
@@ -4491,6 +4519,22 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
                if (!((flags & MDB_RDONLY) ||
                          (env->me_pbuf = calloc(1, env->me_psize))))
                        rc = ENOMEM;
+               if (!(flags & MDB_RDONLY)) {
+                       MDB_txn *txn;
+                       int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs *
+                               (sizeof(MDB_db)+sizeof(MDB_cursor)+sizeof(unsigned int)+1);
+                       txn = calloc(1, size);
+                       if (txn) {
+                               txn->mt_dbs = (MDB_db *)((char *)txn + tsize);
+                               txn->mt_cursors = (MDB_cursor **)(txn->mt_dbs + env->me_maxdbs);
+                               txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs);
+                               txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs);
+                               txn->mt_env = env;
+                               env->me_txn0 = txn;
+                       } else {
+                               rc = ENOMEM;
+                       }
+               }
        }
 
 leave:
@@ -4520,6 +4564,7 @@ mdb_env_close0(MDB_env *env, int excl)
        free(env->me_dbxs);
        free(env->me_path);
        free(env->me_dirty_list);
+       free(env->me_txn0);
        mdb_midl_free(env->me_free_pgs);
 
        if (env->me_flags & MDB_ENV_TXKEY) {
@@ -5383,11 +5428,11 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
                                        }
                                        return rc;
                                }
-                       } else {
-                               mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
-                               if (op == MDB_PREV_DUP)
-                                       return MDB_NOTFOUND;
                        }
+               } else {
+                       mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF);
+                       if (op == MDB_PREV_DUP)
+                               return MDB_NOTFOUND;
                }
        }
 
@@ -5861,8 +5906,7 @@ fetchm:
                        MDB_node *leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
                        if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
                                MDB_GET_KEY(leaf, key);
-                               if (data)
-                                       rc = mdb_node_read(mc->mc_txn, leaf, data);
+                               rc = mdb_node_read(mc->mc_txn, leaf, data);
                                break;
                        }
                }