diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c index 8086bf0..4ab4058 100644 --- a/libraries/liblmdb/mdb.c +++ b/libraries/liblmdb/mdb.c @@ -1438,8 +1438,8 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) if (!mop) { if (!(env->me_pghead = mop = mdb_midl_alloc(i))) return ENOMEM; - } else if (mop_len+i > mop[-1]) { - if ((rc = mdb_midl_grow(&env->me_pghead, i)) != 0) + } else { + if ((rc = mdb_midl_need(&env->me_pghead, i)) != 0) return rc; mop = env->me_pghead; } @@ -1538,12 +1538,13 @@ mdb_page_touch(MDB_cursor *mc) int rc; if (!F_ISSET(mp->mp_flags, P_DIRTY)) { - if ((rc = mdb_page_alloc(mc, 1, &np))) + if ((rc = mdb_midl_need(&txn->mt_free_pgs, 1)) || + (rc = mdb_page_alloc(mc, 1, &np))) return rc; pgno = np->mp_pgno; DPRINTF("touched db %u page %zu -> %zu", mc->mc_dbi,mp->mp_pgno,pgno); assert(mp->mp_pgno != pgno); - mdb_midl_append(&txn->mt_free_pgs, mp->mp_pgno); + mdb_midl_xappend(txn->mt_free_pgs, mp->mp_pgno); /* Update the parent page, if any, to point to the new page */ if (mc->mc_top) { MDB_page *parent = mc->mc_pg[mc->mc_top-1]; @@ -4207,16 +4208,11 @@ mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp) */ if ((mp->mp_flags & P_DIRTY) && !txn->mt_parent && txn->mt_env->me_pghead) { unsigned j, x; - pgno_t *mop = txn->mt_env->me_pghead; + pgno_t *mop; MDB_ID2 *dl, ix, iy; - /* Prepare to insert pg */ - j = mop[0] + ovpages; - if (j > mop[-1]) { - rc = mdb_midl_grow(&mop, ovpages); - if (rc) - return rc; - txn->mt_env->me_pghead = mop; - } + rc = mdb_midl_need(&txn->mt_env->me_pghead, ovpages); + if (rc) + return rc; /* Remove from dirty list */ dl = txn->mt_u.dirty_list; x = dl[0].mid--; @@ -4231,16 +4227,17 @@ mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp) } } /* Insert in me_pghead */ + mop = txn->mt_env->me_pghead; + j = mop[0] + ovpages; for (i = mop[0]; i && mop[i] < pg; i--) mop[j--] = mop[i]; while (j>i) mop[j--] = pg++; mop[0] += ovpages; } else { - for (i=0; imt_free_pgs, pg); - pg++; - } + rc = mdb_midl_append_range(&txn->mt_free_pgs, pg, ovpages); + if (rc) + return rc; } mc->mc_db->md_overflow_pages -= ovpages; return 0; @@ -5229,7 +5226,8 @@ current: memcpy(METADATA(omp), data->mv_data, data->mv_size); goto done; } else { - mdb_ovpage_free(mc, omp); + if ((rc2 = mdb_ovpage_free(mc, omp)) != MDB_SUCCESS) + return rc2; } } else if (NODEDSZ(leaf) == data->mv_size) { /* same size, just replace it. Note that we could @@ -6308,7 +6306,10 @@ mdb_page_merge(MDB_cursor *csrc, MDB_cursor *cdst) return rc; } - mdb_midl_append(&csrc->mc_txn->mt_free_pgs, csrc->mc_pg[csrc->mc_top]->mp_pgno); + rc = mdb_midl_append(&csrc->mc_txn->mt_free_pgs, + csrc->mc_pg[csrc->mc_top]->mp_pgno); + if (rc) + return rc; if (IS_LEAF(csrc->mc_pg[csrc->mc_top])) csrc->mc_db->md_leaf_pages--; else @@ -6409,7 +6410,9 @@ mdb_rebalance(MDB_cursor *mc) mc->mc_db->md_root = P_INVALID; mc->mc_db->md_depth = 0; mc->mc_db->md_leaf_pages = 0; - mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); + rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); + if (rc) + return rc; /* Adjust cursors pointing to mp */ mc->mc_snum = 0; mc->mc_top = 0; @@ -6434,7 +6437,9 @@ mdb_rebalance(MDB_cursor *mc) } } else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) { DPUTS("collapsing root page!"); - mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); + rc = mdb_midl_append(&mc->mc_txn->mt_free_pgs, mp->mp_pgno); + if (rc) + return rc; mc->mc_db->md_root = NODEPGNO(NODEPTR(mp, 0)); rc = mdb_page_get(mc->mc_txn,mc->mc_db->md_root,&mc->mc_pg[0],NULL); if (rc) @@ -6539,10 +6544,9 @@ mdb_cursor_del0(MDB_cursor *mc, MDB_node *leaf) pgno_t pg; memcpy(&pg, NODEDATA(leaf), sizeof(pg)); - if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) != 0) + if ((rc = mdb_page_get(mc->mc_txn, pg, &omp, NULL)) || + (rc = mdb_ovpage_free(mc, omp))) return rc; - assert(IS_OVERFLOW(omp)); - mdb_ovpage_free(mc, omp); } mdb_node_del(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top], mc->mc_db->md_pad); mc->mc_db->md_entries--; @@ -7312,7 +7316,6 @@ mdb_drop0(MDB_cursor *mc, int subs) for (i=0; imn_flags & F_BIGDATA) { - int j, ovpages; MDB_page *omp; pgno_t pg; memcpy(&pg, NODEDATA(ni), sizeof(pg)); @@ -7320,11 +7323,10 @@ mdb_drop0(MDB_cursor *mc, int subs) if (rc != 0) return rc; assert(IS_OVERFLOW(omp)); - ovpages = omp->mp_pages; - for (j=0; jmt_free_pgs, pg); - pg++; - } + rc = mdb_midl_append_range(&txn->mt_free_pgs, + pg, omp->mp_pages); + if (rc) + return rc; } else if (subs && (ni->mn_flags & F_SUBDATA)) { mdb_xcursor_init1(mc, ni); rc = mdb_drop0(&mc->mc_xcursor->mx_cursor, 0); @@ -7333,12 +7335,14 @@ mdb_drop0(MDB_cursor *mc, int subs) } } } else { + if ((rc = mdb_midl_need(&txn->mt_free_pgs, n)) != 0) + return rc; for (i=0; imt_free_pgs, pg); + mdb_midl_xappend(txn->mt_free_pgs, pg); } } if (!mc->mc_top) @@ -7358,9 +7362,11 @@ mdb_drop0(MDB_cursor *mc, int subs) } } /* free it */ - mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root); + rc = mdb_midl_append(&txn->mt_free_pgs, mc->mc_db->md_root); + } else if (rc == MDB_NOTFOUND) { + rc = MDB_SUCCESS; } - return 0; + return rc; } int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del) diff --git a/libraries/liblmdb/midl.c b/libraries/liblmdb/midl.c index 00df385..0fcedbe 100644 --- a/libraries/liblmdb/midl.c +++ b/libraries/liblmdb/midl.c @@ -120,8 +120,9 @@ void mdb_midl_free(MDB_IDL ids) int mdb_midl_shrink( MDB_IDL *idp ) { MDB_IDL ids = *idp; - if (*(--ids) > MDB_IDL_UM_MAX) { - ids = realloc(ids, (MDB_IDL_UM_MAX+1) * sizeof(MDB_ID)); + if (*(--ids) > MDB_IDL_UM_MAX && + (ids = realloc(ids, (MDB_IDL_UM_MAX+1) * sizeof(MDB_ID)))) + { *ids++ = MDB_IDL_UM_MAX; *idp = ids; return 1; @@ -129,7 +130,7 @@ int mdb_midl_shrink( MDB_IDL *idp ) return 0; } -int mdb_midl_grow( MDB_IDL *idp, int num ) +static int mdb_midl_grow( MDB_IDL *idp, int num ) { MDB_IDL idn = *idp-1; /* grow it */ @@ -141,6 +142,20 @@ int mdb_midl_grow( MDB_IDL *idp, int num ) return 0; } +int mdb_midl_need( MDB_IDL *idp, unsigned num ) +{ + MDB_IDL ids = *idp; + num += ids[0]; + if (num > ids[-1]) { + num = (num + num/4 + (256 + 2)) & -256; + if (!(ids = realloc(ids-1, num * sizeof(MDB_ID)))) + return ENOMEM; + *ids++ += num -= 2; + *idp = ids; + } + return 0; +} + int mdb_midl_append( MDB_IDL *idp, MDB_ID id ) { MDB_IDL ids = *idp; @@ -169,6 +184,22 @@ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app ) return 0; } +int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n ) +{ + MDB_ID *ids = *idp, len = ids[0]; + /* Too big? */ + if (len + n > ids[-1]) { + if (mdb_midl_grow(idp, n | MDB_IDL_UM_MAX)) + return ENOMEM; + ids = *idp; + } + ids[0] = len + n; + ids += len; + while (n) + ids[n--] = id++; + return 0; +} + /* Quicksort + Insertion sort for small arrays */ #define SMALL 8 diff --git a/libraries/liblmdb/midl.h b/libraries/liblmdb/midl.h index 019d928..9ce7133 100644 --- a/libraries/liblmdb/midl.h +++ b/libraries/liblmdb/midl.h @@ -68,6 +68,12 @@ typedef MDB_ID *MDB_IDL; #define MDB_IDL_FIRST( ids ) ( (ids)[1] ) #define MDB_IDL_LAST( ids ) ( (ids)[(ids)[0]] ) + /** Append ID to IDL. The IDL must be big enough. */ +#define mdb_midl_xappend(idl, id) do { \ + MDB_ID *xidl = (idl), xlen = ++(xidl[0]); \ + xidl[xlen] = (id); \ + } while (0) + #if 0 /* superseded by append/sort */ /** Insert an ID into an IDL. * @param[in,out] ids The IDL to insert into. @@ -95,28 +101,35 @@ void mdb_midl_free(MDB_IDL ids); */ int mdb_midl_shrink(MDB_IDL *idp); - /** Grow an IDL. - * Add room for num additional elements. - * @param[in,out] idp Address of the IDL to grow. - * @param[in] num Number of elements to add. - * @return 0 on success, -1 on failure. + /** Make room for num additional elements in an IDL. + * @param[in,out] idp Address of the IDL. + * @param[in] num Number of elements to make room for. + * @return 0 on success, ENOMEM on failure. */ -int mdb_midl_grow(MDB_IDL *idp, int num); +int mdb_midl_need(MDB_IDL *idp, unsigned num); /** Append an ID onto an IDL. * @param[in,out] idp Address of the IDL to append to. * @param[in] id The ID to append. - * @return 0 on success, -1 if the IDL is too large. + * @return 0 on success, ENOMEM if the IDL is too large. */ int mdb_midl_append( MDB_IDL *idp, MDB_ID id ); /** Append an IDL onto an IDL. * @param[in,out] idp Address of the IDL to append to. * @param[in] app The IDL to append. - * @return 0 on success, -1 if the IDL is too large. + * @return 0 on success, ENOMEM if the IDL is too large. */ int mdb_midl_append_list( MDB_IDL *idp, MDB_IDL app ); + /** Append an ID range onto an IDL. + * @param[in,out] idp Address of the IDL to append to. + * @param[in] id The lowest ID to append. + * @param[in] n Number of IDs to append. + * @return 0 on success, ENOMEM if the IDL is too large. + */ +int mdb_midl_append_range( MDB_IDL *idp, MDB_ID id, unsigned n ); + /** Sort an IDL. * @param[in,out] ids The IDL to sort. */