]> git.sur5r.net Git - openldap/commitdiff
Merge remote-tracking branch 'origin/mdb.master'
authorHoward Chu <hyc@openldap.org>
Tue, 18 Mar 2014 12:40:30 +0000 (05:40 -0700)
committerHoward Chu <hyc@openldap.org>
Tue, 18 Mar 2014 12:40:30 +0000 (05:40 -0700)
12 files changed:
libraries/liblmdb/lmdb.h
libraries/liblmdb/mdb.c
libraries/liblmdb/mtest.c
libraries/liblmdb/mtest2.c
libraries/liblmdb/mtest3.c
libraries/liblmdb/mtest4.c
libraries/liblmdb/mtest5.c
libraries/liblmdb/mtest6.c
libraries/liblmdb/sample-bdb.c [deleted file]
libraries/liblmdb/sample-bdb.txt [new file with mode: 0644]
libraries/liblmdb/sample-mdb.c [deleted file]
libraries/liblmdb/sample-mdb.txt [new file with mode: 0644]

index 2ebd43f3daedf7817786deaddfb7f97821e168d9..62f0a485dea8ec15a1ff4fa94487eb84d0296536 100644 (file)
@@ -668,7 +668,8 @@ void mdb_env_close(MDB_env *env);
        /** @brief Set environment flags.
         *
         * This may be used to set some flags in addition to those from
-        * #mdb_env_open(), or to unset these flags.
+        * #mdb_env_open(), or to unset these flags.  If several threads
+        * change the flags at the same time, the result is undefined.
         * @param[in] env An environment handle returned by #mdb_env_create()
         * @param[in] flags The flags to change, bitwise OR'ed together
         * @param[in] onoff A non-zero value sets the flags, zero clears them.
@@ -829,7 +830,7 @@ typedef void MDB_assert_func(MDB_env *env, const char *msg);
         * Disabled if liblmdb is buillt with NDEBUG.
         * @note This hack should become obsolete as lmdb's error handling matures.
         * @param[in] env An environment handle returned by #mdb_env_create().
-        * @parem[in] func An #MDB_assert_func function, or 0.
+        * @param[in] func An #MDB_assert_func function, or 0.
         * @return A non-zero error value on failure and 0 on success.
         */
 int  mdb_env_set_assert(MDB_env *env, MDB_assert_func *func);
@@ -1333,7 +1334,7 @@ int  mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
         * <ul>
         *      <li>#MDB_CURRENT - overwrite the data of the key/data pair to which
         *              the cursor refers with the specified data item. The \b key
-        *              parameter is ignored.
+        *              parameter is ignored.  The \b data size must match the original.
         *      <li>#MDB_NODUPDATA - enter the new key/data pair only if it does not
         *              already appear in the database. This flag may only be specified
         *              if the database was opened with #MDB_DUPSORT. The function will
index 7e2905891eb770c4d6eb53f751bd05b2738a0c7a..71b025fa68fd970504cd42ae1a80a7930ed567f7 100644 (file)
@@ -352,7 +352,7 @@ static txnid_t mdb_debug_start;
 
        /**     @brief The maximum size of a database page.
         *
-        *      This is 32k, since it must fit in #MDB_page.#mp_upper.
+        *      This is 32k, since it must fit in #MDB_page.%mp_upper.
         *
         *      LMDB will use database pages < OS pages if needed.
         *      That causes more I/O in write transactions: The OS must
@@ -936,12 +936,12 @@ struct MDB_txn {
  *     @{
  */
 #define MDB_TXN_RDONLY         0x01            /**< read-only transaction */
-#define MDB_TXN_ERROR          0x02            /**< an error has occurred */
+#define MDB_TXN_ERROR          0x02            /**< txn is unusable after an error */
 #define MDB_TXN_DIRTY          0x04            /**< must write, even if dirty list is empty */
 #define MDB_TXN_SPILLS         0x08            /**< txn or a parent has spilled pages */
 /** @} */
        unsigned int    mt_flags;               /**< @ref mdb_txn */
-       /** dirty_list room: Array size - #dirty pages visible to this txn.
+       /** #dirty_list room: Array size - \#dirty pages visible to this txn.
         *      Includes ancestor txns' dirty pages not hidden by other txns'
         *      dirty/spilled pages. Thus commit(nested txn) has room to merge
         *      dirty_list into mt_parent after freeing hidden mt_parent pages.
@@ -1034,8 +1034,6 @@ struct MDB_env {
 #define        MDB_ENV_ACTIVE  0x20000000U
        /** me_txkey is set */
 #define        MDB_ENV_TXKEY   0x10000000U
-       /** Have liveness lock in reader table */
-#define        MDB_LIVE_READER 0x08000000U
        uint32_t        me_flags;               /**< @ref 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 */
@@ -1071,6 +1069,7 @@ struct MDB_env {
 #if !(MDB_MAXKEYSIZE)
        unsigned int    me_maxkey;      /**< max size of a key */
 #endif
+       int             me_live_reader;         /**< have liveness lock in reader table */
 #ifdef _WIN32
        int             me_pidquery;            /**< Used in OpenProcess */
        HANDLE          me_rmutex;              /* Windows mutexes don't reside in shared mem */
@@ -1096,9 +1095,13 @@ typedef struct MDB_ntxn {
 #define MDB_COMMIT_PAGES       IOV_MAX
 #endif
 
-       /* max bytes to write in one call */
+       /** max bytes to write in one call */
 #define MAX_WRITE              (0x80000000U >> (sizeof(ssize_t) == 4))
 
+       /** Check \b txn and \b dbi arguments to a function */
+#define TXN_DBI_EXIST(txn, dbi) \
+       ((txn) && (dbi) < (txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & DB_VALID))
+
 static int  mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp);
 static int  mdb_page_new(MDB_cursor *mc, uint32_t flags, int num, MDB_page **mp);
 static int  mdb_page_touch(MDB_cursor *mc);
@@ -1142,7 +1145,8 @@ static int        mdb_update_key(MDB_cursor *mc, MDB_val *key);
 static void    mdb_cursor_pop(MDB_cursor *mc);
 static int     mdb_cursor_push(MDB_cursor *mc, MDB_page *mp);
 
-static int     mdb_cursor_del0(MDB_cursor *mc, MDB_node *leaf);
+static int     mdb_cursor_del0(MDB_cursor *mc);
+static int     mdb_del0(MDB_txn *txn, MDB_dbi dbi, MDB_val *key, MDB_val *data, unsigned flags);
 static int     mdb_cursor_sibling(MDB_cursor *mc, int move_right);
 static int     mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op);
 static int     mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op);
@@ -1283,18 +1287,55 @@ mdb_dkey(MDB_val *key, char *buf)
        return buf;
 }
 
+static const char *
+mdb_leafnode_type(MDB_node *n)
+{
+       static char *const tp[2][2] = {{"", ": DB"}, {": sub-page", ": sub-DB"}};
+       return F_ISSET(n->mn_flags, F_BIGDATA) ? ": overflow page" :
+               tp[F_ISSET(n->mn_flags, F_DUPDATA)][F_ISSET(n->mn_flags, F_SUBDATA)];
+}
+
 /** Display all the keys in the page. */
 void
 mdb_page_list(MDB_page *mp)
 {
+       pgno_t pgno = mdb_dbg_pgno(mp);
+       const char *type, *state = (mp->mp_flags & P_DIRTY) ? ", dirty" : "";
        MDB_node *node;
        unsigned int i, nkeys, nsize, total = 0;
        MDB_val key;
        DKBUF;
 
+       switch (mp->mp_flags & (P_BRANCH|P_LEAF|P_LEAF2|P_META|P_OVERFLOW|P_SUBP)) {
+       case P_BRANCH:              type = "Branch page";               break;
+       case P_LEAF:                type = "Leaf page";                 break;
+       case P_LEAF|P_SUBP:         type = "Sub-page";                  break;
+       case P_LEAF|P_LEAF2:        type = "LEAF2 page";                break;
+       case P_LEAF|P_LEAF2|P_SUBP: type = "LEAF2 sub-page";    break;
+       case P_OVERFLOW:
+               fprintf(stderr, "Overflow page %"Z"u pages %u%s\n",
+                       pgno, mp->mp_pages, state);
+               return;
+       case P_META:
+               fprintf(stderr, "Meta-page %"Z"u txnid %"Z"u\n",
+                       pgno, ((MDB_meta *)METADATA(mp))->mm_txnid);
+               return;
+       default:
+               fprintf(stderr, "Bad page %"Z"u flags 0x%u\n", pgno, mp->mp_flags);
+               return;
+       }
+
        nkeys = NUMKEYS(mp);
-       fprintf(stderr, "Page %"Z"u numkeys %d\n", mdb_dbg_pgno(mp), nkeys);
+       fprintf(stderr, "%s %"Z"u numkeys %d%s\n", type, pgno, nkeys, state);
+
        for (i=0; i<nkeys; i++) {
+               if (IS_LEAF2(mp)) {     /* LEAF2 pages have no mp_ptrs[] or node headers */
+                       key.mv_size = nsize = mp->mp_pad;
+                       key.mv_data = LEAF2KEY(mp, i, nsize);
+                       total += nsize;
+                       fprintf(stderr, "key %d: nsize %d, %s\n", i, nsize, DKEY(&key));
+                       continue;
+               }
                node = NODEPTR(mp, i);
                key.mv_size = node->mn_ksize;
                key.mv_data = node->mn_data;
@@ -1310,11 +1351,13 @@ mdb_page_list(MDB_page *mp)
                                nsize += NODEDSZ(node);
                        total += nsize;
                        nsize += sizeof(indx_t);
-                       fprintf(stderr, "key %d: nsize %d, %s\n", i, nsize, DKEY(&key));
+                       fprintf(stderr, "key %d: nsize %d, %s%s\n",
+                               i, nsize, DKEY(&key), mdb_leafnode_type(node));
                }
                total = EVEN(total);
        }
