]> git.sur5r.net Git - openldap/commitdiff
ITS#7971 Fix reader allocation and me_numreaders
authorHallvard Furuseth <hallvard@openldap.org>
Sat, 17 Jan 2015 05:32:12 +0000 (06:32 +0100)
committerHallvard Furuseth <hallvard@openldap.org>
Sat, 17 Jan 2015 05:32:12 +0000 (06:32 +0100)
libraries/liblmdb/mdb.c

index e2aa170357c1ef84e4550dbe79dbc812c9f2532d..7175276ab077f5250a9469ff75fc6c36220a8294 100644 (file)
@@ -1185,7 +1185,8 @@ struct MDB_env {
        unsigned int    me_psize;       /**< DB page size, inited from me_os_psize */
        unsigned int    me_os_psize;    /**< OS page size, from #GET_PAGESIZE */
        unsigned int    me_maxreaders;  /**< size of the reader table */
-       unsigned int    me_numreaders;  /**< max numreaders set by this env */
+       /** Max #MDB_txninfo.%mti_numreaders of interest to #mdb_env_close() */
+       volatile int    me_close_readers;
        MDB_dbi         me_numdbs;              /**< number of DBs opened */
        MDB_dbi         me_maxdbs;              /**< size of the DB table */
        MDB_PID_T       me_pid;         /**< process ID of this env */
@@ -2603,13 +2604,19 @@ mdb_txn_renew0(MDB_txn *txn)
                                        return MDB_READERS_FULL;
                                }
                                r = &ti->mti_readers[i];
+                               /* Claim the reader slot, carefully since other code
+                                * uses the reader table un-mutexed: First reset the
+                                * slot, next publish it in mti_numreaders.  After
+                                * that, it is safe for mdb_env_close() to touch it.
+                                * When it will be closed, we can finally claim it.
+                                */
+                               r->mr_pid = 0;
                                r->mr_txnid = (txnid_t)-1;
                                r->mr_tid = tid;
-                               r->mr_pid = pid; /* should be written last, see ITS#7971. */
                                if (i == nr)
                                        ti->mti_numreaders = ++nr;
-                               /* Save numreaders for un-mutexed mdb_env_close() */
-                               env->me_numreaders = nr;
+                               env->me_close_readers = nr;
+                               r->mr_pid = pid;
                                UNLOCK_MUTEX(rmutex);
 
                                new_notls = (env->me_flags & MDB_NOTLS);
@@ -4790,8 +4797,12 @@ mdb_env_close0(MDB_env *env, int excl)
                MDB_PID_T pid = env->me_pid;
                /* Clearing readers is done in this function because
                 * me_txkey with its destructor must be disabled first.
+                *
+                * We skip the the reader mutex, so we touch only
+                * data owned by this process (me_close_readers and
+                * our readers), and clear each reader atomically.
                 */
-               for (i = env->me_numreaders; --i >= 0; )
+               for (i = env->me_close_readers; --i >= 0; )
                        if (env->me_txns->mti_readers[i].mr_pid == pid)
                                env->me_txns->mti_readers[i].mr_pid = 0;
 #ifdef _WIN32
@@ -9110,11 +9121,7 @@ mdb_env_info(MDB_env *env, MDB_envinfo *arg)
        arg->me_mapaddr = env->me_metas[toggle]->mm_address;
        arg->me_mapsize = env->me_mapsize;
        arg->me_maxreaders = env->me_maxreaders;
-
-       /* me_numreaders may be zero if this process never used any readers. Use
-        * the shared numreader count if it exists.
-        */
-       arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : env->me_numreaders;
+       arg->me_numreaders = env->me_txns ? env->me_txns->mti_numreaders : 0;
 
        arg->me_last_pgno = env->me_metas[toggle]->mm_last_pg;
        arg->me_last_txnid = env->me_metas[toggle]->mm_txnid;