diff --git a/libraries/libmdb/mdb.c b/libraries/libmdb/mdb.c index 4563e23..2db10ea 100644 --- a/libraries/libmdb/mdb.c +++ b/libraries/libmdb/mdb.c @@ -1328,6 +1328,27 @@ none: return np; } +/** Copy a page: avoid copying unused portions of the page. + * @param[in] dst page to copy into + * @param[in] src page to copy from + */ +static void +mdb_page_copy(MDB_page *dst, MDB_page *src, unsigned int psize) +{ + dst->mp_flags = src->mp_flags | P_DIRTY; + dst->mp_pages = src->mp_pages; + + if (IS_LEAF2(src)) { + memcpy(dst->mp_ptrs, src->mp_ptrs, psize - PAGEHDRSZ - SIZELEFT(src)); + } else { + unsigned int i, nkeys = NUMKEYS(src); + for (i=0; imp_ptrs[i] = src->mp_ptrs[i]; + memcpy((char *)dst+src->mp_upper, (char *)src+src->mp_upper, + psize - src->mp_upper); + } +} + /** Touch a page: make it dirty and re-insert into tree with updated pgno. * @param[in] mc cursor pointing to the page to be touched * @return 0 on success, non-zero on failure. @@ -1345,11 +1366,16 @@ mdb_page_touch(MDB_cursor *mc) DPRINTF("touched db %u page %zu -> %zu", mc->mc_dbi, mp->mp_pgno, np->mp_pgno); assert(mp->mp_pgno != np->mp_pgno); mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); - pgno = np->mp_pgno; - memcpy(np, mp, mc->mc_txn->mt_env->me_psize); + if (SIZELEFT(mp)) { + /* If page isn't full, just copy the used portion */ + mdb_page_copy(np, mp, mc->mc_txn->mt_env->me_psize); + } else { + pgno = np->mp_pgno; + memcpy(np, mp, mc->mc_txn->mt_env->me_psize); + np->mp_pgno = pgno; + np->mp_flags |= P_DIRTY; + } mp = np; - mp->mp_pgno = pgno; - mp->mp_flags |= P_DIRTY; finish: /* Adjust other cursors pointing to mp */