-       fprintf(stderr, "Total: %d\n", total);
+       fprintf(stderr, "Total: header %d + contents %d + unused %d\n",
+               IS_LEAF2(mp) ? PAGEHDRSZ : mp->mp_lower, total, SIZELEFT(mp));
 }
 
 void
@@ -1340,6 +1383,7 @@ mdb_cursor_chk(MDB_cursor *mc)
 /** Count all the pages in each DB and in the freelist
  *  and make sure it matches the actual number of pages
  *  being used.
+ *  All named DBs must be open for a correct count.
  */
 static void mdb_audit(MDB_txn *txn)
 {
@@ -1353,10 +1397,13 @@ static void mdb_audit(MDB_txn *txn)
        mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
        while ((rc = mdb_cursor_get(&mc, &key, &data, MDB_NEXT)) == 0)
                freecount += *(MDB_ID *)data.mv_data;
+       mdb_tassert(txn, rc == MDB_NOTFOUND);
 
        count = 0;
        for (i = 0; i<txn->mt_numdbs; i++) {
                MDB_xcursor mx;
+               if (!(txn->mt_dbflags[i] & DB_VALID))
+                       continue;
                mdb_cursor_init(&mc, txn, i, &mx);
                if (txn->mt_dbs[i].md_root == P_INVALID)
                        continue;
@@ -1364,8 +1411,8 @@ static void mdb_audit(MDB_txn *txn)
                        txn->mt_dbs[i].md_leaf_pages +
                        txn->mt_dbs[i].md_overflow_pages;
                if (txn->mt_dbs[i].md_flags & MDB_DUPSORT) {
-                       mdb_page_search(&mc, NULL, MDB_PS_FIRST);
-                       do {
+                       rc = mdb_page_search(&mc, NULL, MDB_PS_FIRST);
+                       for (; rc == MDB_SUCCESS; rc = mdb_cursor_sibling(&mc, 1)) {
                                unsigned j;
                                MDB_page *mp;
                                mp = mc.mc_pg[mc.mc_top];
@@ -1379,7 +1426,7 @@ static void mdb_audit(MDB_txn *txn)
                                        }
                                }
                        }
-                       while (mdb_cursor_sibling(&mc, 1) == 0);
+                       mdb_tassert(txn, rc == MDB_NOTFOUND);
                }
        }
        if (freecount + count + 2 /* metapages */ != txn->mt_next_pgno) {
@@ -2059,6 +2106,7 @@ done:
                        if (m2->mc_pg[mc->mc_top] == mp) {
                                m2->mc_pg[mc->mc_top] = np;
                                if ((mc->mc_db->md_flags & MDB_DUPSORT) &&
+                                       IS_LEAF(np) &&
                                        m2->mc_ki[mc->mc_top] == mc->mc_ki[mc->mc_top])
                                {
                                        MDB_node *leaf = NODEPTR(np, mc->mc_ki[mc->mc_top]);
@@ -2268,11 +2316,11 @@ mdb_txn_renew0(MDB_txn *txn)
                                MDB_PID_T pid = env->me_pid;
                                pthread_t tid = pthread_self();
 
-                               if (!(env->me_flags & MDB_LIVE_READER)) {
+                               if (!env->me_live_reader) {
                                        rc = mdb_reader_pid(env, Pidset, pid);
                                        if (rc)
                                                return rc;
-                                       env->me_flags |= MDB_LIVE_READER;
+                                       env->me_live_reader = 1;
                                }
 
                                LOCK_MUTEX_R(env);
@@ -2728,10 +2776,11 @@ mdb_freelist_save(MDB_txn *txn)
                        MDB_ID save;
 
                        mdb_tassert(txn, len >= 0 && id <= env->me_pglast);
-                       key.mv_data = &id;
                        if (len > mop_len) {
                                len = mop_len;
                                data.mv_size = (len + 1) * sizeof(MDB_ID);
+                               /* Drop MDB_CURRENT when changing the data size */
+                               key.mv_data = &id;
                                flags = 0;
                        }
                        data.mv_data = mop -= len;
@@ -5041,12 +5090,9 @@ mdb_get(MDB_txn *txn, MDB_dbi dbi,
        int exact = 0;
        DKBUF;
 
-       if (key == NULL || data == NULL)
-               return EINVAL;
-
        DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key)));
 
-       if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        if (txn->mt_flags & MDB_TXN_ERROR)
@@ -5761,7 +5807,7 @@ mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
        unsigned int nflags;
        DKBUF;
 
-       if (mc == NULL || key == NULL)
+       if (mc == NULL)
                return EINVAL;
 
        env = mc->mc_txn->mt_env;
@@ -5782,8 +5828,16 @@ mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
        if (mc->mc_txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR))
                return (mc->mc_txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
 
-       if (flags != MDB_CURRENT && key->mv_size-1 >= ENV_MAXKEY(env))
-               return MDB_BAD_VALSIZE;
+       if (flags != MDB_CURRENT) {
+               if (key == NULL)
+                       return EINVAL;
+               if (key->mv_size-1 >= ENV_MAXKEY(env))
+                       return MDB_BAD_VALSIZE;
+       } else {
+               /* Ignore key except in sub-cursor, where key holds the data */
+               if (!(mc->mc_flags & C_SUB))
+                       key = NULL;
+       }
 
 #if SIZE_MAX > MAXDATASIZE
        if (data->mv_size > ((mc->mc_db->md_flags & MDB_DUPSORT) ? ENV_MAXKEY(env) : MAXDATASIZE))
@@ -6107,7 +6161,7 @@ current:
                         */
                        if (F_ISSET(flags, MDB_RESERVE))
                                data->mv_data = olddata.mv_data;
-                       else if (data->mv_size)
+                       else if (!(mc->mc_flags & C_SUB))
                                memcpy(olddata.mv_data, data->mv_data, data->mv_size);
                        else
                                memcpy(NODEKEY(leaf), key->mv_data, key->mv_size);
@@ -6175,8 +6229,10 @@ put_sub:
                        /* converted, write the original data first */
                        if (dkey.mv_size) {
                                rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags);
-                               if (rc)
-                                       return rc;
+                               if (rc) {
+                                       mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+                                       return rc == MDB_KEYEXIST ? MDB_CORRUPTED : rc;
+                               }
                                {
                                        /* Adjust other cursors pointing to mp */
                                        MDB_cursor *m2;
@@ -6253,14 +6309,18 @@ mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
                return rc;
 
        mp = mc->mc_pg[mc->mc_top];
+       if (IS_LEAF2(mp))
+               goto del_key;
        leaf = NODEPTR(mp, mc->mc_ki[mc->mc_top]);
 
-       if (!IS_LEAF2(mp) && F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+       if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
                if (!(flags & MDB_NODUPDATA)) {
                        if (!F_ISSET(leaf->mn_flags, F_SUBDATA)) {
                                mc->mc_xcursor->mx_cursor.mc_pg[0] = NODEDATA(leaf);
                        }
                        rc = mdb_cursor_del(&mc->mc_xcursor->mx_cursor, MDB_NOSPILL);
+                       if (rc)
+                               return rc;
                        /* If sub-DB still has entries, we're done */
                        if (mc->mc_xcursor->mx_db.md_entries) {
                                if (leaf->mn_flags & F_SUBDATA) {
@@ -6291,14 +6351,29 @@ mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
                if (leaf->mn_flags & F_SUBDATA) {
                        /* add all the child DB's pages to the free list */
                        rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
-                       if (rc == MDB_SUCCESS) {
-                               mc->mc_db->md_entries -=
-                                       mc->mc_xcursor->mx_db.md_entries;
-                       }
+                       if (rc)
+                               goto fail;
+                       mc->mc_db->md_entries -= mc->mc_xcursor->mx_db.md_entries;
                }
        }
 
-       return mdb_cursor_del0(mc, leaf);
+       /* add overflow pages to free list */
+       if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
+               MDB_page *omp;
+               pgno_t pg;
+
+               memcpy(&pg, NODEDATA(leaf), sizeof(pg));
+               if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) ||
+                       (rc = mdb_ovpage_free(mc, omp)))
+                       goto fail;
+       }
+
+del_key:
+       return mdb_cursor_del0(mc);
+
+fail:
+       mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
+       return rc;
 }
 
 /** Allocate and initialize new pages for a database.
@@ -6525,8 +6600,7 @@ full:
 }
 
 /** Delete the specified node from a page.
- * @param[in] mp The page to operate on.
- * @param[in] indx The index of the node to delete.
+ * @param[in] mc Cursor pointing to the node to delete.
  * @param[in] ksize The size of a node. Only used if the page is
  * part of a #MDB_DUPFIXED database.
  */
@@ -6749,7 +6823,7 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
        MDB_cursor      *mc;
        size_t size = sizeof(MDB_cursor);
 
-       if (txn == NULL || ret == NULL || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if (!ret || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        if (txn->mt_flags & MDB_TXN_ERROR)
@@ -6781,12 +6855,15 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret)
 int
 mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
 {
-       if (txn == NULL || mc == NULL || mc->mc_dbi >= txn->mt_numdbs)
+       if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi))
                return EINVAL;
 
        if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors)
                return EINVAL;
 
+       if (txn->mt_flags & MDB_TXN_ERROR)
+               return MDB_BAD_TXN;
+
        mdb_cursor_init(mc, txn, mc->mc_dbi, mc->mc_xcursor);
        return MDB_SUCCESS;
 }
