diff --git a/dependencies/lmdb/libraries/liblmdb/mdb.c b/dependencies/lmdb/libraries/liblmdb/mdb.c index 4254223e1..c808c2412 100644 --- a/dependencies/lmdb/libraries/liblmdb/mdb.c +++ b/dependencies/lmdb/libraries/liblmdb/mdb.c @@ -2728,7 +2728,7 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) } unsigned empty_entries = 0; unsigned cache_size = env->me_block_size_cache[0]; - pgno_t best_fit_start; // this is a block we will use if we don't find an exact fit + unsigned best_fit_start; // this is a block we will use if we don't find an exact fit pgno_t best_fit_size; for (op = MDB_FIRST;; op = MDB_NEXT) { MDB_val key, data; @@ -2758,8 +2758,9 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) unsigned block_size = 0; ssize_t entry; empty_entries = 0; + mdb_midl_print(stderr, mop); // TODO: Skip this on the first iteration, since we already checked the cache - for (i = 1; i <= mop_len; i++) { + for (i = env->me_freelist_position || 1; i <= mop_len; i++) { entry = mop[i]; //fprintf(stderr, "pgno %u next would be %u\n", entry, block_start + block_size); if (entry == 0) { @@ -2783,6 +2784,12 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) } else if (block_size < best_fit_size || best_fit_size == 0) { best_fit_start = i - 1; best_fit_size = block_size; + if (i == env->me_freelist_position) { + // TODO: Only if we are in the same transaction + // if we just wrote to this block and we are continuing on this block, + // skip ahead to using this block + goto continue_best_fit; + } } } if (block_size > 0) { @@ -2802,6 +2809,7 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) //if (mop[i-n2] == pgno+n2) // goto search_done; } + env->me_freelist_position = 1; i = 0; if (op == MDB_FIRST) { /* 1st iteration */ @@ -2889,12 +2897,13 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp) if (mop != env->me_pghead) env->me_pghead = mop; mop_len = mop[0]; } + continue_best_fit: if (best_fit_start > 0) { mop[best_fit_start] += num; // block length is a negative, so we add to it in order to subtract the amount we are using if (mop[best_fit_start] == -1) mop[best_fit_start] = 0; pgno = mop[best_fit_start + 1]; mop[best_fit_start + 1] += num; - env->me_freelist_position = pgno; + env->me_freelist_position = best_fit_start; fprintf(stderr, "using best fit at %u size %u of %u\n", pgno, num, best_fit_size); env->me_block_size_cache[best_fit_size] = 0; // clear this out of the cache (TODO: could move it) @@ -3484,6 +3493,15 @@ mdb_txn_renew0(MDB_txn *txn) if (ti) { if (LOCK_MUTEX(rc, env, env->me_wmutex)) return rc; + // TODO: This should really be equality check and mt_txnid should be decremented if nothing was written + if (txn->mt_txnid < ti->mti_txnid) { + if (env->me_pghead) mdb_midl_free(env->me_pghead); + env->me_pghead = NULL; + env->me_pglast = 0; + env->me_freelist_position = 0; + // TODO: Free it first + env->me_block_size_cache = NULL; + } txn->mt_txnid = ti->mti_txnid; meta = env->me_metas[txn->mt_txnid & 1]; } else { diff --git a/dependencies/lmdb/libraries/liblmdb/midl.c b/dependencies/lmdb/libraries/liblmdb/midl.c index e0cc80f3e..5a85dc976 100644 --- a/dependencies/lmdb/libraries/liblmdb/midl.c +++ b/dependencies/lmdb/libraries/liblmdb/midl.c @@ -106,22 +106,54 @@ int mdb_midl_insert( MDB_IDL* ids_ref, MDB_ID id ) } else { if (x > ids[0]) return -3; // at the end ssize_t next_id = ids[x]; - if (next_id < 0) next_id = ids[x + 1]; - if (id - 1 == next_id && next_id > 0) { - // connected to next entry - ids[x]--; // increment negatively, as we have just expanded a block - // ids[x + 1] = id; // no need to adjust id, so since we are adding to the end of the block - return 0; + unsigned next_count = 1; + if (next_id < 0) { + next_count = -next_id; + next_id = ids[x + 1]; } unsigned before = x; // this will end up pointing to an entry or zero right before a block of empty space while (!ids[--before] && before > 0) { // move past empty entries } + if (id - next_count == next_id && next_id > 0) { + // connected to next entry + ssize_t count = next_count + 1; + // ids[x + 1] = id; // no need to adjust id, so since we are adding to the end of the block + + if (before > 0) { + MDB_ID previous_id = before > 0 ? ids[before] : 0; + int previous_count = before > 1 ? -ids[before - 1] : 0; + if (previous_count < 1) previous_count = 1; + if (previous_id - 1 == id) { + // the block we just added to can now be connected to previous entry + count += previous_count; + if (previous_count > 1) { + ids[before - 1] = 0; // remove previous length + } + ids[before] = 0; // remove previous id + if (next_count == 1) { + // we can safely add the new count to the empty space + ids[x - 1] = -count; // update the count + return 0; + } + } + } + if (next_count > 1) { + ids[x] = -count; // update the count + } else if (ids[x - 1] == 0) { + ids[x - 1] = -2; + } else { + id = -2; // switching a single entry to a block size of 2 + x--; + goto insert_id; + } + return 0; + } if (before > 0) { - MDB_ID next_id = before > 0 ? ids[before] : 0; + MDB_ID previous_id = before > 0 ? ids[before] : 0; int count = before > 1 ? -ids[before - 1] : 0; if (count < 1) count = 1; - if (next_id - 1 == id) { + if (previous_id - 1 == id) { // connected to previous entry ids[before]--; // adjust the starting block to include this if (count > 1) { @@ -213,6 +245,7 @@ int mdb_midl_need( MDB_IDL *idp, unsigned num ) MDB_IDL new_ids; if (!(new_ids = calloc(num, sizeof(MDB_ID)))) return ENOMEM; + fprintf(stderr, "Created new id list of size %u\n", num); *new_ids++ = num - 2; *new_ids = num - 2; unsigned j = 1; @@ -226,6 +259,7 @@ int mdb_midl_need( MDB_IDL *idp, unsigned num ) new_ids[j++] = entry; if (entry < 0) new_ids[j++] = ids[++i]; // this was a block with a length } + mdb_midl_free(ids); // now shrink (or grow) back to appropriate size num = (j + (j >> 3) + 22) & -16; if (num > new_ids[0]) num = new_ids[0]; @@ -237,6 +271,28 @@ int mdb_midl_need( MDB_IDL *idp, unsigned num ) return 0; } +int mdb_midl_print( FILE *fp, MDB_IDL ids ) +{ + if (ids == NULL) { + fprintf(fp, "freelist: NULL\n"); + return 0; + } + unsigned i; + fprintf(fp, "freelist: %u: ", ids[0]); + for (i=1; i<=ids[0]; i++) { + ssize_t entry = ids[i]; + if (entry < 0) { + fprintf(fp, "%li-%li ", ids[i+1], ids[i+1] - entry - 1); + i++; + } else if (ids[i] == 0) { + fprintf(fp, "_"); + } else { + fprintf(fp, "%lu ", (unsigned long)ids[i]); + } + } + fprintf(fp, "\n"); + return 0; +} int mdb_midl_append( MDB_IDL *idp, MDB_ID id ) { MDB_IDL ids = *idp; diff --git a/dependencies/lmdb/libraries/liblmdb/midl.h b/dependencies/lmdb/libraries/liblmdb/midl.h index bf3df89f3..3823dd499 100644 --- a/dependencies/lmdb/libraries/liblmdb/midl.h +++ b/dependencies/lmdb/libraries/liblmdb/midl.h @@ -28,6 +28,8 @@ #define _MDB_MIDL_H_ #include "lmdb.h" +#include + #ifdef __cplusplus extern "C" { @@ -109,6 +111,7 @@ void mdb_midl_shrink(MDB_IDL *idp); */ int mdb_midl_need(MDB_IDL *idp, unsigned num); +int mdb_midl_print( FILE *fp, MDB_IDL ids ); /** Insert an ID into an IDL. * @param[in,out] idp Address of the IDL to append to. * @param[in] id The ID to append.