]> git.sur5r.net Git - openldap/blobdiff - libraries/liblmdb/mdb.c
ITS#7992 Fix memleak in prev change
[openldap] / libraries / liblmdb / mdb.c
index 4ff49500a5567e783165dbafac31bf5565bd6c85..ea9e4729025f4934af2a0e473d268f8b9973385d 100644 (file)
@@ -5,7 +5,7 @@
  *     BerkeleyDB API, but much simplified.
  */
 /*
- * Copyright 2011-2015 Howard Chu, Symas Corp.
+ * Copyright 2011-2016 Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE 1
 #endif
-#ifdef MDB_VL32
+#if defined(MDB_VL32) || defined(__WIN64__)
 #define _FILE_OFFSET_BITS      64
 #endif
 #ifdef _WIN32
@@ -1075,7 +1075,7 @@ typedef struct MDB_db {
        pgno_t          md_branch_pages;        /**< number of internal pages */
        pgno_t          md_leaf_pages;          /**< number of leaf pages */
        pgno_t          md_overflow_pages;      /**< number of overflow pages */
-       pgno_t          md_entries;             /**< number of data items */
+       mdb_size_t      md_entries;             /**< number of data items */
        pgno_t          md_root;                /**< the root page of this tree */
 } MDB_db;
 
@@ -1403,7 +1403,7 @@ struct MDB_env {
 #endif
 #ifdef MDB_VL32
        MDB_ID3L        me_rpages;      /**< like #mt_rpages, but global to env */
-       mdb_mutex_t     me_rpmutex;     /**< control access to #me_rpages */
+       pthread_mutex_t me_rpmutex;     /**< control access to #me_rpages */
 #define MDB_ERPAGE_SIZE        16384
 #define MDB_ERPAGE_MAX (MDB_ERPAGE_SIZE-1)
        unsigned int me_rpcheck;
@@ -1426,7 +1426,7 @@ typedef struct MDB_ntxn {
 #endif
 
        /** max bytes to write in one call */
-#define MAX_WRITE              (0x80000000U >> (sizeof(ssize_t) == 4))
+#define MAX_WRITE              (0x40000000U >> (sizeof(ssize_t) == 4))
 
        /** Check \b txn and \b dbi arguments to a function */
 #define TXN_DBI_EXIST(txn, dbi, validity) \
@@ -1952,7 +1952,7 @@ static void
 mdb_cursor_unref(MDB_cursor *mc)
 {
        int i;
-       if (!mc->mc_pg[0] || IS_SUBP(mc->mc_pg[0]))
+       if (!mc->mc_snum || !mc->mc_pg[0] || IS_SUBP(mc->mc_pg[0]))
                return;
        for (i=0; i<mc->mc_snum; i++)
                mdb_page_unref(mc->mc_txn, mc->mc_pg[i]);
@@ -2428,8 +2428,8 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
                        rc = MDB_MAP_FULL;
                        goto fail;
        }
-#ifdef _WIN32
-       if (env->me_flags & MDB_WRITEMAP) {
+#if defined(_WIN32) && !defined(MDB_VL32)
+       if (!(env->me_flags & MDB_RDONLY)) {
                void *p;
                p = (MDB_page *)(env->me_map + env->me_psize * pgno);
                p = VirtualAlloc(p, env->me_psize * num, MEM_COMMIT,
@@ -3227,7 +3227,7 @@ mdb_txn_end(MDB_txn *txn, unsigned mode)
        if (!txn->mt_parent) {
                MDB_ID3L el = env->me_rpages, tl = txn->mt_rpages;
                unsigned i, x, n = tl[0].mid;
-               LOCK_MUTEX0(env->me_rpmutex);
+               pthread_mutex_lock(&env->me_rpmutex);
                for (i = 1; i <= n; i++) {
                        if (tl[i].mid & (MDB_RPAGE_CHUNK-1)) {
                                /* tmp overflow pages that we didn't share in env */
@@ -3242,7 +3242,7 @@ mdb_txn_end(MDB_txn *txn, unsigned mode)
                                }
                        }
                }
-               UNLOCK_MUTEX(env->me_rpmutex);
+               pthread_mutex_unlock(&env->me_rpmutex);
                tl[0].mid = 0;
                if (mode & MDB_END_FREE)
                        free(tl);
@@ -4272,7 +4272,7 @@ mdb_env_set_mapsize(MDB_env *env, mdb_size_t size)
                        size = meta->mm_mapsize;
                {
                        /* Silently round up to minimum if the size is too small */
-                       size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
+                       mdb_size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
                        if (size < minsize)
                                size = minsize;
                }
@@ -5016,7 +5016,7 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
 #ifdef _WIN32
        env->me_rpmutex = CreateMutex(NULL, FALSE, NULL);
 #else
-       pthread_mutex_init(env->me_rpmutex, NULL);
+       pthread_mutex_init(&env->me_rpmutex, NULL);
 #endif
 #endif
 
@@ -5255,14 +5255,16 @@ mdb_env_close0(MDB_env *env, int excl)
        free(env->me_dbflags);
        free(env->me_path);
        free(env->me_dirty_list);
-       free(env->me_txn0);
 #ifdef MDB_VL32
+       if (env->me_txn0 && env->me_txn0->mt_rpages)
+               free(env->me_txn0->mt_rpages);
        { unsigned int x;
                for (x=1; x<=env->me_rpages[0].mid; x++)
                munmap(env->me_rpages[x].mptr, env->me_rpages[x].mcnt * env->me_psize);
        }
        free(env->me_rpages);
 #endif
+       free(env->me_txn0);
        mdb_midl_free(env->me_free_pgs);
 
        if (env->me_flags & MDB_ENV_TXKEY) {
@@ -5350,9 +5352,10 @@ mdb_env_close0(MDB_env *env, int excl)
        }
 #ifdef MDB_VL32
 #ifdef _WIN32
+       if (env->me_fmh) CloseHandle(env->me_fmh);
        if (env->me_rpmutex) CloseHandle(env->me_rpmutex);
 #else
-       pthread_mutex_destroy(env->me_rpmutex);
+       pthread_mutex_destroy(&env->me_rpmutex);
 #endif
 #endif
 
@@ -5735,7 +5738,7 @@ mdb_rpage_get(MDB_txn *txn, pgno_t pg0, MDB_page **ret)
                                /* if no active ref, see if we can replace in env */
                                if (!tl[x].mref) {
                                        unsigned i;
-                                       LOCK_MUTEX0(env->me_rpmutex);
+                                       pthread_mutex_lock(&env->me_rpmutex);
                                        i = mdb_mid3l_search(el, tl[x].mid);
                                        if (el[i].mref == 1) {
                                                /* just us, replace it */
@@ -5746,7 +5749,7 @@ mdb_rpage_get(MDB_txn *txn, pgno_t pg0, MDB_page **ret)
                                                /* there are others, remove ourself */
                                                el[i].mref--;
                                        }
-                                       UNLOCK_MUTEX(env->me_rpmutex);
+                                       pthread_mutex_unlock(&env->me_rpmutex);
                                }
                        }
                }
@@ -5760,10 +5763,10 @@ notlocal:
        if (tl[0].mid >= MDB_TRPAGE_MAX - txn->mt_rpcheck) {
                unsigned i, y;
                /* purge unref'd pages from our list and unref in env */
-               LOCK_MUTEX0(env->me_rpmutex);
+               pthread_mutex_lock(&env->me_rpmutex);
 retry:
                y = 0;
-               for (i=1; i<tl[0].mid; i++) {
+               for (i=1; i<=tl[0].mid; i++) {
                        if (!tl[i].mref) {
                                if (!y) y = i;
                                /* tmp overflow pages don't go to env */
@@ -5775,7 +5778,7 @@ retry:
                                el[x].mref--;
                        }
                }
-               UNLOCK_MUTEX(env->me_rpmutex);
+               pthread_mutex_unlock(&env->me_rpmutex);
                if (!y) {
                        /* we didn't find any unref'd chunks.
                         * if we're out of room, fail.
@@ -5812,7 +5815,7 @@ retry:
                id3.mid = pgno;
 
                /* search for page in env */
-               LOCK_MUTEX0(env->me_rpmutex);
+               pthread_mutex_lock(&env->me_rpmutex);
                x = mdb_mid3l_search(el, pgno);
                if (x <= el[0].mid && el[x].mid == pgno) {
                        id3.mptr = el[x].mptr;
@@ -5827,23 +5830,23 @@ retry:
                                if (rc)
                                        goto fail;
                                if (!el[x].mref) {
-                                       munmap(el[x].mptr, el[x].mcnt);
+                                       munmap(el[x].mptr, env->me_psize * el[x].mcnt);
                                        el[x].mptr = id3.mptr;
                                        el[x].mcnt = id3.mcnt;
                                } else {
                                        id3.mid = pg0;
-                                       UNLOCK_MUTEX(env->me_rpmutex);
+                                       pthread_mutex_unlock(&env->me_rpmutex);
                                        goto found;
                                }
                        }
                        el[x].mref++;
-                       UNLOCK_MUTEX(env->me_rpmutex);
+                       pthread_mutex_unlock(&env->me_rpmutex);
                        goto found;
                }
                if (el[0].mid >= MDB_ERPAGE_MAX - env->me_rpcheck) {
                        /* purge unref'd pages */
                        unsigned i, y = 0;
-                       for (i=1; i<el[0].mid; i++) {
+                       for (i=1; i<=el[0].mid; i++) {
                                if (!el[i].mref) {
                                        if (!y) y = i;
                                        munmap(el[i].mptr, env->me_psize * el[i].mcnt);
@@ -5857,7 +5860,7 @@ retry:
                                        goto retry;
                                }
                                if (el[0].mid >= MDB_ERPAGE_MAX) {
-                                       UNLOCK_MUTEX(env->me_rpmutex);
+                                       pthread_mutex_unlock(&env->me_rpmutex);
                                        return MDB_MAP_FULL;
                                }
                                env->me_rpcheck /= 2;
@@ -5876,42 +5879,21 @@ retry:
                MAP(rc, env, id3.mptr, len, off);
                if (rc) {
 fail:
-                       UNLOCK_MUTEX(env->me_rpmutex);
+                       pthread_mutex_unlock(&env->me_rpmutex);
                        return rc;
                }
-               /* If this page is far enough from the end of the env, scan for
-                * any overflow pages that would spill onto another block.
-                * Note we must compare against mt_last_pgno, the last written
-                * page in the environment. Not mt_next_pgno, which increases
-                * for every newly allocated (but not yet written) page. If
-                * we scanned beyond the last written page we'd get a bus error.
-                */
-               if (pgno + MDB_RPAGE_CHUNK <= txn->mt_last_pgno) {
-                       int i;
-                       char *cp = (char *)id3.mptr + rem * env->me_psize;
-                       for (i=rem; i<MDB_RPAGE_CHUNK;) {
-                               p = (MDB_page *)cp;
-                               if (IS_OVERFLOW(p)) {
-                                       int nop = p->mp_pages;
-                                       if (nop + i > MDB_RPAGE_CHUNK) {
-                                               munmap(id3.mptr, len);
-                                               id3.mcnt = nop + i;
-                                               len = id3.mcnt * env->me_psize;
-                                               MAP(rc, env, id3.mptr, len, off);
-                                               if (rc)
-                                                       goto fail;
-                                               break;
-                                       }
-                                       i += nop;
-                                       cp += nop * env->me_psize;
-                               } else {
-                                       i++;
-                                       cp += env->me_psize;
-                               }
-                       }
+               /* check for overflow size */
+               p = (MDB_page *)((char *)id3.mptr + rem * env->me_psize);
+               if (IS_OVERFLOW(p) && p->mp_pages + rem > id3.mcnt) {
+                       id3.mcnt = p->mp_pages + rem;
+                       munmap(id3.mptr, len);
+                       len = id3.mcnt * env->me_psize;
+                       MAP(rc, env, id3.mptr, len, off);
+                       if (rc)
+                               goto fail;
                }
                mdb_mid3l_insert(el, &id3);
-               UNLOCK_MUTEX(env->me_rpmutex);
+               pthread_mutex_unlock(&env->me_rpmutex);
 found:
                mdb_mid3l_insert(tl, &id3);
        } else {
@@ -6455,8 +6437,10 @@ mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
 
        DPRINTF(("cursor_next: top page is %"Y"u in cursor %p",
                mdb_dbg_pgno(mp), (void *) mc));
-       if (mc->mc_flags & C_DEL)
+       if (mc->mc_flags & C_DEL) {
+               mc->mc_flags ^= C_DEL;
                goto skip;
+       }
 
        if (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mp)) {
                DPUTS("=====> move to next sibling page");
@@ -6542,6 +6526,8 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
        DPRINTF(("cursor_prev: top page is %"Y"u in cursor %p",
                mdb_dbg_pgno(mp), (void *) mc));
 
+       mc->mc_flags &= ~(C_EOF|C_DEL);
+
        if (mc->mc_ki[mc->mc_top] == 0)  {
                DPUTS("=====> move to prev sibling page");
                if ((rc = mdb_cursor_sibling(mc, 0)) != MDB_SUCCESS) {
@@ -6996,6 +6982,28 @@ fetchm:
                        }
                }
                break;
+       case MDB_PREV_MULTIPLE:
+               if (data == NULL) {
+                       rc = EINVAL;
+                       break;
+               }
+               if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+                       rc = MDB_INCOMPATIBLE;
+                       break;
+               }
+               if (!(mc->mc_flags & C_INITIALIZED))
+                       rc = mdb_cursor_first(mc, key, data);
+               else {
+                       MDB_cursor *mx = &mc->mc_xcursor->mx_cursor;
+                       if (mx->mc_flags & C_INITIALIZED) {
+                               rc = mdb_cursor_sibling(mx, 0);
+                               if (rc == MDB_SUCCESS)
+                                       goto fetchm;
+                       } else {
+                               rc = MDB_NOTFOUND;
+                       }
+               }
+               break;
        case MDB_NEXT:
        case MDB_NEXT_DUP:
        case MDB_NEXT_NODUP:
@@ -7537,7 +7545,7 @@ new_sub:
                 */
                if (do_sub) {
                        int xflags, new_dupdata;
-                       size_t ecount;
+                       mdb_size_t ecount;
 put_sub:
                        xdata.mv_size = 0;
                        xdata.mv_data = "";
@@ -8252,7 +8260,7 @@ mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
 
 /* Return the count of duplicate data items for the current key */
 int
-mdb_cursor_count(MDB_cursor *mc, size_t *countp)
+mdb_cursor_count(MDB_cursor *mc, mdb_size_t *countp)
 {
        MDB_node        *leaf;
 
@@ -9976,7 +9984,7 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd)
        MDB_txn *txn = NULL;
        mdb_mutexref_t wmutex = NULL;
        int rc;
-       size_t wsize;
+       mdb_size_t wsize, w3;
        char *ptr;
 #ifdef _WIN32
        DWORD len, w2;
@@ -10035,15 +10043,15 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd)
        if (rc)
                goto leave;
 
-       w2 = txn->mt_next_pgno * env->me_psize;
+       w3 = txn->mt_next_pgno * env->me_psize;
        {
                mdb_size_t fsize = 0;
                if ((rc = mdb_fsize(env->me_fd, &fsize)))
                        goto leave;
-               if (w2 > fsize)
-                       w2 = fsize;
+               if (w3 > fsize)
+                       w3 = fsize;
        }
-       wsize = w2 - wsize;
+       wsize = w3 - wsize;
        while (wsize > 0) {
                if (wsize > MAX_WRITE)
                        w2 = MAX_WRITE;
@@ -10112,7 +10120,7 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
 #ifdef _WIN32
        rc = utf8_to_utf16(lpath, -1, &wpath, NULL);
        if (rc)
-               return rc;
+               goto leave;
        newfd = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
                                FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
        free(wpath);