@@ -6803,6 +6880,9 @@ mdb_cursor_count(MDB_cursor *mc, size_t *countp)
        if (mc->mc_xcursor == NULL)
                return MDB_INCOMPATIBLE;
 
+       if (mc->mc_txn->mt_flags & MDB_TXN_ERROR)
+               return MDB_BAD_TXN;
+
        leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
        if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
                *countp = 1;
@@ -6955,7 +7035,9 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst)
                        unsigned int snum = csrc->mc_snum;
                        MDB_node *s2;
                        /* must find the lowest key below src */
-                       mdb_page_search_lowest(csrc);
+                       rc = mdb_page_search_lowest(csrc);
+                       if (rc)
+                               return rc;
                        if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
                                key.mv_size = csrc->mc_db->md_pad;
                                key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size);
@@ -6978,7 +7060,9 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst)
                MDB_node *s2;
                MDB_val bkey;
                /* must find the lowest key below dst */
-               mdb_page_search_lowest(cdst);
+               rc = mdb_page_search_lowest(cdst);
+               if (rc)
+                       return rc;
                if (IS_LEAF2(cdst->mc_pg[cdst->mc_top])) {
                        bkey.mv_size = cdst->mc_db->md_pad;
                        bkey.mv_data = LEAF2KEY(cdst->mc_pg[cdst->mc_top], 0, bkey.mv_size);
@@ -7100,6 +7184,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst)
  *     the \b csrc page will be freed.
  * @param[in] csrc Cursor pointing to the source page.
  * @param[in] cdst Cursor pointing to the destination page.
+ * @return 0 on success, non-zero on failure.
  */
 static int
 mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst)
@@ -7139,7 +7224,9 @@ mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst)
                                unsigned int snum = csrc->mc_snum;
                                MDB_node *s2;
                                /* must find the lowest key below src */
-                               mdb_page_search_lowest(csrc);
+                               rc = mdb_page_search_lowest(csrc);
+                               if (rc)
+                                       return rc;
                                if (IS_LEAF2(csrc->mc_pg[csrc->mc_top])) {
                                        key.mv_size = csrc->mc_db->md_pad;
                                        key.mv_data = LEAF2KEY(csrc->mc_pg[csrc->mc_top], 0, key.mv_size);
@@ -7402,32 +7489,19 @@ mdb_rebalance(MDB_cursor *mc)
 
 /** Complete a delete operation started by #mdb_cursor_del(). */
 static int
-mdb_cursor_del0(MDB_cursor *mc, MDB_node *leaf)
+mdb_cursor_del0(MDB_cursor *mc)
 {
        int rc;
        MDB_page *mp;
        indx_t ki;
        unsigned int nkeys;
 
-       mp = mc->mc_pg[mc->mc_top];
        ki = mc->mc_ki[mc->mc_top];
-
-       /* add overflow pages to free list */
-       if (!IS_LEAF2(mp) && F_ISSET(leaf->mn_flags, F_BIGDATA)) {
-               MDB_page *omp;
-               pgno_t pg;
-
-               memcpy(&pg, NODEDATA(leaf), sizeof(pg));
-               if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) ||
-                       (rc = mdb_ovpage_free(mc, omp)))
-                       return rc;
-       }
        mdb_node_del(mc, mc->mc_db->md_pad);
        mc->mc_db->md_entries--;
        rc = mdb_rebalance(mc);
-       if (rc != MDB_SUCCESS)
-               mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
-       else {
+
+       if (rc == MDB_SUCCESS) {
                MDB_cursor *m2, *m3;
                MDB_dbi dbi = mc->mc_dbi;
 
@@ -7435,11 +7509,14 @@ mdb_cursor_del0(MDB_cursor *mc, MDB_node *leaf)
                nkeys = NUMKEYS(mp);
 
                /* if mc points past last node in page, find next sibling */
-               if (mc->mc_ki[mc->mc_top] >= nkeys)
-                       mdb_cursor_sibling(mc, 1);
+               if (mc->mc_ki[mc->mc_top] >= nkeys) {
+                       rc = mdb_cursor_sibling(mc, 1);
+                       if (rc == MDB_NOTFOUND)
+                               rc = MDB_SUCCESS;
+               }
 
                /* Adjust other cursors pointing to mp */
-               for (m2 = mc->mc_txn->mt_cursors[dbi]; m2; m2=m2->mc_next) {
+               for (m2 = mc->mc_txn->mt_cursors[dbi]; !rc && m2; m2=m2->mc_next) {
                        m3 = (mc->mc_flags & C_SUB) ? &m2->mc_xcursor->mx_cursor : m2;
                        if (! (m2->mc_flags & m3->mc_flags & C_INITIALIZED))
                                continue;
@@ -7451,45 +7528,54 @@ mdb_cursor_del0(MDB_cursor *mc, MDB_node *leaf)
                                        if (m3->mc_ki[mc->mc_top] > ki)
                                                m3->mc_ki[mc->mc_top]--;
                                }
-                               if (m3->mc_ki[mc->mc_top] >= nkeys)
-                                       mdb_cursor_sibling(m3, 1);
+                               if (m3->mc_ki[mc->mc_top] >= nkeys) {
+                                       rc = mdb_cursor_sibling(m3, 1);
+                                       if (rc == MDB_NOTFOUND)
+                                               rc = MDB_SUCCESS;
+                               }
                        }
                }
                mc->mc_flags |= C_DEL;
        }
 
+       if (rc)
+               mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
        return rc;
 }
 
 int
 mdb_del(MDB_txn *txn, MDB_dbi dbi,
     MDB_val *key, MDB_val *data)
+{
+       if (!key || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
+               return EINVAL;
+
+       if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR))
+               return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
+
+       if (!F_ISSET(txn->mt_dbs[dbi].md_flags, MDB_DUPSORT)) {
+               /* must ignore any data */
+               data = NULL;
+       }
+
+       return mdb_del0(txn, dbi, key, data, 0);
+}
+
+static int
+mdb_del0(MDB_txn *txn, MDB_dbi dbi,
+       MDB_val *key, MDB_val *data, unsigned flags)
 {
        MDB_cursor mc;
        MDB_xcursor mx;
        MDB_cursor_op op;
        MDB_val rdata, *xdata;
-       int              rc, exact;
+       int              rc, exact = 0;
        DKBUF;
 
-       if (key == NULL)
-               return EINVAL;
-
        DPRINTF(("====> delete db %u key [%s]", dbi, DKEY(key)));
 
-       if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
-               return EINVAL;
-
-       if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR))
-               return (txn->mt_flags & MDB_TXN_RDONLY) ? EACCES : MDB_BAD_TXN;
-
        mdb_cursor_init(&mc, txn, dbi, &mx);
 
