#endif
#endif
-#define ULONG unsigned long
typedef ULONG pgno_t;
#ifndef DEBUG
static int mdb_cursor_last(MDB_cursor *cursor,
MDB_val *key, MDB_val *data);
-static void mdb_xcursor_init0(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx);
+static void mdb_xcursor_init0(MDB_cursor *mc);
static void mdb_xcursor_init1(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx,
MDB_page *mp, MDB_node *node);
static void mdb_xcursor_fini(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx);
mdb_get(MDB_txn *txn, MDB_dbi dbi,
MDB_val *key, MDB_val *data)
{
- int rc, exact;
- MDB_node *leaf;
- MDB_pageparent mpp;
+ MDB_cursor mc;
+ MDB_xcursor mx;
+ int exact;
DKBUF;
assert(key);
return EINVAL;
}
- if ((rc = mdb_search_page(txn, dbi, key, NULL, 0, &mpp)) != MDB_SUCCESS)
- return rc;
-
- leaf = mdb_search_node(txn, dbi, mpp.mp_page, key, &exact, NULL);
- if (leaf && exact) {
- /* Return first duplicate data item */
- if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
- MDB_xcursor mx;
-
- mdb_xcursor_init0(txn, dbi, &mx);
- mdb_xcursor_init1(txn, dbi, &mx, mpp.mp_page, leaf);
- rc = mdb_search_page(&mx.mx_txn, mx.mx_cursor.mc_dbi, NULL, NULL, 0, &mpp);
- if (rc != MDB_SUCCESS)
- return rc;
- if (IS_LEAF2(mpp.mp_page)) {
- data->mv_size = txn->mt_dbs[dbi].md_pad;
- data->mv_data = LEAF2KEY(mpp.mp_page, 0, data->mv_size);
- } else {
- leaf = NODEPTR(mpp.mp_page, 0);
- data->mv_size = NODEKSZ(leaf);
- data->mv_data = NODEKEY(leaf);
- }
- } else {
- rc = mdb_read_data(txn, leaf, data);
- }
+ mc.mc_txn = txn;
+ mc.mc_dbi = dbi;
+ mc.mc_initialized = 0;
+ if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
+ mc.mc_xcursor = &mx;
+ mdb_xcursor_init0(&mc);
} else {
- rc = MDB_NOTFOUND;
+ mc.mc_xcursor = NULL;
}
-
- return rc;
+ return mdb_cursor_set(&mc, key, data, MDB_SET, &exact);
}
static int
return rc;
}
+static int
+mdb_cursor_touch(MDB_cursor *cursor)
+{
+ MDB_pageparent mpp;
+ unsigned int i;
+ int rc;
+
+ mpp.mp_parent = NULL;
+ mpp.mp_pi = 0;
+ for(i=0; i<cursor->mc_snum; i++) {
+ mpp.mp_page = cursor->mc_stack[i].mp_page;
+ if (!F_ISSET(mpp.mp_page->mp_flags, P_DIRTY)) {
+ rc = mdb_touch(cursor->mc_txn, cursor->mc_dbi, &mpp);
+ if (rc) return rc;
+ cursor->mc_stack[i].mp_page = mpp.mp_page;
+ }
+ mpp.mp_parent = mpp.mp_page;
+ mpp.mp_pi = cursor->mc_stack[i].mp_ki;
+ }
+ if (cursor->mc_xcursor)
+ return mdb_cursor_touch(&cursor->mc_xcursor->mx_cursor);
+ return MDB_SUCCESS;
+}
+
+int
+mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data,
+ unsigned int flags)
+{
+ MDB_ppage *top;
+ MDB_node *leaf;
+ int rc, exact;
+
+ if (flags == MDB_NODUPDATA) {
+ rc = mdb_cursor_set(cursor, key, data, MDB_GET_BOTH, &exact);
+ if (rc == 0)
+ return MDB_KEYEXIST;
+ if (rc != MDB_NOTFOUND)
+ return rc;
+ } else if (flags != MDB_CURRENT) {
+ rc = mdb_cursor_set(cursor, key, NULL, MDB_SET, &exact);
+ if (flags == MDB_NOOVERWRITE && rc == 0)
+ return MDB_KEYEXIST;
+ if (rc != MDB_NOTFOUND)
+ return rc;
+ } else if (!cursor->mc_initialized) {
+ return EINVAL;
+ }
+ /* Cursor is positioned, now make sure all pages are writable */
+ rc = mdb_cursor_touch(cursor);
+ if (rc) return rc;
+
+ top = CURSOR_TOP(cursor);
+
+}
+
/* Allocate a page and initialize it
*/
static MDB_dpage *
}
static void
-mdb_xcursor_init0(MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
+mdb_xcursor_init0(MDB_cursor *mc)
{
+ MDB_xcursor *mx = mc->mc_xcursor;
MDB_dbi dbn;
- mx->mx_txn = *txn;
+ mx->mx_txn = *mc->mc_txn;
mx->mx_txn.mt_dbxs = mx->mx_dbxs;
mx->mx_txn.mt_dbs = mx->mx_dbs;
- mx->mx_dbxs[0] = txn->mt_dbxs[0];
- mx->mx_dbxs[1] = txn->mt_dbxs[1];
- if (dbi > 1) {
- mx->mx_dbxs[2] = txn->mt_dbxs[dbi];
+ mx->mx_dbxs[0] = mc->mc_txn->mt_dbxs[0];
+ mx->mx_dbxs[1] = mc->mc_txn->mt_dbxs[1];
+ if (mc->mc_dbi > 1) {
+ mx->mx_dbxs[2] = mc->mc_txn->mt_dbxs[mc->mc_dbi];
dbn = 2;
} else {
dbn = 1;
if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
MDB_xcursor *mx = (MDB_xcursor *)(cursor + 1);
cursor->mc_xcursor = mx;
- mdb_xcursor_init0(txn, dbi, mx);
+ mdb_xcursor_init0(cursor);
}
} else {
return ENOMEM;
}
if (!IS_LEAF2(mpp.mp_page) && F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ MDB_cursor mc;
MDB_xcursor mx;
MDB_pageparent mp2;
- mdb_xcursor_init0(txn, dbi, &mx);
+ mc.mc_txn = txn;
+ mc.mc_dbi = dbi;
+ mc.mc_initialized = 0;
+ mc.mc_xcursor = &mx;
+ mdb_xcursor_init0(&mc);
mdb_xcursor_init1(txn, dbi, &mx, mpp.mp_page, leaf);
if (data) {
rc = mdb_del(&mx.mx_txn, mx.mx_cursor.mc_dbi, data, NULL);
* DB are all zero size.
*/
if (do_sub) {
+ MDB_cursor mc;
MDB_xcursor mx;
leaf = NODEPTR(mpp.mp_page, ki);
put_sub:
- mdb_xcursor_init0(txn, dbi, &mx);
+ mc.mc_txn = txn;
+ mc.mc_dbi = dbi;
+ mc.mc_initialized = 0;
+ mc.mc_xcursor = &mx;
+ mdb_xcursor_init0(&mc);
mdb_xcursor_init1(txn, dbi, &mx, mpp.mp_page, leaf);
xdata.mv_size = 0;
xdata.mv_data = "";
mdb_put(MDB_txn *txn, MDB_dbi dbi,
MDB_val *key, MDB_val *data, unsigned int flags)
{
+ MDB_cursor mc;
+ MDB_xcursor mx;
+ int rc;
+
assert(key != NULL);
assert(data != NULL);
if ((flags & (MDB_NOOVERWRITE|MDB_NODUPDATA)) != flags)
return EINVAL;
- return mdb_put0(txn, dbi, key, data, flags);
+ mc.mc_txn = txn;
+ mc.mc_dbi = dbi;
+ mc.mc_snum = 0;
+ mc.mc_initialized = 0;
+ mc.mc_eof = 0;
+ if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) {
+ mc.mc_xcursor = &mx;
+ mdb_xcursor_init0(&mc);
+ } else {
+ mc.mc_xcursor = NULL;
+ }
+ rc = mdb_cursor_put(&mc, key, data, flags);
+ if (mc.mc_xcursor) {
+ MDB_ppage *top;
+ MDB_node *leaf;
+ mdb_xcursor_fini(txn, dbi, &mx);
+ top = CURSOR_TOP(&mc);
+ leaf = NODEPTR(top->mp_page, top->mp_ki);
+ memcpy(NODEDATA(leaf), &mx.mx_txn.mt_dbs[mx.mx_cursor.mc_dbi],
+ sizeof(MDB_db));
+ }
+ return rc;
}
int
*/
typedef void (MDB_rel_func)(void *newptr, void *oldptr, size_t size);
-/** @defgroup mdb_env environment flags
+/** @defgroup mdb_env Environment Flags
* @{
*/
/** mmap at a fixed address */
#define MDB_RDONLY 0x20000
/** @} */
-/** @defgroup mdb_open database flags
+/** @defgroup mdb_open Database Flags
* @{
*/
/** use reverse string keys */
#define MDB_CREATE 0x40000
/** @} */
-/** @defgroup mdb_put mdb_put flags
+/** @defgroup mdb_put Write Flags
* @{
*/
-/** For mdb_put: don't write if the key already exists. */
+/** For put: Don't write if the key already exists. */
#define MDB_NOOVERWRITE 0x10
-/** For mdb_put: don't write if the key and data pair already exist.
- * Only for #MDB_DUPSORT
+/** Only for #MDB_DUPSORT<br>
+ * For put: don't write if the key and data pair already exist.<br>
+ * For mdb_cursor_del: remove all duplicate data items.
*/
#define MDB_NODUPDATA 0x20
+/** For mdb_cursor_put: overwrite the current key/data pair */
+#define MDB_CURRENT 0x40
/* @} */
/** Cursor operations */
/** Create a cursor handle.
* Cursors are associated with a specific transaction and database and
* may not span threads.
- * @todo Cursors only support read operations. Support for cursor_put() and
- * cursor_del() needs to be added.
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
* @param[in] dbi A database handle returned by #mdb_open()
* @param[out] cursor Address where the new #MDB_cursor handle will be stored