+ /* It's potentially usable, unless there are still
+ * older readers outstanding. Grab it.
+ */
+ if (oldest > *kptr) {
+ MDB_oldpages *mop;
+ MDB_val data;
+ pgno_t *idl;
+
+ mdb_read_data(txn, leaf, &data);
+ idl = (ULONG *)data.mv_data;
+ mop = malloc(sizeof(MDB_oldpages) + MDB_IDL_SIZEOF(idl) - sizeof(pgno_t));
+ mop->mo_next = txn->mt_env->me_pghead;
+ mop->mo_txnid = *kptr;
+ txn->mt_env->me_pghead = mop;
+ memcpy(mop->mo_pages, idl, MDB_IDL_SIZEOF(idl));
+
+#if DEBUG > 1
+ {
+ unsigned int i;
+ DPRINTF("IDL read txn %lu root %lu num %lu",
+ mop->mo_txnid, txn->mt_dbs[FREE_DBI].md_root, idl[0]);
+ for (i=0; i<idl[0]; i++) {
+ DPRINTF("IDL %lu", idl[i+1]);
+ }
+ }
+#endif
+ /* drop this IDL from the DB */
+ mpp.mp_parent = NULL;
+ mpp.mp_pi = 0;
+ mdb_search_page(txn, FREE_DBI, NULL, NULL, 1, &mpp);
+ leaf = NODEPTR(mpp.mp_page, 0);
+ mdb_del0(txn, FREE_DBI, 0, &mpp, leaf);
+ }
+ }
+ if (txn->mt_env->me_pghead) {
+ unsigned int i;
+ for (i=0; i<txn->mt_env->me_txns->mti_numreaders; i++) {
+ ULONG mr = txn->mt_env->me_txns->mti_readers[i].mr_txnid;
+ if (!mr) continue;
+ if (mr < oldest)
+ oldest = txn->mt_env->me_txns->mti_readers[i].mr_txnid;
+ }
+ if (oldest > txn->mt_env->me_pghead->mo_txnid) {
+ MDB_oldpages *mop = txn->mt_env->me_pghead;
+ txn->mt_oldest = oldest;
+ if (num > 1) {
+ /* FIXME: For now, always use fresh pages. We
+ * really ought to search the free list for a
+ * contiguous range.
+ */
+ ;
+ } else {
+ /* peel pages off tail, so we only have to truncate the list */
+ pgno = MDB_IDL_LAST(mop->mo_pages);
+ if (MDB_IDL_IS_RANGE(mop->mo_pages)) {
+ mop->mo_pages[2]++;
+ if (mop->mo_pages[2] > mop->mo_pages[1])
+ mop->mo_pages[0] = 0;
+ } else {
+ mop->mo_pages[0]--;
+ }
+ if (MDB_IDL_IS_ZERO(mop->mo_pages)) {
+ txn->mt_env->me_pghead = mop->mo_next;
+ free(mop);
+ }
+ }
+ }
+ }
+ }
+
+ if (pgno == P_INVALID) {
+ /* DB size is maxed out */
+ if (txn->mt_next_pgno + num >= txn->mt_env->me_maxpg)
+ return NULL;
+ }
+ if (txn->mt_env->me_dpages && num == 1) {
+ dp = txn->mt_env->me_dpages;
+ txn->mt_env->me_dpages = (MDB_dpage *)dp->h.md_parent;
+ } else {
+ if ((dp = malloc(txn->mt_env->me_psize * num + sizeof(MDB_dhead))) == NULL)
+ return NULL;
+ }