-       exact = 0;
-       if (!F_ISSET(txn->mt_dbs[dbi].md_flags, MDB_DUPSORT)) {
-               /* must ignore any data */
-               data = NULL;
-       }
        if (data) {
                op = MDB_GET_BOTH;
                rdata = *data;
@@ -7497,6 +7583,7 @@ mdb_del(MDB_txn *txn, MDB_dbi dbi,
        } else {
                op = MDB_SET;
                xdata = NULL;
+               flags |= MDB_NODUPDATA;
        }
        rc = mdb_cursor_set(&mc, key, xdata, op, &exact);
        if (rc == 0) {
@@ -7511,7 +7598,7 @@ mdb_del(MDB_txn *txn, MDB_dbi dbi,
                mc.mc_flags |= C_UNTRACK;
                mc.mc_next = txn->mt_cursors[dbi];
                txn->mt_cursors[dbi] = &mc;
-               rc = mdb_cursor_del(&mc, data ? 0 : MDB_NODUPDATA);
+               rc = mdb_cursor_del(&mc, flags);
                txn->mt_cursors[dbi] = mc.mc_next;
        }
        return rc;
@@ -7560,7 +7647,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
 
        if (mc->mc_snum < 2) {
                if ((rc = mdb_page_new(mc, P_BRANCH, 1, &pp)))
-                       return rc;
+                       goto done;
                /* shift current top to make room for new parent */
                mc->mc_pg[1] = mc->mc_pg[0];
                mc->mc_ki[1] = mc->mc_ki[0];
@@ -7578,7 +7665,7 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
                        mc->mc_ki[0] = mc->mc_ki[1];
                        mc->mc_db->md_root = mp->mp_pgno;
                        mc->mc_db->md_depth--;
-                       return rc;
+                       goto done;
                }
                mc->mc_snum = 2;
                mc->mc_top = 1;
@@ -7607,7 +7694,6 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
                        int x;
                        unsigned int lsize, rsize, ksize;
                        /* Move half of the keys to the right sibling */
-                       copy = NULL;
                        x = mc->mc_ki[mc->mc_top] - split_indx;
                        ksize = mc->mc_db->md_pad;
                        split = LEAF2KEY(mp, split_indx, ksize);
@@ -7654,8 +7740,10 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
 
                        /* grab a page to hold a temporary copy */
                        copy = mdb_page_malloc(mc->mc_txn, 1);
-                       if (copy == NULL)
-                               return ENOMEM;
+                       if (copy == NULL) {
+                               rc = ENOMEM;
+                               goto done;
+                       }
                        copy->mp_pgno  = mp->mp_pgno;
                        copy->mp_flags = mp->mp_flags;
                        copy->mp_lower = PAGEHDRSZ;
@@ -7735,6 +7823,8 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
                mn.mc_top--;
                did_split = 1;
                rc = mdb_page_split(&mn, &sepkey, NULL, rp->mp_pgno, 0);
+               if (rc)
+                       goto done;
 
                /* root split? */
                if (mn.mc_snum == mc->mc_snum) {
@@ -7756,7 +7846,13 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
                                mc->mc_ki[i] = mn.mc_ki[i];
                        }
                        mc->mc_pg[ptop] = mn.mc_pg[ptop];
-                       mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
+                       if (mn.mc_ki[ptop]) {
+                               mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
+                       } else {
+                               /* find right page's left sibling */
+                               mc->mc_ki[ptop] = mn.mc_ki[ptop];
+                               mdb_cursor_sibling(mc, 0);
+                       }
                }
        } else {
                mn.mc_top--;
@@ -7765,14 +7861,14 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
        }
        mc->mc_flags ^= C_SPLITTING;
        if (rc != MDB_SUCCESS) {
-               return rc;
+               goto done;
        }
        if (nflags & MDB_APPEND) {
                mc->mc_pg[mc->mc_top] = rp;
                mc->mc_ki[mc->mc_top] = 0;
                rc = mdb_node_add(mc, 0, newkey, newdata, newpgno, nflags);
                if (rc)
-                       return rc;
+                       goto done;
                for (i=0; i<mc->mc_top; i++)
                        mc->mc_ki[i] = mn.mc_ki[i];
        } else if (!IS_LEAF2(mp)) {
@@ -7810,11 +7906,8 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
                        }
 
                        rc = mdb_node_add(mc, j, &rkey, rdata, pgno, flags);
-                       if (rc) {
-                               /* return tmp page to freelist */
-                               mdb_page_free(env, copy);
-                               return rc;
-                       }
+                       if (rc)
+                               goto done;
                        if (i == nkeys) {
                                i = 0;
                                j = 0;
@@ -7848,16 +7941,12 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
                         */
                        if (mn.mc_pg[ptop] != mc->mc_pg[ptop] &&
                                mc->mc_ki[ptop] >= NUMKEYS(mc->mc_pg[ptop])) {
-                               for (i=0; i<ptop; i++) {
+                               for (i=0; i<=ptop; i++) {
                                        mc->mc_pg[i] = mn.mc_pg[i];
                                        mc->mc_ki[i] = mn.mc_ki[i];
                                }
-                               mc->mc_pg[ptop] = mn.mc_pg[ptop];
-                               mc->mc_ki[ptop] = mn.mc_ki[ptop] - 1;
                        }
                }
-               /* return tmp page to freelist */
-               mdb_page_free(env, copy);
        }
 
        {
@@ -7908,6 +7997,12 @@ mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, pgno_t newpgno
                }
        }
        DPRINTF(("mp left: %d, rp left: %d", SIZELEFT(mp), SIZELEFT(rp)));
+
+done:
+       if (copy)                                       /* tmp page */
+               mdb_page_free(env, copy);
+       if (rc)
+               mc->mc_txn->mt_flags |= MDB_TXN_ERROR;
        return rc;
 }
 
@@ -7918,10 +8013,7 @@ mdb_put(MDB_txn *txn, MDB_dbi dbi,
        MDB_cursor mc;
        MDB_xcursor mx;
 
-       if (key == NULL || data == NULL)
-               return EINVAL;
-
-       if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        if ((flags & (MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)) != flags)
@@ -8180,9 +8272,12 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db
 
 int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg)
 {
-       if (txn == NULL || arg == NULL || dbi >= txn->mt_numdbs)
+       if (!arg || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
+       if (txn->mt_flags & MDB_TXN_ERROR)
+               return MDB_BAD_TXN;
+
        if (txn->mt_dbflags[dbi] & DB_STALE) {
                MDB_cursor mc;
                MDB_xcursor mx;
@@ -8207,7 +8302,7 @@ void mdb_dbi_close(MDB_env *env, MDB_dbi dbi)
 int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags)
 {
        /* We could return the flags for the FREE_DBI too but what's the point? */
-       if (txn == NULL || dbi < MAIN_DBI || dbi >= txn->mt_numdbs)
+       if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
        *flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS;
        return MDB_SUCCESS;
@@ -8247,22 +8342,22 @@ mdb_drop0(MDB_cursor *mc, int subs)
                                                memcpy(&pg, NODEDATA(ni), sizeof(pg));
                                                rc = mdb_page_get(txn, pg, &omp, NULL);
                                                if (rc != 0)
-                                                       return rc;
+                                                       goto done;
                                                mdb_cassert(mc, IS_OVERFLOW(omp));
                                                rc = mdb_midl_append_range(&txn->mt_free_pgs,
                                                        pg, omp->mp_pages);
                                                if (rc)
-                                                       return rc;
+                                                       goto done;
                                        } else if (subs && (ni->mn_flags & F_SUBDATA)) {
                                                mdb_xcursor_init1(mc, ni);
                                                rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0);
                                                if (rc)
-                                                       return rc;
+                                                       goto done;
                                        }
                                }
                        } else {
                                if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0)
