]> git.sur5r.net Git - openldap/blobdiff - libraries/libmdb/mdb.c
Keep re-using dpages instead of freeing them
[openldap] / libraries / libmdb / mdb.c
index 30037849858b05ad2b383f2ddaf2e8192228e7d7..d197facbf5ba231baed0508f7480e0d72e4c8545 100644 (file)
@@ -55,6 +55,14 @@ typedef ULONG                pgno_t;
 
 #include "midl.h"
 
+/* Note: If O_DSYNC is undefined but exists in /usr/include,
+ * preferably set some compiler flag to get the definition.
+ * Otherwise compile with the less efficient -DMDB_DSYNC=O_SYNC.
+ */
+#ifndef MDB_DSYNC
+# define MDB_DSYNC     O_DSYNC
+#endif
+
 #ifndef DEBUG
 #define DEBUG 1
 #endif
@@ -178,7 +186,7 @@ typedef struct MDB_page {           /* represents a page of storage */
 #define IS_BRANCH(p)    F_ISSET((p)->mp_flags, P_BRANCH)
 #define IS_OVERFLOW(p)  F_ISSET((p)->mp_flags, P_OVERFLOW)
 
-#define OVPAGES(size, psize)   (PAGEHDRSZ + size + psize - 1) / psize;
+#define OVPAGES(size, psize)   ((PAGEHDRSZ-1 + (size)) / (psize) + 1)
 
 typedef struct MDB_db {
        uint32_t        md_pad;
@@ -252,7 +260,7 @@ struct MDB_cursor {
        struct MDB_xcursor      *mc_xcursor;
 };
 
-#define METADATA(p)     ((void *)((char *)p + PAGEHDRSZ))
+#define METADATA(p)     ((void *)((char *)(p) + PAGEHDRSZ))
 
 typedef struct MDB_node {
 #define mn_pgno                 mn_p.np_pgno
@@ -331,6 +339,7 @@ struct MDB_env {
        MDB_db          *me_dbs[2];
        MDB_oldpages *me_pghead;
        pthread_key_t   me_txkey;       /* thread-key for readers */
+       MDB_dpage       *me_dpages;
        pgno_t          me_free_pgs[MDB_IDL_UM_SIZE];
        MIDL2           me_dirty_list[MDB_IDL_DB_SIZE];
 };
@@ -457,7 +466,7 @@ mdb_version(int *maj, int *min, int *pat)
        return MDB_VERSION_STRING;
 }
 
-static const char *errstr[] = {
+static char *const errstr[] = {
        "MDB_KEYEXIST: Key/data pair already exists",
        "MDB_NOTFOUND: No matching key/data pair found",
        "MDB_PAGE_NOTFOUND: Requested page not found",
@@ -473,7 +482,7 @@ mdb_strerror(int err)
                return ("Successful return: 0");
 
        if (err >= MDB_KEYEXIST && err <= MDB_VERSION_MISMATCH)
-               return (char *)errstr[err - MDB_KEYEXIST];
+               return errstr[err - MDB_KEYEXIST];
 
        return strerror(err);
 }
@@ -602,8 +611,13 @@ mdb_alloc_page(MDB_txn *txn, MDB_page *parent, unsigned int parent_idx, int num)
                if (txn->mt_next_pgno + num >= txn->mt_env->me_maxpg)
                        return NULL;
        }
-       if ((dp = malloc(txn->mt_env->me_psize * num + sizeof(MDB_dhead))) == NULL)
-               return NULL;
+       if (txn->mt_env->me_dpages && num == 1) {
+               dp = txn->mt_env->me_dpages;
+               txn->mt_env->me_dpages = (MDB_dpage *)dp->h.md_parent;
+       } else {
+               if ((dp = malloc(txn->mt_env->me_psize * num + sizeof(MDB_dhead))) == NULL)
+                       return NULL;
+       }
        dp->h.md_num = num;
        dp->h.md_parent = parent;
        dp->h.md_pi = parent_idx;
@@ -763,11 +777,20 @@ mdb_txn_abort(MDB_txn *txn)
                txn->mt_u.reader->mr_txnid = 0;
        } else {
                MDB_oldpages *mop;
+               MDB_dpage *dp;
                unsigned int i;
 
-               /* Discard all dirty pages. */
-               for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++)
-                       free(txn->mt_u.dirty_list[i].mptr);
+               /* return all dirty pages to dpage list */
+               for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++) {
+                       dp = txn->mt_u.dirty_list[i].mptr;
+                       if (dp->h.md_num == 1) {
+                               dp->h.md_parent = (MDB_page *)txn->mt_env->me_dpages;
+                               txn->mt_env->me_dpages = dp;
+                       } else {
+                               /* large pages just get freed directly */
+                               free(dp);
+                       }
+               }
 
                while ((mop = txn->mt_env->me_pghead)) {
                        txn->mt_env->me_pghead = mop->mo_next;
@@ -945,8 +968,16 @@ mdb_txn_commit(MDB_txn *txn)
 
        /* Drop the dirty pages.
         */
-       for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++)
-               free(txn->mt_u.dirty_list[i].mptr);
+       for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++) {
+               dp = txn->mt_u.dirty_list[i].mptr;
+               if (dp->h.md_num == 1) {
+                       dp->h.md_parent = (MDB_page *)txn->mt_env->me_dpages;
+                       txn->mt_env->me_dpages = dp;
+               } else {
+                       free(dp);
+               }
+               txn->mt_u.dirty_list[i].mid = 0;
+       }
 
        if ((n = mdb_env_sync(env, 0)) != 0 ||
            (n = mdb_env_write_meta(txn)) != MDB_SUCCESS) {
@@ -1407,7 +1438,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mode_t mode)
        if ((rc = mdb_env_open2(env, flags)) == MDB_SUCCESS) {
                /* synchronous fd for meta writes */
                if (!(flags & (MDB_RDONLY|MDB_NOSYNC)))
-                       oflags |= O_DSYNC;
+                       oflags |= MDB_DSYNC;
                if ((env->me_mfd = open(dpath, oflags, mode)) == -1) {
                        rc = errno;
                        goto leave;
@@ -1442,9 +1473,17 @@ leave:
 void
 mdb_env_close(MDB_env *env)
 {
+       MDB_dpage *dp;
+
        if (env == NULL)
                return;
 
+       while (env->me_dpages) {
+               dp = env->me_dpages;
+               env->me_dpages = (MDB_dpage *)dp->h.md_parent;
+               free(dp);
+       }
+
        free(env->me_dbs[1]);
        free(env->me_dbs[0]);
        free(env->me_dbxs);