]> git.sur5r.net Git - openldap/commitdiff
ITS#7789 persist mapsize changes
authorHoward Chu <hyc@symas.com>
Wed, 9 Jul 2014 02:06:45 +0000 (19:06 -0700)
committerHoward Chu <hyc@symas.com>
Wed, 9 Jul 2014 02:18:02 +0000 (19:18 -0700)
Write decreases too, not just increases. Check for any size change
that was not requested by this process.

libraries/liblmdb/lmdb.h
libraries/liblmdb/mdb.c

index 1a04682b1a46ebcf45722c62bd5a2717732a5906..068088ccd0d36ece9bccebe804c71ee2ba6c3fb4 100644 (file)
@@ -782,7 +782,10 @@ int  mdb_env_get_fd(MDB_env *env, mdb_filehandle_t *fd);
         * This function should be called after #mdb_env_create() and before #mdb_env_open().
         * It may be called at later times if no transactions are active in
         * this process. Note that the library does not check for this condition,
-        * the caller must ensure it explicitly.
+        * the caller must ensure it explicitly. The new size takes effect
+        * immediately for the current process but will not be persisted to
+        * any others until a write transaction has been committed by the
+        * current process.
         *
         * If the mapsize is changed by another process, #mdb_txn_begin() will
         * return #MDB_MAP_RESIZED. This function may be called with a size
index 267a6e3951e14f67e4f10ee814c2064a37bc0b46..fd48ff136f7f7a212d4495d2d71f847c760441ac 100644 (file)
@@ -1071,6 +1071,8 @@ struct MDB_env {
        HANDLE          me_mfd;                 /**< just for writing the meta pages */
        /** Failed to update the meta page. Probably an I/O error. */
 #define        MDB_FATAL_ERROR 0x80000000U
+       /** We're explicitly changing the mapsize. */
+#define        MDB_RESIZING    0x40000000U
        /** Some fields are initialized. */
 #define        MDB_ENV_ACTIVE  0x20000000U
        /** me_txkey is set */
@@ -2492,7 +2494,9 @@ mdb_txn_renew0(MDB_txn *txn)
        }
        txn->mt_dbflags[0] = txn->mt_dbflags[1] = DB_VALID;
 
-       if (env->me_maxpg < txn->mt_next_pgno) {
+       /* If we didn't ask for a resize, but the size changed, fail */
+       if (!(env->me_flags & MDB_RESIZING)
+               && env->me_mapsize != meta->mm_mapsize) {
                mdb_txn_reset0(txn, "renew0-mapfail");
                if (new_notls) {
                        txn->mt_u.reader->mr_pid = 0;
@@ -3216,8 +3220,13 @@ mdb_txn_commit(MDB_txn *txn)
        mdb_cursors_close(txn, 0);
 
        if (!txn->mt_u.dirty_list[0].mid &&
-               !(txn->mt_flags & (MDB_TXN_DIRTY|MDB_TXN_SPILLS)))
+               !(txn->mt_flags & (MDB_TXN_DIRTY|MDB_TXN_SPILLS))) {
+               if ((env->me_flags & MDB_RESIZING)
+                       && (rc = mdb_env_write_meta(txn))) {
+                       goto fail;
+               }
                goto done;
+       }
 
        DPRINTF(("committing txn %"Z"u %p on mdbenv %p, root page %"Z"u",
            txn->mt_txnid, (void*)txn, (void*)env, txn->mt_dbs[MAIN_DBI].md_root));
@@ -3431,9 +3440,11 @@ mdb_env_write_meta(MDB_txn *txn)
        mp = env->me_metas[toggle];
 
        if (env->me_flags & MDB_WRITEMAP) {
-               /* Persist any increases of mapsize config */
-               if (env->me_mapsize > mp->mm_mapsize)
+               /* Persist any changes of mapsize config */
+               if (env->me_flags & MDB_RESIZING) {
                        mp->mm_mapsize = env->me_mapsize;
+                       env->me_flags ^= MDB_RESIZING;
+               }
                mp->mm_dbs[0] = txn->mt_dbs[0];
                mp->mm_dbs[1] = txn->mt_dbs[1];
                mp->mm_last_pg = txn->mt_next_pgno - 1;
@@ -3461,10 +3472,11 @@ mdb_env_write_meta(MDB_txn *txn)
        metab.mm_last_pg = env->me_metas[toggle]->mm_last_pg;
 
        ptr = (char *)&meta;
-       if (env->me_mapsize > mp->mm_mapsize) {
-               /* Persist any increases of mapsize config */
+       if (env->me_flags & MDB_RESIZING) {
+               /* Persist any changes of mapsize config */
                meta.mm_mapsize = env->me_mapsize;
                off = offsetof(MDB_meta, mm_mapsize);
+               env->me_flags ^= MDB_RESIZING;
        } else {
                off = offsetof(MDB_meta, mm_dbs[0].md_depth);
        }
@@ -3652,19 +3664,25 @@ mdb_env_set_mapsize(MDB_env *env, size_t size)
         * sure there are no active txns.
         */
        if (env->me_map) {
-               int rc;
+               int rc, change = 0;
                void *old;
                if (env->me_txn)
                        return EINVAL;
                if (!size)
                        size = env->me_metas[mdb_env_pick_meta(env)]->mm_mapsize;
-               else if (size < env->me_mapsize) {
-                       /* If the configured size is smaller, make sure it's
-                        * still big enough. Silently round up to minimum if not.
-                        */
-                       size_t minsize = (env->me_metas[mdb_env_pick_meta(env)]->mm_last_pg + 1) * env->me_psize;
-                       if (size < minsize)
-                               size = minsize;
+               else {
+                       if (size < env->me_mapsize) {
+                               /* If the configured size is smaller, make sure it's
+                                * still big enough. Silently round up to minimum if not.
+                                */
+                               size_t minsize = (env->me_metas[mdb_env_pick_meta(env)]->mm_last_pg + 1) * env->me_psize;
+                               if (size < minsize)
+                                       size = minsize;
+                       }
+                       /* nothing actually changed */
+                       if (size == env->me_mapsize)
+                               return MDB_SUCCESS;
+                       change = 1;
                }
                munmap(env->me_map, env->me_mapsize);
                env->me_mapsize = size;
@@ -3672,6 +3690,8 @@ mdb_env_set_mapsize(MDB_env *env, size_t size)
                rc = mdb_env_map(env, old, 1);
                if (rc)
                        return rc;
+               if (change)
+                       env->me_flags |= MDB_RESIZING;
        }
        env->me_mapsize = size;
        if (env->me_psize)