-                                       return rc;
+                                       goto done;
                                for (i=0; i<n; i++) {
                                        pgno_t pg;
                                        ni = NODEPTR(mp, i);
@@ -8276,6 +8371,8 @@ mdb_drop0(MDB_cursor *mc, int subs)
                        mc->mc_ki[mc->mc_top] = i;
                        rc = mdb_cursor_sibling(mc, 1);
                        if (rc) {
+                               if (rc != MDB_NOTFOUND)
+                                       goto done;
                                /* no more siblings, go back to beginning
                                 * of previous level.
                                 */
@@ -8289,6 +8386,9 @@ mdb_drop0(MDB_cursor *mc, int subs)
                }
                /* free it */
                rc = mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root);
+done:
+               if (rc)
+                       txn->mt_flags |= MDB_TXN_ERROR;
        } else if (rc == MDB_NOTFOUND) {
                rc = MDB_SUCCESS;
        }
@@ -8300,7 +8400,7 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
        MDB_cursor *mc, *m2;
        int rc;
 
-       if (!txn || !dbi || dbi >= txn->mt_numdbs || (unsigned)del > 1 || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if ((unsigned)del > 1 || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))
@@ -8319,10 +8419,12 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
 
        /* Can't delete the main DB */
        if (del && dbi > MAIN_DBI) {
-               rc = mdb_del(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL);
+               rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, 0);
                if (!rc) {
                        txn->mt_dbflags[dbi] = DB_STALE;
                        mdb_dbi_close(txn->mt_env, dbi);
+               } else {
+                       txn->mt_flags |= MDB_TXN_ERROR;
                }
        } else {
                /* reset the DB record, mark it dirty */
@@ -8343,7 +8445,7 @@ leave:
 
 int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
 {
-       if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        txn->mt_dbxs[dbi].md_cmp = cmp;
@@ -8352,7 +8454,7 @@ int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
 
 int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
 {
-       if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        txn->mt_dbxs[dbi].md_dcmp = cmp;
@@ -8361,7 +8463,7 @@ int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp)
 
 int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
 {
-       if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        txn->mt_dbxs[dbi].md_rel = rel;
@@ -8370,7 +8472,7 @@ int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel)
 
 int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx)
 {
-       if (txn == NULL || !dbi || dbi >= txn->mt_numdbs || !(txn->mt_dbflags[dbi] & DB_VALID))
+       if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi))
                return EINVAL;
 
        txn->mt_dbxs[dbi].md_relctx = ctx;
index f9a96b2ab813b47506b71d81a6adf07a10920b41..01579950b1b0a3b61b45fbb785d06b420e469ab2 100644 (file)
 #include <time.h>
 #include "lmdb.h"
 
+#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
+#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
+#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
+       "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
+
 int main(int argc,char * argv[])
 {
        int i = 0, j = 0, rc;
@@ -26,6 +31,7 @@ int main(int argc,char * argv[])
        MDB_txn *txn;
        MDB_stat mst;
        MDB_cursor *cursor, *cur2;
+       MDB_cursor_op op;
        int count;
        int *values;
        char sval[32] = "";
@@ -39,11 +45,11 @@ int main(int argc,char * argv[])
                        values[i] = random()%1024;
            }
     
-               rc = mdb_env_create(&env);
-               rc = mdb_env_set_mapsize(env, 10485760);
-               rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664);
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
-               rc = mdb_open(txn, NULL, 0, &dbi);
+               E(mdb_env_create(&env));
+               E(mdb_env_set_mapsize(env, 10485760));
+               E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));
+               E(mdb_txn_begin(env, NULL, 0, &txn));
+               E(mdb_open(txn, NULL, 0, &dbi));
    
                key.mv_size = sizeof(int);
                key.mv_data = sval;
@@ -53,24 +59,24 @@ int main(int argc,char * argv[])
                printf("Adding %d values\n", count);
            for (i=0;i<count;i++) {     
                        sprintf(sval, "%03x %d foo bar", values[i], values[i]);
-                       rc = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
-                       if (rc) {
+                       if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {
                                j++;
                                data.mv_size = sizeof(sval);
                                data.mv_data = sval;
                        }
            }
                if (j) printf("%d duplicates skipped\n", j);
-               rc = mdb_txn_commit(txn);
-               rc = mdb_env_stat(env, &mst);
+               E(mdb_txn_commit(txn));
+               E(mdb_env_stat(env, &mst));
 
-               rc = mdb_txn_begin(env, NULL, 1, &txn);
-               rc = mdb_cursor_open(txn, dbi, &cursor);
+               E(mdb_txn_begin(env, NULL, 1, &txn));
+               E(mdb_cursor_open(txn, dbi, &cursor));
                while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                        printf("key: %p %.*s, data: %p %.*s\n",
                                key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                                data.mv_data, (int) data.mv_size, (char *) data.mv_data);
                }
+               CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
                mdb_cursor_close(cursor);
                mdb_txn_abort(txn);
 
@@ -79,30 +85,30 @@ int main(int argc,char * argv[])
            for (i= count - 1; i > -1; i-= (random()%5)) {      
                        j++;
                        txn=NULL;
-                       rc = mdb_txn_begin(env, NULL, 0, &txn);
+                       E(mdb_txn_begin(env, NULL, 0, &txn));
                        sprintf(sval, "%03x ", values[i]);
-                       rc = mdb_del(txn, dbi, &key, NULL);
-                       if (rc) {
+                       if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {
                                j--;
                                mdb_txn_abort(txn);
                        } else {
-                               rc = mdb_txn_commit(txn);
+                               E(mdb_txn_commit(txn));
                        }
            }
            free(values);
                printf("Deleted %d values\n", j);
 
-               rc = mdb_env_stat(env, &mst);
-               rc = mdb_txn_begin(env, NULL, 1, &txn);
-               rc = mdb_cursor_open(txn, dbi, &cursor);
+               E(mdb_env_stat(env, &mst));
+               E(mdb_txn_begin(env, NULL, 1, &txn));
+               E(mdb_cursor_open(txn, dbi, &cursor));
                printf("Cursor next\n");
                while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                        printf("key: %.*s, data: %.*s\n",
                                (int) key.mv_size,  (char *) key.mv_data,
                                (int) data.mv_size, (char *) data.mv_data);
                }
+               CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
                printf("Cursor last\n");
-               rc = mdb_cursor_get(cursor, &key, &data, MDB_LAST);
+               E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
@@ -112,12 +118,13 @@ int main(int argc,char * argv[])
                                (int) key.mv_size,  (char *) key.mv_data,
                                (int) data.mv_size, (char *) data.mv_data);
                }
+               CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
                printf("Cursor last/prev\n");
-               rc = mdb_cursor_get(cursor, &key, &data, MDB_LAST);
+               E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));
                        printf("key: %.*s, data: %.*s\n",
                                (int) key.mv_size,  (char *) key.mv_data,
                                (int) data.mv_size, (char *) data.mv_data);
-               rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV);
+               E(mdb_cursor_get(cursor, &key, &data, MDB_PREV));
                        printf("key: %.*s, data: %.*s\n",
                                (int) key.mv_size,  (char *) key.mv_data,
                                (int) data.mv_size, (char *) data.mv_data);
@@ -125,43 +132,34 @@ int main(int argc,char * argv[])
                mdb_txn_abort(txn);
 
                printf("Deleting with cursor\n");
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
-               rc = mdb_cursor_open(txn, dbi, &cur2);
+               E(mdb_txn_begin(env, NULL, 0, &txn));
+               E(mdb_cursor_open(txn, dbi, &cur2));
                for (i=0; i<50; i++) {
-                       rc = mdb_cursor_get(cur2, &key, &data, MDB_NEXT);
-                       if (rc)
+                       if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT)))
                                break;
                        printf("key: %p %.*s, data: %p %.*s\n",
                                key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                                data.mv_data, (int) data.mv_size, (char *) data.mv_data);
-                       rc = mdb_del(txn, dbi, &key, NULL);
+                       E(mdb_del(txn, dbi, &key, NULL));
                }
 
                printf("Restarting cursor in txn\n");
-               rc = mdb_cursor_get(cur2, &key, &data, MDB_FIRST);
-               printf("key: %p %.*s, data: %p %.*s\n",
-                       key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
-                       data.mv_data, (int) data.mv_size, (char *) data.mv_data);
-               for (i=0; i<32; i++) {
-                       rc = mdb_cursor_get(cur2, &key, &data, MDB_NEXT);
-                       if (rc) break;
+               for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
+                       if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op)))
+                               break;
                        printf("key: %p %.*s, data: %p %.*s\n",
                                key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                                data.mv_data, (int) data.mv_size, (char *) data.mv_data);
                }
                mdb_cursor_close(cur2);
