MDB_dbx *me_dbxs; /**< array of static DB info */
uint16_t *me_dbflags; /**< array of flags from MDB_db.md_flags */
pgno_t *me_pghead; /**< old pages reclaimed from freelist */
+ pgno_t *me_pgfree; /**< memory to free when dropping me_pghead */
pthread_key_t me_txkey; /**< thread-key for readers */
MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */
/** IDL of pages that became unused in a write txn */
MDB_IDL me_free_pgs;
/** ID2L of pages that were written during a write txn */
MDB_ID2 me_dirty_list[MDB_IDL_UM_SIZE];
+ /** Max number of freelist items that can fit in a single overflow page */
+ unsigned int me_maxfree_1pg;
#ifdef _WIN32
HANDLE me_rmutex; /* Windows mutexes don't reside in shared mem */
HANDLE me_wmutex;
if (!mop)
return ENOMEM;
txn->mt_env->me_pglast = last;
- txn->mt_env->me_pghead = mop;
+ txn->mt_env->me_pghead = txn->mt_env->me_pgfree = mop;
memcpy(mop, idl, MDB_IDL_SIZEOF(idl));
#if MDB_DEBUG > 1
mop2[k--] = mop[j--];
}
txn->mt_env->me_pglast = last;
- txn->mt_env->me_pghead = mop2;
- free(mop);
+ free(txn->mt_env->me_pgfree);
+ txn->mt_env->me_pghead = txn->mt_env->me_pgfree = mop2;
mop = mop2;
/* Keep trying to read until we have enough */
if (mop[0] < (unsigned)num) {
mop[0]--;
}
if (MDB_IDL_IS_ZERO(mop)) {
- txn->mt_env->me_pghead = NULL;
- free(mop);
+ free(txn->mt_env->me_pgfree);
+ txn->mt_env->me_pghead = txn->mt_env->me_pgfree = NULL;
}
}
}
if (!(env->me_flags & MDB_ROFS))
txn->mt_u.reader->mr_txnid = (txnid_t)-1;
} else {
- pgno_t *mop;
MDB_page *dp;
unsigned int i;
env->me_free_pgs = txn->mt_free_pgs;
}
- if ((mop = txn->mt_env->me_pghead) != NULL) {
- txn->mt_env->me_pghead = NULL;
- free(mop);
- }
+ free(txn->mt_env->me_pgfree);
+ txn->mt_env->me_pghead = txn->mt_env->me_pgfree = NULL;
txn->mt_env->me_pglast = 0;
env->me_txn = NULL;
off_t size;
MDB_page *dp;
MDB_env *env;
- pgno_t next, freecnt, maxfree_1pg;
+ pgno_t next, freecnt;
txnid_t oldpg_txnid, id;
MDB_cursor mc;
mdb_cursor_init(&mc, txn, FREE_DBI, NULL);
oldpg_txnid = id = 0;
freecnt = 0;
- /* Preferred max #items per freelist entry, to avoid overflow pages.
- * Leave room for headers, key (txnid), pagecount (pageno_t), and
- * FIXME: a bit more in case there is some delimiter I don't know about.
- */
- maxfree_1pg = (env->me_psize - (PAGEHDRSZ + NODESIZE + 3*sizeof(MDB_ID)))
- / sizeof(pgno_t);
/* should only be one record now */
if (env->me_pghead || env->me_pglast) {
i = 2;
do {
orig = mop[0];
- if (orig > maxfree_1pg && id > 4)
- orig = maxfree_1pg; /* Do not use an overflow page */
+ if (orig > env->me_maxfree_1pg && id > 4)
+ orig = env->me_maxfree_1pg; /* Do not use more than 1 page */
data.mv_size = (orig + 1) * sizeof(pgno_t);
rc = mdb_cursor_put(&mc, &key, &data, MDB_RESERVE);
if (rc)
if (mop[0] <= orig)
break;
*(pgno_t *)data.mv_data = orig;
- mop[0] -= orig;
- memmove(&mop[1], &mop[1 + orig],
- mop[0] * sizeof(pgno_t));
+ mop[orig] = mop[0] - orig;
+ env->me_pghead = mop += orig;
/* Save more oldpages at the previous txnid. */
assert(env->me_pglast == id && id == oldpg_txnid);
env->me_pglast = --oldpg_txnid;
if (freecnt != txn->mt_free_pgs[0])
goto free2;
- if (env->me_pghead) {
- free(env->me_pghead);
- env->me_pghead = NULL;
- }
+ free(env->me_pgfree);
+ env->me_pghead = env->me_pgfree = NULL;
if (!MDB_IDL_IS_ZERO(txn->mt_free_pgs)) {
if (mdb_midl_shrink(&txn->mt_free_pgs))
return EBUSY; /* TODO: Make a new MDB_* error code? */
}
env->me_psize = meta.mm_psize;
+ env->me_maxfree_1pg = (env->me_psize - PAGEHDRSZ) / sizeof(pgno_t) - 1;
env->me_maxpg = env->me_mapsize / env->me_psize;