mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-02 00:44:12 +08:00
lmdb: ITS#8263 fix cursor tracking in cursor_put.
Includes ITS#8263 streamline prev patch.
This commit is contained in:
parent
68171d5f5d
commit
f6045ae77e
70
mdb.c
70
mdb.c
@ -1059,6 +1059,7 @@ static int mdb_cursor_last(MDB_cursor *mc, MDB_val *key, MDB_val *data);
|
||||
static void mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx);
|
||||
static void mdb_xcursor_init0(MDB_cursor *mc);
|
||||
static void mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node);
|
||||
static void mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int force);
|
||||
|
||||
static int mdb_drop0(MDB_cursor *mc, int subs);
|
||||
static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi);
|
||||
@ -6202,7 +6203,7 @@ mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data,
|
||||
{
|
||||
MDB_env *env;
|
||||
MDB_node *leaf = NULL;
|
||||
MDB_page *fp, *mp;
|
||||
MDB_page *fp, *mp, *sub_root = NULL;
|
||||
uint16_t fp_flags;
|
||||
MDB_val xdata, *rdata, dkey, olddata;
|
||||
MDB_db dummy;
|
||||
@ -6491,6 +6492,7 @@ prep_subDB:
|
||||
offset = env->me_psize - olddata.mv_size;
|
||||
flags |= F_DUPDATA|F_SUBDATA;
|
||||
dummy.md_root = mp->mp_pgno;
|
||||
sub_root = mp;
|
||||
}
|
||||
if (mp != fp) {
|
||||
mp->mp_flags = fp_flags | P_DIRTY;
|
||||
@ -6637,7 +6639,7 @@ new_sub:
|
||||
* DB are all zero size.
|
||||
*/
|
||||
if (do_sub) {
|
||||
int xflags;
|
||||
int xflags, new_dupdata;
|
||||
size_t ecount;
|
||||
put_sub:
|
||||
xdata.mv_size = 0;
|
||||
@ -6650,28 +6652,32 @@ put_sub:
|
||||
xflags = (flags & MDB_NODUPDATA) ?
|
||||
MDB_NOOVERWRITE|MDB_NOSPILL : MDB_NOSPILL;
|
||||
}
|
||||
if (sub_root)
|
||||
mc->mc_xcursor->mx_cursor.mc_pg[0] = sub_root;
|
||||
new_dupdata = (int)dkey.mv_size;
|
||||
/* converted, write the original data first */
|
||||
if (dkey.mv_size) {
|
||||
rc = mdb_cursor_put(&mc->mc_xcursor->mx_cursor, &dkey, &xdata, xflags);
|
||||
if (unlikely(rc))
|
||||
goto bad_sub;
|
||||
{
|
||||
/* Adjust other cursors pointing to mp */
|
||||
MDB_cursor *m2;
|
||||
unsigned i = mc->mc_top;
|
||||
MDB_page *mp = mc->mc_pg[i];
|
||||
|
||||
for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
|
||||
if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
|
||||
if (!(m2->mc_flags & C_INITIALIZED)) continue;
|
||||
if (m2->mc_pg[i] == mp && m2->mc_ki[i] == mc->mc_ki[i]) {
|
||||
mdb_xcursor_init1(m2, leaf);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we've done our job */
|
||||
dkey.mv_size = 0;
|
||||
}
|
||||
if (!(leaf->mn_flags & F_SUBDATA) || sub_root) {
|
||||
/* Adjust other cursors pointing to mp */
|
||||
MDB_cursor *m2;
|
||||
MDB_xcursor *mx = mc->mc_xcursor;
|
||||
unsigned i = mc->mc_top;
|
||||
MDB_page *mp = mc->mc_pg[i];
|
||||
|
||||
for (m2 = mc->mc_txn->mt_cursors[mc->mc_dbi]; m2; m2=m2->mc_next) {
|
||||
if (m2 == mc || m2->mc_snum < mc->mc_snum) continue;
|
||||
if (!(m2->mc_flags & C_INITIALIZED)) continue;
|
||||
if (m2->mc_pg[i] == mp && m2->mc_ki[i] == mc->mc_ki[i]) {
|
||||
mdb_xcursor_init2(m2, mx, new_dupdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
ecount = mc->mc_xcursor->mx_db.md_entries;
|
||||
if (flags & MDB_APPENDDUP)
|
||||
xflags |= MDB_APPEND;
|
||||
@ -7215,6 +7221,38 @@ mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node)
|
||||
#endif */
|
||||
}
|
||||
|
||||
|
||||
/** Fixup a sorted-dups cursor due to underlying update.
|
||||
* Sets up some fields that depend on the data from the main cursor.
|
||||
* Almost the same as init1, but skips initialization steps if the
|
||||
* xcursor had already been used.
|
||||
* @param[in] mc The main cursor whose sorted-dups cursor is to be fixed up.
|
||||
* @param[in] src_mx The xcursor of an up-to-date cursor.
|
||||
* @param[in] new_dupdata True if converting from a non-#F_DUPDATA item.
|
||||
*/
|
||||
static void
|
||||
mdb_xcursor_init2(MDB_cursor *mc, MDB_xcursor *src_mx, int new_dupdata)
|
||||
{
|
||||
MDB_xcursor *mx = mc->mc_xcursor;
|
||||
|
||||
if (new_dupdata) {
|
||||
mx->mx_cursor.mc_snum = 1;
|
||||
mx->mx_cursor.mc_top = 0;
|
||||
mx->mx_cursor.mc_flags |= C_INITIALIZED;
|
||||
mx->mx_cursor.mc_ki[0] = 0;
|
||||
mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */
|
||||
#if UINT_MAX < SIZE_MAX
|
||||
mx->mx_dbx.md_cmp = src_mx->mx_dbx.md_cmp;
|
||||
#endif
|
||||
} else if (!(mx->mx_cursor.mc_flags & C_INITIALIZED)) {
|
||||
return;
|
||||
}
|
||||
mx->mx_db = src_mx->mx_db;
|
||||
mx->mx_cursor.mc_pg[0] = src_mx->mx_cursor.mc_pg[0];
|
||||
mdb_debug("Sub-db -%u root page %zu", mx->mx_cursor.mc_dbi,
|
||||
mx->mx_db.md_root);
|
||||
}
|
||||
|
||||
/** Initialize a cursor for a given transaction and database. */
|
||||
static void
|
||||
mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx)
|
||||
|
Loading…
x
Reference in New Issue
Block a user