-               rc = mdb_txn_commit(txn);
+               E(mdb_txn_commit(txn));
 
                printf("Restarting cursor outside txn\n");
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
-               rc = mdb_cursor_open(txn, dbi, &cursor);
-               rc = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
-               printf("key: %p %.*s, data: %p %.*s\n",
-                       key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
-                       data.mv_data, (int) data.mv_size, (char *) data.mv_data);
-               for (i=0; i<32; i++) {
-                       rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT);
-                       if (rc) break;
+               E(mdb_txn_begin(env, NULL, 0, &txn));
+               E(mdb_cursor_open(txn, dbi, &cursor));
+               for (op=MDB_FIRST, i=0; i<=32; op=MDB_NEXT, i++) {
+                       if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op)))
+                               break;
                        printf("key: %p %.*s, data: %p %.*s\n",
                                key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                                data.mv_data, (int) data.mv_size, (char *) data.mv_data);
index bfa29f9f74d8112ea03fe834063f2411946e3616..ebda8521e4eb3eb56ca255a5bc068e74e17fdb8f 100644 (file)
 #include <time.h>
 #include "lmdb.h"
 
+#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
+#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
+#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
+       "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
+
 int main(int argc,char * argv[])
 {
        int i = 0, j = 0, rc;
@@ -42,12 +47,12 @@ int main(int argc,char * argv[])
                values[i] = random()%1024;
        }
 
-       rc = mdb_env_create(&env);
-       rc = mdb_env_set_mapsize(env, 10485760);
-       rc = mdb_env_set_maxdbs(env, 4);
-       rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_open(txn, "id1", MDB_CREATE, &dbi);
+       E(mdb_env_create(&env));
+       E(mdb_env_set_mapsize(env, 10485760));
+       E(mdb_env_set_maxdbs(env, 4));
+       E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       E(mdb_open(txn, "id1", MDB_CREATE, &dbi));
    
        key.mv_size = sizeof(int);
        key.mv_data = sval;
@@ -57,20 +62,21 @@ int main(int argc,char * argv[])
        printf("Adding %d values\n", count);
        for (i=0;i<count;i++) { 
                sprintf(sval, "%03x %d foo bar", values[i], values[i]);
-               rc = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
-               if (rc) j++;
+               if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE)))
+                       j++;
        }
        if (j) printf("%d duplicates skipped\n", j);
-       rc = mdb_txn_commit(txn);
-       rc = mdb_env_stat(env, &mst);
+       E(mdb_txn_commit(txn));
+       E(mdb_env_stat(env, &mst));
 
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %p %.*s, data: %p %.*s\n",
                        key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                        data.mv_data, (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_txn_abort(txn);
 
@@ -79,34 +85,35 @@ int main(int argc,char * argv[])
        for (i= count - 1; i > -1; i-= (random()%5)) {  
                j++;
                txn=NULL;
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
+               E(mdb_txn_begin(env, NULL, 0, &txn));
                sprintf(sval, "%03x ", values[i]);
-               rc = mdb_del(txn, dbi, &key, NULL);
-               if (rc) {
+               if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {
                        j--;
                        mdb_txn_abort(txn);
                } else {
-                       rc = mdb_txn_commit(txn);
+                       E(mdb_txn_commit(txn));
                }
        }
        free(values);
        printf("Deleted %d values\n", j);
 
-       rc = mdb_env_stat(env, &mst);
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_env_stat(env, &mst));
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        printf("Cursor next\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        printf("Cursor prev\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_close(env, dbi);
 
index c189eaa952f429a658b1742d2aed111122d4f2c1..95b174968844e7e631b0af4137706806d9884d0c 100644 (file)
 #include <time.h>
 #include "lmdb.h"
 
+#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
+#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
+#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
+       "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
+
 int main(int argc,char * argv[])
 {
        int i = 0, j = 0, rc;
@@ -45,12 +50,12 @@ int main(int argc,char * argv[])
                values[i] = random()%1024;
        }
 
-       rc = mdb_env_create(&env);
-       rc = mdb_env_set_mapsize(env, 10485760);
-       rc = mdb_env_set_maxdbs(env, 4);
-       rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi);
+       E(mdb_env_create(&env));
+       E(mdb_env_set_mapsize(env, 10485760));
+       E(mdb_env_set_maxdbs(env, 4));
+       E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
 
        key.mv_size = sizeof(int);
        key.mv_data = kval;
@@ -62,20 +67,21 @@ int main(int argc,char * argv[])
                if (!(i & 0x0f))
                        sprintf(kval, "%03x", values[i]);
                sprintf(sval, "%03x %d foo bar", values[i], values[i]);
-               rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
-               if (rc) j++;
+               if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA)))
+                       j++;
        }
        if (j) printf("%d duplicates skipped\n", j);
-       rc = mdb_txn_commit(txn);
-       rc = mdb_env_stat(env, &mst);
+       E(mdb_txn_commit(txn));
+       E(mdb_env_stat(env, &mst));
 
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %p %.*s, data: %p %.*s\n",
                        key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                        data.mv_data, (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_txn_abort(txn);
 
@@ -84,39 +90,40 @@ int main(int argc,char * argv[])
        for (i= count - 1; i > -1; i-= (random()%5)) {
                j++;
                txn=NULL;
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
+               E(mdb_txn_begin(env, NULL, 0, &txn));
                sprintf(kval, "%03x", values[i & ~0x0f]);
                sprintf(sval, "%03x %d foo bar", values[i], values[i]);
                key.mv_size = sizeof(int);
                key.mv_data = kval;
                data.mv_size = sizeof(sval);
                data.mv_data = sval;
-               rc = mdb_del(txn, dbi, &key, &data);
-               if (rc) {
+               if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
                        j--;
                        mdb_txn_abort(txn);
                } else {
-                       rc = mdb_txn_commit(txn);
+                       E(mdb_txn_commit(txn));
                }
        }
        free(values);
        printf("Deleted %d values\n", j);
 
-       rc = mdb_env_stat(env, &mst);
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_env_stat(env, &mst));
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        printf("Cursor next\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        printf("Cursor prev\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_close(env, dbi);
 
index e0ba7e20b6b6eb8dd4ca9f6fe7adaf7225bc37ca..37f95baa24dd5923889aa30f77e96b8df2167029 100644 (file)
 #include <time.h>
 #include "lmdb.h"
 
+#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
+#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
+#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
+       "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
+
 int main(int argc,char * argv[])
 {
        int i = 0, j = 0, rc;
@@ -43,12 +48,12 @@ int main(int argc,char * argv[])
                values[i] = i*5;
        }
 
-       rc = mdb_env_create(&env);
-       rc = mdb_env_set_mapsize(env, 10485760);
-       rc = mdb_env_set_maxdbs(env, 4);
-       rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi);
+       E(mdb_env_create(&env));
+       E(mdb_env_set_mapsize(env, 10485760));
+       E(mdb_env_set_maxdbs(env, 4));
+       E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       E(mdb_open(txn, "id4", MDB_CREATE|MDB_DUPSORT|MDB_DUPFIXED, &dbi));
 
        key.mv_size = sizeof(int);
        key.mv_data = kval;
@@ -59,22 +64,23 @@ int main(int argc,char * argv[])
        strcpy(kval, "001");
        for (i=0;i<count;i++) {
                sprintf(sval, "%07x", values[i]);
-               rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
-               if (rc) j++;
+               if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA)))
+                       j++;
        }
        if (j) printf("%d duplicates skipped\n", j);
-       rc = mdb_txn_commit(txn);
-       rc = mdb_env_stat(env, &mst);
+       E(mdb_txn_commit(txn));
+       E(mdb_env_stat(env, &mst));
 
        /* there should be one full page of dups now.
         */
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %p %.*s, data: %p %.*s\n",
                        key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                        data.mv_data, (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_txn_abort(txn);
 
@@ -90,28 +96,29 @@ int main(int argc,char * argv[])
        data.mv_data = sval;
 
        sprintf(sval, "%07x", values[3]+1);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       (void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
        mdb_txn_abort(txn);
 
        sprintf(sval, "%07x", values[255]+1);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       (void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
        mdb_txn_abort(txn);
 
        sprintf(sval, "%07x", values[500]+1);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA);
-       rc = mdb_txn_commit(txn);
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       (void)RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NODUPDATA));
+       E(mdb_txn_commit(txn));
 
        /* Try MDB_NEXT_MULTIPLE */
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT_MULTIPLE)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_txn_abort(txn);
        j=0;
@@ -119,38 +126,39 @@ int main(int argc,char * argv[])
        for (i= count - 1; i > -1; i-= (random()%3)) {
                j++;
                txn=NULL;
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
+               E(mdb_txn_begin(env, NULL, 0, &txn));
                sprintf(sval, "%07x", values[i]);
                key.mv_size = sizeof(int);
                key.mv_data = kval;
                data.mv_size = sizeof(sval);
                data.mv_data = sval;
-               rc = mdb_del(txn, dbi, &key, &data);
-               if (rc) {
+               if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
                        j--;
                        mdb_txn_abort(txn);
                } else {
-                       rc = mdb_txn_commit(txn);
+                       E(mdb_txn_commit(txn));
                }
        }
        free(values);
        printf("Deleted %d values\n", j);
 
-       rc = mdb_env_stat(env, &mst);
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_env_stat(env, &mst));
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        printf("Cursor next\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        printf("Cursor prev\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_close(env, dbi);
 
index bc472fa0930a519a7c26bfabd14ad3e14378c971..4edfea0d4c4d61ea103c47a01f7d6b277ea27f6a 100644 (file)
 #include <time.h>
 #include "lmdb.h"
 
+#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
+#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
+#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
+       "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
+
 int main(int argc,char * argv[])
 {
        int i = 0, j = 0, rc;
@@ -45,13 +50,13 @@ int main(int argc,char * argv[])
                values[i] = random()%1024;
        }
 
-       rc = mdb_env_create(&env);
-       rc = mdb_env_set_mapsize(env, 10485760);
-       rc = mdb_env_set_maxdbs(env, 4);
-       rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_env_create(&env));
+       E(mdb_env_set_mapsize(env, 10485760));
+       E(mdb_env_set_maxdbs(env, 4));
+       E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       E(mdb_open(txn, "id2", MDB_CREATE|MDB_DUPSORT, &dbi));
+       E(mdb_cursor_open(txn, dbi, &cursor));
 
        key.mv_size = sizeof(int);
        key.mv_data = kval;
@@ -63,21 +68,22 @@ int main(int argc,char * argv[])
                if (!(i & 0x0f))
                        sprintf(kval, "%03x", values[i]);
                sprintf(sval, "%03x %d foo bar", values[i], values[i]);
-               rc = mdb_cursor_put(cursor, &key, &data, MDB_NODUPDATA);
-               if (rc) j++;
+               if (RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NODUPDATA)))
+                       j++;
        }
        if (j) printf("%d duplicates skipped\n", j);
        mdb_cursor_close(cursor);
-       rc = mdb_txn_commit(txn);
-       rc = mdb_env_stat(env, &mst);
+       E(mdb_txn_commit(txn));
+       E(mdb_env_stat(env, &mst));
 
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %p %.*s, data: %p %.*s\n",
                        key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
                        data.mv_data, (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_txn_abort(txn);
 
@@ -86,39 +92,40 @@ int main(int argc,char * argv[])
        for (i= count - 1; i > -1; i-= (random()%5)) {
                j++;
                txn=NULL;
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
+               E(mdb_txn_begin(env, NULL, 0, &txn));
                sprintf(kval, "%03x", values[i & ~0x0f]);
                sprintf(sval, "%03x %d foo bar", values[i], values[i]);
                key.mv_size = sizeof(int);
                key.mv_data = kval;
                data.mv_size = sizeof(sval);
                data.mv_data = sval;
-               rc = mdb_del(txn, dbi, &key, &data);
-               if (rc) {
+               if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
                        j--;
                        mdb_txn_abort(txn);
                } else {
-                       rc = mdb_txn_commit(txn);
+                       E(mdb_txn_commit(txn));
                }
        }
        free(values);
        printf("Deleted %d values\n", j);
 
-       rc = mdb_env_stat(env, &mst);
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_env_stat(env, &mst));
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        printf("Cursor next\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        printf("Cursor prev\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_close(env, dbi);
 
index 0bf26ccc45ab93bfd9e869feb9972940abd42c41..8d32e8851abb35a811385cd34198dacb966493d8 100644 (file)
 #include <time.h>
 #include "lmdb.h"
 
+#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
+#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
+#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
+       "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))
+
 char dkbuf[1024];
 
 int main(int argc,char * argv[])
@@ -38,14 +43,14 @@ int main(int argc,char * argv[])
 
        srandom(time(NULL));
 
-       rc = mdb_env_create(&env);
-       rc = mdb_env_set_mapsize(env, 10485760);
-       rc = mdb_env_set_maxdbs(env, 4);
-       rc = mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_open(txn, "id2", MDB_CREATE|MDB_INTEGERKEY, &dbi);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
-       rc = mdb_stat(txn, dbi, &mst);
+       E(mdb_env_create(&env));
+       E(mdb_env_set_mapsize(env, 10485760));
+       E(mdb_env_set_maxdbs(env, 4));
+       E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664));
+       E(mdb_txn_begin(env, NULL, 0, &txn));
+       E(mdb_open(txn, "id6", MDB_CREATE|MDB_INTEGERKEY, &dbi));
+       E(mdb_cursor_open(txn, dbi, &cursor));
+       E(mdb_stat(txn, dbi, &mst));
 
        sval = calloc(1, mst.ms_psize / 4);
        key.mv_size = sizeof(long);
@@ -57,27 +62,28 @@ int main(int argc,char * argv[])
        for (i=0;i<12;i++) {
                kval = i*5;
                sprintf(sval, "%08x", kval);
-               rc = mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE);
+               (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
        }
        printf("Adding 12 more values, should yield 3 splits\n");
        for (i=0;i<12;i++) {
                kval = i*5+4;
                sprintf(sval, "%08x", kval);
-               rc = mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE);
+               (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
        }
        printf("Adding 12 more values, should yield 3 splits\n");
        for (i=0;i<12;i++) {
                kval = i*5+1;
                sprintf(sval, "%08x", kval);
-               rc = mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE);
+               (void)RES(MDB_KEYEXIST, mdb_cursor_put(cursor, &key, &data, MDB_NOOVERWRITE));
        }
-       rc = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
+       E(mdb_cursor_get(cursor, &key, &data, MDB_FIRST));
 
        do {
                printf("key: %p %s, data: %p %.*s\n",
                        key.mv_data,  mdb_dkey(&key, dkbuf),
                        data.mv_data, (int) data.mv_size, (char *) data.mv_data);
        } while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0);
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
        mdb_txn_commit(txn);
 
@@ -87,41 +93,42 @@ int main(int argc,char * argv[])
        for (i= count - 1; i > -1; i-= (random()%5)) {
                j++;
                txn=NULL;
-               rc = mdb_txn_begin(env, NULL, 0, &txn);
+               E(mdb_txn_begin(env, NULL, 0, &txn));
                sprintf(kval, "%03x", values[i & ~0x0f]);
                sprintf(sval, "%03x %d foo bar", values[i], values[i]);
                key.mv_size = sizeof(int);
                key.mv_data = kval;
                data.mv_size = sizeof(sval);
                data.mv_data = sval;
-               rc = mdb_del(txn, dbi, &key, &data);
-               if (rc) {
+               if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, &data))) {
                        j--;
                        mdb_txn_abort(txn);
                } else {
-                       rc = mdb_txn_commit(txn);
+                       E(mdb_txn_commit(txn));
                }
        }
        free(values);
        printf("Deleted %d values\n", j);
 
-       rc = mdb_env_stat(env, &mst);
-       rc = mdb_txn_begin(env, NULL, 1, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
+       E(mdb_env_stat(env, &mst));
+       E(mdb_txn_begin(env, NULL, 1, &txn));
+       E(mdb_cursor_open(txn, dbi, &cursor));
        printf("Cursor next\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        printf("Cursor prev\n");
        while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {
                printf("key: %.*s, data: %.*s\n",
                        (int) key.mv_size,  (char *) key.mv_data,
                        (int) data.mv_size, (char *) data.mv_data);
        }
+       CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");
        mdb_cursor_close(cursor);
-       mdb_close(txn, dbi);
+       mdb_close(env, dbi);
 
        mdb_txn_abort(txn);
 #endif
diff --git a/libraries/liblmdb/sample-bdb.c b/libraries/liblmdb/sample-bdb.c
deleted file mode 100644 (file)
index 2c11bb3..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* sample-bdb.c - BerkeleyDB toy/sample
- *
- * Do a line-by-line comparison of this and sample-mdb.c
- */
-/*
- * Copyright 2012 Howard Chu, Symas Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-#include <stdio.h>
-#include <string.h>
-#include <db.h>
-
-int main(int argc,char * argv[])
-{
-       int rc;
-       DB_ENV *env;
-       DB *dbi;
-       DBT key, data;
-       DB_TXN *txn;
-       DBC *cursor;
-       char sval[32], kval[32];
-
-#define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD)
-       rc = db_env_create(&env, 0);
-       rc = env->open(env, "./testdb", FLAGS, 0664);
-       rc = db_create(&dbi, env, 0);
-       rc = env->txn_begin(env, NULL, &txn, 0);
-       rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664);
-
-       memset(&key, 0, sizeof(DBT));
-       memset(&data, 0, sizeof(DBT));
-       key.size = sizeof(int);
-       key.data = sval;
-       data.size = sizeof(sval);
-       data.data = sval;
-
-       sprintf(sval, "%03x %d foo bar", 32, 3141592);
-       rc = dbi->put(dbi, txn, &key, &data, 0);
-       rc = txn->commit(txn, 0);
-       if (rc) {
-               fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc));
-               goto leave;
-       }
-       rc = env->txn_begin(env, NULL, &txn, 0);
-       rc = dbi->cursor(dbi, txn, &cursor, 0);
-       key.flags = DB_DBT_USERMEM;
-       key.data = kval;
-       key.ulen = sizeof(kval);
-       data.flags = DB_DBT_USERMEM;
-       data.data = sval;
-       data.ulen = sizeof(sval);
-       while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
-               printf("key: %p %.*s, data: %p %.*s\n",
-                       key.data,  (int) key.size,  (char *) key.data,
-                       data.data, (int) data.size, (char *) data.data);
-       }
-       rc = cursor->c_close(cursor);
-       rc = txn->abort(txn);
-leave:
-       rc = dbi->close(dbi, 0);
-       rc = env->close(env, 0);
-       return rc;
-}
diff --git a/libraries/liblmdb/sample-bdb.txt b/libraries/liblmdb/sample-bdb.txt
new file mode 100644 (file)
index 0000000..6a959bd
--- /dev/null
@@ -0,0 +1,73 @@
+/* sample-bdb.txt - BerkeleyDB toy/sample
+ *
+ * Do a line-by-line comparison of this and sample-mdb.txt
+ */
+/*
+ * Copyright 2012 Howard Chu, Symas Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <db.h>
+
+int main(int argc,char * argv[])
+{
+       int rc;
+       DB_ENV *env;
+       DB *dbi;
+       DBT key, data;
+       DB_TXN *txn;
+       DBC *cursor;
+       char sval[32], kval[32];
+
+       /* Note: Most error checking omitted for simplicity */
+
+#define FLAGS (DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_INIT_MPOOL|DB_CREATE|DB_THREAD)
+       rc = db_env_create(&env, 0);
+       rc = env->open(env, "./testdb", FLAGS, 0664);
+       rc = db_create(&dbi, env, 0);
+       rc = env->txn_begin(env, NULL, &txn, 0);
+       rc = dbi->open(dbi, txn, "test.bdb", NULL, DB_BTREE, DB_CREATE, 0664);
+
+       memset(&key, 0, sizeof(DBT));
+       memset(&data, 0, sizeof(DBT));
+       key.size = sizeof(int);
+       key.data = sval;
+       data.size = sizeof(sval);
+       data.data = sval;
+
+       sprintf(sval, "%03x %d foo bar", 32, 3141592);
+       rc = dbi->put(dbi, txn, &key, &data, 0);
+       rc = txn->commit(txn, 0);
+       if (rc) {
+               fprintf(stderr, "txn->commit: (%d) %s\n", rc, db_strerror(rc));
+               goto leave;
+       }
+       rc = env->txn_begin(env, NULL, &txn, 0);
+       rc = dbi->cursor(dbi, txn, &cursor, 0);
+       key.flags = DB_DBT_USERMEM;
+       key.data = kval;
+       key.ulen = sizeof(kval);
+       data.flags = DB_DBT_USERMEM;
+       data.data = sval;
+       data.ulen = sizeof(sval);
+       while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) {
+               printf("key: %p %.*s, data: %p %.*s\n",
+                       key.data,  (int) key.size,  (char *) key.data,
+                       data.data, (int) data.size, (char *) data.data);
+       }
+       rc = cursor->c_close(cursor);
+       rc = txn->abort(txn);
+leave:
+       rc = dbi->close(dbi, 0);
+       rc = env->close(env, 0);
+       return rc;
+}
diff --git a/libraries/liblmdb/sample-mdb.c b/libraries/liblmdb/sample-mdb.c
deleted file mode 100644 (file)
index 0b10f47..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/* sample-mdb.c - MDB toy/sample
- *
- * Do a line-by-line comparison of this and sample-bdb.c
- */
-/*
- * Copyright 2012 Howard Chu, Symas Corp.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted only as authorized by the OpenLDAP
- * Public License.
- *
- * A copy of this license is available in the file LICENSE in the
- * top-level directory of the distribution or, alternatively, at
- * <http://www.OpenLDAP.org/license.html>.
- */
-#include <stdio.h>
-#include "lmdb.h"
-
-int main(int argc,char * argv[])
-{
-       int rc;
-       MDB_env *env;
-       MDB_dbi dbi;
-       MDB_val key, data;
-       MDB_txn *txn;
-       MDB_cursor *cursor;
-       char sval[32];
-
-       rc = mdb_env_create(&env);
-       rc = mdb_env_open(env, "./testdb", 0, 0664);
-       rc = mdb_txn_begin(env, NULL, 0, &txn);
-       rc = mdb_open(txn, NULL, 0, &dbi);
-
-       key.mv_size = sizeof(int);
-       key.mv_data = sval;
-       data.mv_size = sizeof(sval);
-       data.mv_data = sval;
-
-       sprintf(sval, "%03x %d foo bar", 32, 3141592);
-       rc = mdb_put(txn, dbi, &key, &data, 0);
-       rc = mdb_txn_commit(txn);
-       if (rc) {
-               fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc));
-               goto leave;
-       }
-       rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
-       rc = mdb_cursor_open(txn, dbi, &cursor);
-       while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
-               printf("key: %p %.*s, data: %p %.*s\n",
-                       key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
-                       data.mv_data, (int) data.mv_size, (char *) data.mv_data);
-       }
-       mdb_cursor_close(cursor);
-       mdb_txn_abort(txn);
-leave:
-       mdb_close(env, dbi);
-       mdb_env_close(env);
-       return 0;
-}
diff --git a/libraries/liblmdb/sample-mdb.txt b/libraries/liblmdb/sample-mdb.txt
new file mode 100644 (file)
index 0000000..a233ec5
--- /dev/null
@@ -0,0 +1,62 @@
+/* sample-mdb.txt - MDB toy/sample
+ *
+ * Do a line-by-line comparison of this and sample-bdb.txt
+ */
+/*
+ * Copyright 2012 Howard Chu, Symas Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+#include <stdio.h>
+#include "lmdb.h"
+
+int main(int argc,char * argv[])
+{
+       int rc;
+       MDB_env *env;
+       MDB_dbi dbi;
+       MDB_val key, data;
+       MDB_txn *txn;
+       MDB_cursor *cursor;
+       char sval[32];
+
+       /* Note: Most error checking omitted for simplicity */
+
+       rc = mdb_env_create(&env);
+       rc = mdb_env_open(env, "./testdb", 0, 0664);
+       rc = mdb_txn_begin(env, NULL, 0, &txn);
+       rc = mdb_open(txn, NULL, 0, &dbi);
+
+       key.mv_size = sizeof(int);
+       key.mv_data = sval;
+       data.mv_size = sizeof(sval);
+       data.mv_data = sval;
+
+       sprintf(sval, "%03x %d foo bar", 32, 3141592);
+       rc = mdb_put(txn, dbi, &key, &data, 0);
+       rc = mdb_txn_commit(txn);
+       if (rc) {
+               fprintf(stderr, "mdb_txn_commit: (%d) %s\n", rc, mdb_strerror(rc));
+               goto leave;
+       }
+       rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
+       rc = mdb_cursor_open(txn, dbi, &cursor);
+       while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
+               printf("key: %p %.*s, data: %p %.*s\n",
+                       key.mv_data,  (int) key.mv_size,  (char *) key.mv_data,
+                       data.mv_data, (int) data.mv_size, (char *) data.mv_data);
+       }
+       mdb_cursor_close(cursor);
+       mdb_txn_abort(txn);
+leave:
+       mdb_close(env, dbi);
+       mdb_env_close(env);
+       return 0;
+}