mdbx: refine pgno-lists.

Change-Id: Id38e4aff508437210d4c0e63962067dfe518eb31
This commit is contained in:
Leo Yuriev 2017-07-26 09:31:22 +03:00
parent 592c064873
commit 552b759878
3 changed files with 312 additions and 295 deletions

View File

@ -434,11 +434,11 @@ typedef struct MDBX_lockinfo {
/*----------------------------------------------------------------------------*/
/* Two kind lists of pages (aka IDL) */
/* An IDL is an ID List, a sorted array of IDs. The first
/* An PNL is an Page Number List, a sorted array of IDs. The first
* element of the array is a counter for how many actual
* IDs are in the list. In the libmdbx IDLs are sorted in
* IDs are in the list. In the libmdbx PNLs are sorted in
* descending order. */
typedef pgno_t *MDBX_IDL;
typedef pgno_t *MDBX_PNL;
/* List of txnid, only for MDBX_env.mt_lifo_reclaimed */
typedef txnid_t *MDBX_TXL;
@ -455,23 +455,23 @@ typedef struct MDBX_ID2 {
* unused. The array is sorted in ascending order by mid. */
typedef MDBX_ID2 *MDBX_ID2L;
/* IDL sizes - likely should be even bigger
/* PNL sizes - likely should be even bigger
* limiting factors: sizeof(pgno_t), thread stack size */
#define MDBX_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
#define MDBX_IDL_DB_SIZE (1 << MDBX_IDL_LOGN)
#define MDBX_IDL_UM_SIZE (1 << (MDBX_IDL_LOGN + 1))
#define MDBX_PNL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */
#define MDBX_PNL_DB_SIZE (1 << MDBX_PNL_LOGN)
#define MDBX_PNL_UM_SIZE (1 << (MDBX_PNL_LOGN + 1))
#define MDBX_IDL_DB_MAX (MDBX_IDL_DB_SIZE - 1)
#define MDBX_IDL_UM_MAX (MDBX_IDL_UM_SIZE - 1)
#define MDBX_PNL_DB_MAX (MDBX_PNL_DB_SIZE - 1)
#define MDBX_PNL_UM_MAX (MDBX_PNL_UM_SIZE - 1)
#define MDBX_IDL_SIZEOF(ids) (((ids)[0] + 1) * sizeof(pgno_t))
#define MDBX_IDL_IS_ZERO(ids) ((ids)[0] == 0)
#define MDBX_IDL_CPY(dst, src) (memcpy(dst, src, MDBX_IDL_SIZEOF(src)))
#define MDBX_IDL_FIRST(ids) ((ids)[1])
#define MDBX_IDL_LAST(ids) ((ids)[(ids)[0]])
#define MDBX_PNL_SIZEOF(pl) (((pl)[0] + 1) * sizeof(pgno_t))
#define MDBX_PNL_IS_ZERO(pl) ((pl)[0] == 0)
#define MDBX_PNL_CPY(dst, src) (memcpy(dst, src, MDBX_PNL_SIZEOF(src)))
#define MDBX_PNL_FIRST(pl) ((pl)[1])
#define MDBX_PNL_LAST(pl) ((pl)[(pl)[0]])
/* Current max length of an mdbx_midl_alloc()ed IDL */
#define MDBX_IDL_ALLOCLEN(ids) ((ids)[-1])
/* Current max length of an mdbx_pnl_alloc()ed PNL */
#define MDBX_PNL_ALLOCLEN(pl) ((pl)[-1])
/*----------------------------------------------------------------------------*/
/* Internal structures */
@ -503,7 +503,7 @@ struct MDBX_txn {
/* The list of reclaimed txns from freeDB */
MDBX_TXL mt_lifo_reclaimed;
/* The list of pages that became unused during this transaction. */
MDBX_IDL mt_befree_pages;
MDBX_PNL mt_befree_pages;
/* The list of loose pages that became unused and may be reused
* in this transaction, linked through NEXT_LOOSE_PAGE(page). */
MDBX_page *mt_loose_pages;
@ -512,7 +512,7 @@ struct MDBX_txn {
/* The sorted list of dirty pages we temporarily wrote to disk
* because the dirty list was full. page numbers in here are
* shifted left by 1, deleted slots have the LSB set. */
MDBX_IDL mt_spill_pages;
MDBX_PNL mt_spill_pages;
union {
/* For write txns: Modified pages. Sorted when not MDBX_WRITEMAP. */
MDBX_ID2L mt_rw_dirtylist;
@ -699,9 +699,9 @@ struct MDBX_env {
#define me_last_reclaimed me_pgstate.mf_last_reclaimed
#define me_reclaimed_pglist me_pgstate.mf_reclaimed_pglist
MDBX_page *me_dpages; /* list of malloc'd blocks for re-use */
/* IDL of pages that became unused in a write txn */
MDBX_IDL me_free_pgs;
/* ID2L of pages written during a write txn. Length MDBX_IDL_UM_SIZE. */
/* PNL of pages that became unused in a write txn */
MDBX_PNL me_free_pgs;
/* ID2L of pages written during a write txn. Length MDBX_PNL_UM_SIZE. */
MDBX_ID2L me_dirtylist;
/* Max number of freelist items that can fit in a single overflow page */
unsigned me_maxfree_1pg;

View File

@ -156,16 +156,16 @@ __cold void mdbx_rthc_remove(mdbx_thread_key_t key) {
/*----------------------------------------------------------------------------*/
/* Allocate an IDL.
* Allocates memory for an IDL of the given size.
* Returns IDL on success, NULL on failure. */
static MDBX_IDL mdbx_midl_alloc(size_t size) {
MDBX_IDL ids = malloc((size + 2) * sizeof(pgno_t));
if (likely(ids)) {
*ids++ = (pgno_t)size;
*ids = 0;
/* Allocate an PNL.
* Allocates memory for an PNL of the given size.
* Returns PNL on success, NULL on failure. */
static MDBX_PNL mdbx_pnl_alloc(size_t size) {
MDBX_PNL pl = malloc((size + 2) * sizeof(pgno_t));
if (likely(pl)) {
*pl++ = (pgno_t)size;
*pl = 0;
}
return ids;
return pl;
}
static MDBX_TXL mdbx_txl_alloc(void) {
@ -181,11 +181,11 @@ static MDBX_TXL mdbx_txl_alloc(void) {
return ptr;
}
/* Free an IDL.
* [in] ids The IDL to free. */
static void mdbx_midl_free(MDBX_IDL ids) {
if (likely(ids))
free(ids - 1);
/* Free an PNL.
* [in] pl The PNL to free. */
static void mdbx_pnl_free(MDBX_PNL pl) {
if (likely(pl))
free(pl - 1);
}
static void mdbx_txl_free(MDBX_TXL list) {
@ -193,29 +193,122 @@ static void mdbx_txl_free(MDBX_TXL list) {
free(list - 1);
}
/* Append ID to IDL. The IDL must be big enough. */
static __inline void mdbx_midl_xappend(MDBX_IDL idl, pgno_t id) {
assert(idl[0] + (size_t)1 < MDBX_IDL_ALLOCLEN(idl));
idl[idl[0] += 1] = id;
/* Append ID to PNL. The PNL must be big enough. */
static __inline void mdbx_pnl_xappend(MDBX_PNL pl, pgno_t id) {
assert(pl[0] + (size_t)1 < MDBX_PNL_ALLOCLEN(pl));
pl[pl[0] += 1] = id;
}
/* Search for an ID in an IDL.
* [in] ids The IDL to search.
static bool mdbx_pnl_check(MDBX_PNL pl) {
if (pl) {
for (const pgno_t *ptr = pl + pl[0]; --ptr > pl;) {
assert(ptr[0] > ptr[1]);
if (unlikely(ptr[0] <= ptr[1]))
return false;
}
}
return true;
}
/* Sort an PNL.
* [in,out] pnl The PNL to sort. */
static void __hot mdbx_pnl_sort(MDBX_PNL pnl) {
/* Max possible depth of int-indexed tree * 2 items/level */
int istack[sizeof(int) * CHAR_BIT * 2];
int i, j, k, l, ir, jstack;
pgno_t a;
/* Quicksort + Insertion sort for small arrays */
#define PNL_SMALL 8
#define PNL_SWAP(a, b) \
do { \
pgno_t tmp_pgno = (a); \
(a) = (b); \
(b) = tmp_pgno; \
} while (0)
ir = (int)pnl[0];
l = 1;
jstack = 0;
while (1) {
if (ir - l < PNL_SMALL) { /* Insertion sort */
for (j = l + 1; j <= ir; j++) {
a = pnl[j];
for (i = j - 1; i >= 1; i--) {
if (pnl[i] >= a)
break;
pnl[i + 1] = pnl[i];
}
pnl[i + 1] = a;
}
if (jstack == 0)
break;
ir = istack[jstack--];
l = istack[jstack--];
} else {
k = (l + ir) >> 1; /* Choose median of left, center, right */
PNL_SWAP(pnl[k], pnl[l + 1]);
if (pnl[l] < pnl[ir])
PNL_SWAP(pnl[l], pnl[ir]);
if (pnl[l + 1] < pnl[ir])
PNL_SWAP(pnl[l + 1], pnl[ir]);
if (pnl[l] < pnl[l + 1])
PNL_SWAP(pnl[l], pnl[l + 1]);
i = l + 1;
j = ir;
a = pnl[l + 1];
while (1) {
do
i++;
while (pnl[i] > a);
do
j--;
while (pnl[j] < a);
if (j < i)
break;
PNL_SWAP(pnl[i], pnl[j]);
}
pnl[l + 1] = pnl[j];
pnl[j] = a;
jstack += 2;
if (ir - i + 1 >= j - l) {
istack[jstack] = ir;
istack[jstack - 1] = i;
ir = j - 1;
} else {
istack[jstack] = j - 1;
istack[jstack - 1] = l;
l = i;
}
}
}
#undef PNL_SMALL
#undef PNL_SWAP
assert(mdbx_pnl_check(pnl));
}
/* Search for an ID in an PNL.
* [in] pl The PNL to search.
* [in] id The ID to search for.
* Returns The index of the first ID greater than or equal to id. */
static unsigned __hot mdbx_midl_search(MDBX_IDL ids, pgno_t id) {
/* binary search of id in ids
static unsigned __hot mdbx_pnl_search(MDBX_PNL pnl, pgno_t id) {
assert(mdbx_pnl_check(pnl));
/* binary search of id in pl
* if found, returns position of id
* if not found, returns first position greater than id */
unsigned base = 0;
unsigned cursor = 1;
int val = 0;
unsigned n = ids[0];
unsigned n = pnl[0];
while (n > 0) {
unsigned pivot = n >> 1;
cursor = base + pivot + 1;
val = mdbx_cmp2int(ids[cursor], id);
val = mdbx_cmp2int(pnl[cursor], id);
if (val < 0) {
n = pivot;
@ -233,32 +326,32 @@ static unsigned __hot mdbx_midl_search(MDBX_IDL ids, pgno_t id) {
return cursor;
}
/* Shrink an IDL.
* Return the IDL to the default size if it has grown larger.
* [in,out] idp Address of the IDL to shrink. */
static void mdbx_midl_shrink(MDBX_IDL *idp) {
MDBX_IDL ids = *idp - 1;
if (unlikely(*ids > MDBX_IDL_UM_MAX)) {
/* shrink to MDBX_IDL_UM_MAX */
ids = realloc(ids, (MDBX_IDL_UM_MAX + 2) * sizeof(pgno_t));
if (likely(ids)) {
*ids++ = MDBX_IDL_UM_MAX;
*idp = ids;
/* Shrink an PNL.
* Return the PNL to the default size if it has grown larger.
* [in,out] ppl Address of the PNL to shrink. */
static void mdbx_pnl_shrink(MDBX_PNL *ppl) {
MDBX_PNL pl = *ppl - 1;
if (unlikely(*pl > MDBX_PNL_UM_MAX)) {
/* shrink to MDBX_PNL_UM_MAX */
pl = realloc(pl, (MDBX_PNL_UM_MAX + 2) * sizeof(pgno_t));
if (likely(pl)) {
*pl++ = MDBX_PNL_UM_MAX;
*ppl = pl;
}
}
}
/* Grow an IDL.
* Return the IDL to the size growed by given number.
* [in,out] idp Address of the IDL to grow. */
static int mdbx_midl_grow(MDBX_IDL *idp, size_t num) {
MDBX_IDL idn = *idp - 1;
/* Grow an PNL.
* Return the PNL to the size growed by given number.
* [in,out] ppl Address of the PNL to grow. */
static int mdbx_pnl_grow(MDBX_PNL *ppl, size_t num) {
MDBX_PNL idn = *ppl - 1;
/* grow it */
idn = realloc(idn, (*idn + num + 2) * sizeof(pgno_t));
if (unlikely(!idn))
return MDBX_ENOMEM;
*idn++ += (pgno_t)num;
*idp = idn;
*ppl = idn;
return 0;
}
@ -273,38 +366,38 @@ static int mdbx_txl_grow(MDBX_TXL *ptr, size_t num) {
return 0;
}
/* Make room for num additional elements in an IDL.
* [in,out] idp Address of the IDL.
/* Make room for num additional elements in an PNL.
* [in,out] ppl Address of the PNL.
* [in] num Number of elements to make room for.
* Returns 0 on success, MDBX_ENOMEM on failure. */
static int mdbx_midl_need(MDBX_IDL *idp, size_t num) {
MDBX_IDL ids = *idp;
num += ids[0];
if (unlikely(num > ids[-1])) {
static int mdbx_pnl_need(MDBX_PNL *ppl, size_t num) {
MDBX_PNL pl = *ppl;
num += pl[0];
if (unlikely(num > pl[-1])) {
num = (num + num / 4 + (256 + 2)) & -256;
ids = realloc(ids - 1, num * sizeof(pgno_t));
if (unlikely(!ids))
pl = realloc(pl - 1, num * sizeof(pgno_t));
if (unlikely(!pl))
return MDBX_ENOMEM;
*ids++ = (pgno_t)num - 2;
*idp = ids;
*pl++ = (pgno_t)num - 2;
*ppl = pl;
}
return 0;
}
/* Append an ID onto an IDL.
* [in,out] idp Address of the IDL to append to.
/* Append an ID onto an PNL.
* [in,out] ppl Address of the PNL to append to.
* [in] id The ID to append.
* Returns 0 on success, MDBX_ENOMEM if the IDL is too large. */
static int mdbx_midl_append(MDBX_IDL *idp, pgno_t id) {
MDBX_IDL ids = *idp;
* Returns 0 on success, MDBX_ENOMEM if the PNL is too large. */
static int mdbx_pnl_append(MDBX_PNL *ppl, pgno_t id) {
MDBX_PNL pl = *ppl;
/* Too big? */
if (unlikely(ids[0] >= ids[-1])) {
if (mdbx_midl_grow(idp, MDBX_IDL_UM_MAX))
if (unlikely(pl[0] >= pl[-1])) {
if (mdbx_pnl_grow(ppl, MDBX_PNL_UM_MAX))
return MDBX_ENOMEM;
ids = *idp;
pl = *ppl;
}
ids[0]++;
ids[ids[0]] = id;
pl[0]++;
pl[pl[0]] = id;
return 0;
}
@ -321,20 +414,20 @@ static int mdbx_txl_append(MDBX_TXL *ptr, txnid_t id) {
return 0;
}
/* Append an IDL onto an IDL.
* [in,out] idp Address of the IDL to append to.
* [in] app The IDL to append.
* Returns 0 on success, MDBX_ENOMEM if the IDL is too large. */
static int mdbx_midl_append_list(MDBX_IDL *idp, MDBX_IDL app) {
MDBX_IDL ids = *idp;
/* Append an PNL onto an PNL.
* [in,out] ppl Address of the PNL to append to.
* [in] app The PNL to append.
* Returns 0 on success, MDBX_ENOMEM if the PNL is too large. */
static int mdbx_pnl_append_list(MDBX_PNL *ppl, MDBX_PNL app) {
MDBX_PNL pnl = *ppl;
/* Too big? */
if (unlikely(ids[0] + app[0] >= ids[-1])) {
if (mdbx_midl_grow(idp, app[0]))
if (unlikely(pnl[0] + app[0] >= pnl[-1])) {
if (mdbx_pnl_grow(ppl, app[0]))
return MDBX_ENOMEM;
ids = *idp;
pnl = *ppl;
}
memcpy(&ids[ids[0] + 1], &app[1], app[0] * sizeof(pgno_t));
ids[0] += app[0];
memcpy(&pnl[pnl[0] + 1], &app[1], app[0] * sizeof(pgno_t));
pnl[0] += app[0];
return 0;
}
@ -351,139 +444,63 @@ static int mdbx_txl_append_list(MDBX_TXL *ptr, MDBX_TXL append) {
return 0;
}
/* Append an ID range onto an IDL.
* [in,out] idp Address of the IDL to append to.
/* Append an ID range onto an PNL.
* [in,out] ppl Address of the PNL to append to.
* [in] id The lowest ID to append.
* [in] n Number of IDs to append.
* Returns 0 on success, MDBX_ENOMEM if the IDL is too large. */
static int mdbx_midl_append_range(MDBX_IDL *idp, pgno_t id, size_t n) {
pgno_t *ids = *idp, len = ids[0];
* Returns 0 on success, MDBX_ENOMEM if the PNL is too large. */
static int mdbx_pnl_append_range(MDBX_PNL *ppl, pgno_t id, size_t n) {
pgno_t *pnl = *ppl, len = pnl[0];
/* Too big? */
if (unlikely(len + n > ids[-1])) {
if (mdbx_midl_grow(idp, n | MDBX_IDL_UM_MAX))
if (unlikely(len + n > pnl[-1])) {
if (mdbx_pnl_grow(ppl, n | MDBX_PNL_UM_MAX))
return MDBX_ENOMEM;
ids = *idp;
pnl = *ppl;
}
ids[0] = len + (pgno_t)n;
ids += len;
pnl[0] = len + (pgno_t)n;
pnl += len;
while (n)
ids[n--] = id++;
pnl[n--] = id++;
return 0;
}
/* Merge an IDL onto an IDL. The destination IDL must be big enough.
* [in] idl The IDL to merge into.
* [in] merge The IDL to merge. */
static void __hot mdbx_midl_xmerge(MDBX_IDL idl, MDBX_IDL merge) {
pgno_t old_id, merge_id, i = merge[0], j = idl[0], k = i + j, total = k;
idl[0] = ~(pgno_t)0; /* delimiter for idl scan below */
old_id = idl[j];
/* Merge an PNL onto an PNL. The destination PNL must be big enough.
* [in] pl The PNL to merge into.
* [in] merge The PNL to merge. */
static void __hot mdbx_pnl_xmerge(MDBX_PNL pnl, MDBX_PNL merge) {
assert(mdbx_pnl_check(pnl));
assert(mdbx_pnl_check(merge));
pgno_t old_id, merge_id, i = merge[0], j = pnl[0], k = i + j, total = k;
pnl[0] = ~(pgno_t)0; /* delimiter for pl scan below */
old_id = pnl[j];
while (i) {
merge_id = merge[i--];
for (; old_id < merge_id; old_id = idl[--j])
idl[k--] = old_id;
idl[k--] = merge_id;
for (; old_id < merge_id; old_id = pnl[--j])
pnl[k--] = old_id;
pnl[k--] = merge_id;
}
idl[0] = total;
}
/* Sort an IDL.
* [in,out] ids The IDL to sort. */
static void __hot mdbx_midl_sort(MDBX_IDL ids) {
/* Max possible depth of int-indexed tree * 2 items/level */
int istack[sizeof(int) * CHAR_BIT * 2];
int i, j, k, l, ir, jstack;
pgno_t a;
/* Quicksort + Insertion sort for small arrays */
#define MIDL_SMALL 8
#define MIDL_SWAP(a, b) \
do { \
pgno_t tmp_pgno = (a); \
(a) = (b); \
(b) = tmp_pgno; \
} while (0)
ir = (int)ids[0];
l = 1;
jstack = 0;
for (;;) {
if (ir - l < MIDL_SMALL) { /* Insertion sort */
for (j = l + 1; j <= ir; j++) {
a = ids[j];
for (i = j - 1; i >= 1; i--) {
if (ids[i] >= a)
break;
ids[i + 1] = ids[i];
}
ids[i + 1] = a;
}
if (jstack == 0)
break;
ir = istack[jstack--];
l = istack[jstack--];
} else {
k = (l + ir) >> 1; /* Choose median of left, center, right */
MIDL_SWAP(ids[k], ids[l + 1]);
if (ids[l] < ids[ir])
MIDL_SWAP(ids[l], ids[ir]);
if (ids[l + 1] < ids[ir])
MIDL_SWAP(ids[l + 1], ids[ir]);
if (ids[l] < ids[l + 1])
MIDL_SWAP(ids[l], ids[l + 1]);
i = l + 1;
j = ir;
a = ids[l + 1];
for (;;) {
do
i++;
while (ids[i] > a);
do
j--;
while (ids[j] < a);
if (j < i)
break;
MIDL_SWAP(ids[i], ids[j]);
}
ids[l + 1] = ids[j];
ids[j] = a;
jstack += 2;
if (ir - i + 1 >= j - l) {
istack[jstack] = ir;
istack[jstack - 1] = i;
ir = j - 1;
} else {
istack[jstack] = j - 1;
istack[jstack - 1] = l;
l = i;
}
}
}
#undef MIDL_SMALL
#undef MIDL_SWAP
pnl[0] = total;
assert(mdbx_pnl_check(pnl));
}
/* Search for an ID in an ID2L.
* [in] ids The ID2L to search.
* [in] pnl The ID2L to search.
* [in] id The ID to search for.
* Returns The index of the first ID2 whose mid member is greater than
* or equal to id. */
static unsigned __hot mdbx_mid2l_search(MDBX_ID2L ids, pgno_t id) {
/* binary search of id in ids
static unsigned __hot mdbx_mid2l_search(MDBX_ID2L pnl, pgno_t id) {
/* binary search of id in pnl
* if found, returns position of id
* if not found, returns first position greater than id */
unsigned base = 0;
unsigned cursor = 1;
int val = 0;
unsigned n = (unsigned)ids[0].mid;
unsigned n = (unsigned)pnl[0].mid;
while (n > 0) {
unsigned pivot = n >> 1;
cursor = base + pivot + 1;
val = mdbx_cmp2int(id, ids[cursor].mid);
val = mdbx_cmp2int(id, pnl[cursor].mid);
if (val < 0) {
n = pivot;
@ -502,39 +519,39 @@ static unsigned __hot mdbx_mid2l_search(MDBX_ID2L ids, pgno_t id) {
}
/* Insert an ID2 into a ID2L.
* [in,out] ids The ID2L to insert into.
* [in,out] pnl The ID2L to insert into.
* [in] id The ID2 to insert.
* Returns 0 on success, -1 if the ID was already present in the ID2L. */
static int mdbx_mid2l_insert(MDBX_ID2L ids, MDBX_ID2 *id) {
unsigned x = mdbx_mid2l_search(ids, id->mid);
static int mdbx_mid2l_insert(MDBX_ID2L pnl, MDBX_ID2 *id) {
unsigned x = mdbx_mid2l_search(pnl, id->mid);
if (unlikely(x < 1))
return /* internal error */ -2;
if (x <= ids[0].mid && ids[x].mid == id->mid)
if (x <= pnl[0].mid && pnl[x].mid == id->mid)
return /* duplicate */ -1;
if (unlikely(ids[0].mid >= MDBX_IDL_UM_MAX))
if (unlikely(pnl[0].mid >= MDBX_PNL_UM_MAX))
return /* too big */ -2;
/* insert id */
ids[0].mid++;
for (unsigned i = (unsigned)ids[0].mid; i > x; i--)
ids[i] = ids[i - 1];
ids[x] = *id;
pnl[0].mid++;
for (unsigned i = (unsigned)pnl[0].mid; i > x; i--)
pnl[i] = pnl[i - 1];
pnl[x] = *id;
return 0;
}
/* Append an ID2 into a ID2L.
* [in,out] ids The ID2L to append into.
* [in,out] pnl The ID2L to append into.
* [in] id The ID2 to append.
* Returns 0 on success, -2 if the ID2L is too big. */
static int mdbx_mid2l_append(MDBX_ID2L ids, MDBX_ID2 *id) {
static int mdbx_mid2l_append(MDBX_ID2L pnl, MDBX_ID2 *id) {
/* Too big? */
if (unlikely(ids[0].mid >= MDBX_IDL_UM_MAX))
if (unlikely(pnl[0].mid >= MDBX_PNL_UM_MAX))
return -2;
ids[0].mid++;
ids[ids[0].mid] = *id;
pnl[0].mid++;
pnl[pnl[0].mid] = *id;
return 0;
}
@ -1128,7 +1145,7 @@ static int mdbx_page_loose(MDBX_cursor *mc, MDBX_page *mp) {
txn->mt_loose_count++;
mp->mp_flags |= P_LOOSE;
} else {
int rc = mdbx_midl_append(&txn->mt_befree_pages, pgno);
int rc = mdbx_pnl_append(&txn->mt_befree_pages, pgno);
if (unlikely(rc))
return rc;
}
@ -1260,12 +1277,12 @@ static int mdbx_page_spill(MDBX_cursor *m0, MDBX_val *key, MDBX_val *data) {
return MDBX_SUCCESS;
if (!txn->mt_spill_pages) {
txn->mt_spill_pages = mdbx_midl_alloc(MDBX_IDL_UM_MAX);
txn->mt_spill_pages = mdbx_pnl_alloc(MDBX_PNL_UM_MAX);
if (unlikely(!txn->mt_spill_pages))
return MDBX_ENOMEM;
} else {
/* purge deleted slots */
MDBX_IDL sl = txn->mt_spill_pages;
MDBX_PNL sl = txn->mt_spill_pages;
pgno_t num = sl[0], j = 0;
for (i = 1; i <= num; i++) {
if (!(sl[i] & 1))
@ -1285,8 +1302,8 @@ static int mdbx_page_spill(MDBX_cursor *m0, MDBX_val *key, MDBX_val *data) {
* of those pages will need to be used again. So now we spill only 1/8th
* of the dirty pages. Testing revealed this to be a good tradeoff,
* better than 1/2, 1/4, or 1/10. */
if (need < MDBX_IDL_UM_MAX / 8)
need = MDBX_IDL_UM_MAX / 8;
if (need < MDBX_PNL_UM_MAX / 8)
need = MDBX_PNL_UM_MAX / 8;
/* Save the page IDs of all the pages we're flushing */
/* flush from the tail forward, this saves a lot of shifting later on. */
@ -1301,7 +1318,7 @@ static int mdbx_page_spill(MDBX_cursor *m0, MDBX_val *key, MDBX_val *data) {
MDBX_txn *tx2;
for (tx2 = txn->mt_parent; tx2; tx2 = tx2->mt_parent) {
if (tx2->mt_spill_pages) {
unsigned j = mdbx_midl_search(tx2->mt_spill_pages, pn);
unsigned j = mdbx_pnl_search(tx2->mt_spill_pages, pn);
if (j <= tx2->mt_spill_pages[0] && tx2->mt_spill_pages[j] == pn) {
dp->mp_flags |= P_KEEP;
break;
@ -1311,12 +1328,12 @@ static int mdbx_page_spill(MDBX_cursor *m0, MDBX_val *key, MDBX_val *data) {
if (tx2)
continue;
}
rc = mdbx_midl_append(&txn->mt_spill_pages, pn);
rc = mdbx_pnl_append(&txn->mt_spill_pages, pn);
if (unlikely(rc != MDBX_SUCCESS))
goto bailout;
need--;
}
mdbx_midl_sort(txn->mt_spill_pages);
mdbx_pnl_sort(txn->mt_spill_pages);
/* Flush the spilled part of dirty list */
rc = mdbx_page_flush(txn, i);
@ -1781,20 +1798,21 @@ static int mdbx_page_alloc(MDBX_cursor *mc, unsigned num, MDBX_page **mp,
}
}
/* Append IDL from FreeDB record to me_reclaimed_pglist */
pgno_t *re_idl = (pgno_t *)data.iov_base;
mdbx_tassert(txn, re_idl[0] == 0 ||
data.iov_len == (re_idl[0] + 1) * sizeof(pgno_t));
repg_pos = re_idl[0];
/* Append PNL from FreeDB record to me_reclaimed_pglist */
pgno_t *re_pnl = (pgno_t *)data.iov_base;
mdbx_tassert(txn, re_pnl[0] == 0 ||
data.iov_len == (re_pnl[0] + 1) * sizeof(pgno_t));
mdbx_tassert(txn, mdbx_pnl_check(re_pnl));
repg_pos = re_pnl[0];
if (!repg_list) {
if (unlikely(!(env->me_reclaimed_pglist = repg_list =
mdbx_midl_alloc(repg_pos)))) {
mdbx_pnl_alloc(repg_pos)))) {
rc = MDBX_ENOMEM;
goto fail;
}
} else {
if (unlikely((rc = mdbx_midl_need(&env->me_reclaimed_pglist,
repg_pos)) != 0))
if (unlikely(
(rc = mdbx_pnl_need(&env->me_reclaimed_pglist, repg_pos)) != 0))
goto fail;
repg_list = env->me_reclaimed_pglist;
}
@ -1807,17 +1825,17 @@ static int mdbx_page_alloc(MDBX_cursor *mc, unsigned num, MDBX_page **mp,
env->me_last_reclaimed = last;
if (mdbx_debug_enabled(MDBX_DBG_EXTRA)) {
mdbx_debug_extra("IDL read txn %" PRIaTXN " root %" PRIaPGNO
" num %u, IDL",
mdbx_debug_extra("PNL read txn %" PRIaTXN " root %" PRIaPGNO
" num %u, PNL",
last, txn->mt_dbs[FREE_DBI].md_root, repg_pos);
unsigned i;
for (i = repg_pos; i; i--)
mdbx_debug_extra_print(" %" PRIaPGNO "", re_idl[i]);
mdbx_debug_extra_print(" %" PRIaPGNO "", re_pnl[i]);
mdbx_debug_extra_print("\n");
}
/* Merge in descending sorted order */
mdbx_midl_xmerge(repg_list, re_idl);
mdbx_pnl_xmerge(repg_list, re_pnl);
repg_len = repg_list[0];
if (unlikely((flags & MDBX_ALLOC_CACHE) == 0)) {
@ -1834,7 +1852,7 @@ static int mdbx_page_alloc(MDBX_cursor *mc, unsigned num, MDBX_page **mp,
}
/* Don't try to coalesce too much. */
if (repg_len > MDBX_IDL_UM_SIZE / 2)
if (repg_len > MDBX_PNL_UM_SIZE / 2)
break;
if (flags & MDBX_COALESCE) {
if (repg_len /* current size */ >= env->me_maxfree_1pg / 2 ||
@ -2016,7 +2034,7 @@ static int mdbx_page_unspill(MDBX_txn *txn, MDBX_page *mp, MDBX_page **ret) {
for (tx2 = txn; tx2; tx2 = tx2->mt_parent) {
if (!tx2->mt_spill_pages)
continue;
x = mdbx_midl_search(tx2->mt_spill_pages, pn);
x = mdbx_pnl_search(tx2->mt_spill_pages, pn);
if (x <= tx2->mt_spill_pages[0] && tx2->mt_spill_pages[x] == pn) {
MDBX_page *np;
int num;
@ -2079,14 +2097,14 @@ static int mdbx_page_touch(MDBX_cursor *mc) {
goto done;
}
if (unlikely((rc = mdbx_midl_need(&txn->mt_befree_pages, 1)) ||
if (unlikely((rc = mdbx_pnl_need(&txn->mt_befree_pages, 1)) ||
(rc = mdbx_page_alloc(mc, 1, &np, MDBX_ALLOC_ALL))))
goto fail;
pgno = np->mp_pgno;
mdbx_debug("touched db %d page %" PRIaPGNO " -> %" PRIaPGNO, DDBI(mc),
mp->mp_pgno, pgno);
mdbx_cassert(mc, mp->mp_pgno != pgno);
mdbx_midl_xappend(txn->mt_befree_pages, mp->mp_pgno);
mdbx_pnl_xappend(txn->mt_befree_pages, mp->mp_pgno);
/* Update the parent page, if any, to point to the new page */
if (mc->mc_top) {
MDBX_page *parent = mc->mc_pg[mc->mc_top - 1];
@ -2115,7 +2133,7 @@ static int mdbx_page_touch(MDBX_cursor *mc) {
}
mdbx_debug("clone db %d page %" PRIaPGNO, DDBI(mc), mp->mp_pgno);
mdbx_cassert(mc, dl[0].mid < MDBX_IDL_UM_MAX);
mdbx_cassert(mc, dl[0].mid < MDBX_PNL_UM_MAX);
/* No - copy it */
np = mdbx_page_malloc(txn, 1);
if (unlikely(!np))
@ -2477,7 +2495,7 @@ static int mdbx_txn_renew0(MDBX_txn *txn, unsigned flags) {
txn->mt_child = NULL;
txn->mt_loose_pages = NULL;
txn->mt_loose_count = 0;
txn->mt_dirtyroom = MDBX_IDL_UM_MAX;
txn->mt_dirtyroom = MDBX_PNL_UM_MAX;
txn->mt_rw_dirtylist = env->me_dirtylist;
txn->mt_rw_dirtylist[0].mid = 0;
txn->mt_befree_pages = env->me_free_pgs;
@ -2620,9 +2638,9 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
unsigned i;
txn->mt_cursors = (MDBX_cursor **)(txn->mt_dbs + env->me_maxdbs);
txn->mt_dbiseqs = parent->mt_dbiseqs;
txn->mt_rw_dirtylist = malloc(sizeof(MDBX_ID2) * MDBX_IDL_UM_SIZE);
txn->mt_rw_dirtylist = malloc(sizeof(MDBX_ID2) * MDBX_PNL_UM_SIZE);
if (!txn->mt_rw_dirtylist ||
!(txn->mt_befree_pages = mdbx_midl_alloc(MDBX_IDL_UM_MAX))) {
!(txn->mt_befree_pages = mdbx_pnl_alloc(MDBX_PNL_UM_MAX))) {
free(txn->mt_rw_dirtylist);
free(txn);
return MDBX_ENOMEM;
@ -2646,8 +2664,8 @@ int mdbx_txn_begin(MDBX_env *env, MDBX_txn *parent, unsigned flags,
ntxn->mnt_pgstate =
env->me_pgstate; /* save parent me_reclaimed_pglist & co */
if (env->me_reclaimed_pglist) {
size = MDBX_IDL_SIZEOF(env->me_reclaimed_pglist);
env->me_reclaimed_pglist = mdbx_midl_alloc(env->me_reclaimed_pglist[0]);
size = MDBX_PNL_SIZEOF(env->me_reclaimed_pglist);
env->me_reclaimed_pglist = mdbx_pnl_alloc(env->me_reclaimed_pglist[0]);
if (likely(env->me_reclaimed_pglist))
memcpy(env->me_reclaimed_pglist, ntxn->mnt_pgstate.mf_reclaimed_pglist,
size);
@ -2778,7 +2796,7 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) {
txn->mt_flags = MDBX_TXN_FINISHED;
if (!txn->mt_parent) {
mdbx_midl_shrink(&txn->mt_befree_pages);
mdbx_pnl_shrink(&txn->mt_befree_pages);
env->me_free_pgs = txn->mt_befree_pages;
/* me_pgstate: */
env->me_reclaimed_pglist = NULL;
@ -2795,12 +2813,12 @@ static int mdbx_txn_end(MDBX_txn *txn, unsigned mode) {
txn->mt_parent->mt_child = NULL;
txn->mt_parent->mt_flags &= ~MDBX_TXN_HAS_CHILD;
env->me_pgstate = ((MDBX_ntxn *)txn)->mnt_pgstate;
mdbx_midl_free(txn->mt_befree_pages);
mdbx_midl_free(txn->mt_spill_pages);
mdbx_pnl_free(txn->mt_befree_pages);
mdbx_pnl_free(txn->mt_spill_pages);
free(txn->mt_rw_dirtylist);
}
mdbx_midl_free(pghead);
mdbx_pnl_free(pghead);
}
if (mode & MDBX_END_FREE) {
@ -2962,32 +2980,32 @@ again_on_freelist_change:
/* Put loose page numbers in mt_free_pages,
* since unable to return them to me_reclaimed_pglist. */
MDBX_page *mp = txn->mt_loose_pages;
if (unlikely((rc = mdbx_midl_need(&txn->mt_befree_pages,
if (unlikely((rc = mdbx_pnl_need(&txn->mt_befree_pages,
txn->mt_loose_count)) != 0))
return rc;
for (; mp; mp = NEXT_LOOSE_PAGE(mp))
mdbx_midl_xappend(txn->mt_befree_pages, mp->mp_pgno);
mdbx_pnl_xappend(txn->mt_befree_pages, mp->mp_pgno);
} else {
/* Room for loose pages + temp IDL with same */
if ((rc = mdbx_midl_need(&env->me_reclaimed_pglist,
/* Room for loose pages + temp PNL with same */
if ((rc = mdbx_pnl_need(&env->me_reclaimed_pglist,
2 * txn->mt_loose_count + 1)) != 0)
goto bailout;
MDBX_IDL loose = env->me_reclaimed_pglist +
MDBX_IDL_ALLOCLEN(env->me_reclaimed_pglist) -
MDBX_PNL loose = env->me_reclaimed_pglist +
MDBX_PNL_ALLOCLEN(env->me_reclaimed_pglist) -
txn->mt_loose_count;
unsigned count = 0;
for (MDBX_page *mp = txn->mt_loose_pages; mp; mp = NEXT_LOOSE_PAGE(mp))
loose[++count] = mp->mp_pgno;
loose[0] = count;
mdbx_midl_sort(loose);
mdbx_midl_xmerge(env->me_reclaimed_pglist, loose);
mdbx_pnl_sort(loose);
mdbx_pnl_xmerge(env->me_reclaimed_pglist, loose);
}
txn->mt_loose_pages = NULL;
txn->mt_loose_count = 0;
}
/* Save the IDL of pages freed by this txn, to a single record */
/* Save the PNL of pages freed by this txn, to a single record */
if (befree_count < txn->mt_befree_pages[0]) {
if (unlikely(!befree_count)) {
/* Make sure last page of freeDB is touched and on freelist */
@ -3001,7 +3019,7 @@ again_on_freelist_change:
key.iov_base = &txn->mt_txnid;
do {
befree_count = befree_pages[0];
data.iov_len = MDBX_IDL_SIZEOF(befree_pages);
data.iov_len = MDBX_PNL_SIZEOF(befree_pages);
rc = mdbx_cursor_put(&mc, &key, &data, MDBX_RESERVE);
if (unlikely(rc))
goto bailout;
@ -3009,13 +3027,13 @@ again_on_freelist_change:
befree_pages = txn->mt_befree_pages;
} while (befree_count < befree_pages[0]);
mdbx_midl_sort(befree_pages);
mdbx_pnl_sort(befree_pages);
memcpy(data.iov_base, befree_pages, data.iov_len);
if (mdbx_debug_enabled(MDBX_DBG_EXTRA)) {
unsigned i = (unsigned)befree_pages[0];
mdbx_debug_extra("IDL write txn %" PRIaTXN " root %" PRIaPGNO
" num %u, IDL",
mdbx_debug_extra("PNL write txn %" PRIaTXN " root %" PRIaPGNO
" num %u, PNL",
txn->mt_txnid, txn->mt_dbs[FREE_DBI].md_root, i);
for (; i; i--)
mdbx_debug_extra_print(" %" PRIaPGNO "", befree_pages[i]);
@ -3084,7 +3102,7 @@ again_on_freelist_change:
mdbx_tassert(txn, txn->mt_lifo_reclaimed == NULL);
}
/* (Re)write {key = head_id, IDL length = head_room} */
/* (Re)write {key = head_id, PNL length = head_room} */
total_room -= head_room;
head_room = rpl_len - total_room;
if (head_room > (intptr_t)env->me_maxfree_1pg && head_id > 1) {
@ -3104,7 +3122,7 @@ again_on_freelist_change:
if (unlikely(rc))
goto bailout;
/* IDL is initially empty, zero out at least the length */
/* PNL is initially empty, zero out at least the length */
pgno_t *pgs = (pgno_t *)data.iov_base;
intptr_t i = head_room > clean_limit ? head_room : 0;
do {
@ -3170,6 +3188,7 @@ again_on_freelist_change:
data.iov_base = rpl_end;
pgno_t save = rpl_end[0];
rpl_end[0] = (pgno_t)chunk_len;
mdbx_tassert(txn, mdbx_pnl_check(rpl_end));
mc.mc_flags |= C_RECLAIMING;
rc = mdbx_cursor_put(&mc, &key, &data, MDBX_CURRENT);
mc.mc_flags ^= C_RECLAIMING;
@ -3358,7 +3377,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
MDBX_txn *parent = txn->mt_parent;
MDBX_page **lp;
MDBX_ID2L dst, src;
MDBX_IDL pspill;
MDBX_PNL pspill;
unsigned i, x, y, len, ps_len;
/* Append our reclaim list to parent's */
@ -3375,10 +3394,10 @@ int mdbx_txn_commit(MDBX_txn *txn) {
}
/* Append our free list to parent's */
rc = mdbx_midl_append_list(&parent->mt_befree_pages, txn->mt_befree_pages);
rc = mdbx_pnl_append_list(&parent->mt_befree_pages, txn->mt_befree_pages);
if (unlikely(rc != MDBX_SUCCESS))
goto fail;
mdbx_midl_free(txn->mt_befree_pages);
mdbx_pnl_free(txn->mt_befree_pages);
/* Failures after this must either undo the changes
* to the parent or set MDBX_TXN_ERROR in the parent. */
@ -3458,7 +3477,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
}
}
} else { /* Simplify the above for single-ancestor case */
len = MDBX_IDL_UM_MAX - txn->mt_dirtyroom;
len = MDBX_PNL_UM_MAX - txn->mt_dirtyroom;
}
/* Merge our dirty list with parent's */
y = src[0].mid;
@ -3476,12 +3495,11 @@ int mdbx_txn_commit(MDBX_txn *txn) {
if (txn->mt_spill_pages) {
if (parent->mt_spill_pages) {
/* TODO: Prevent failure here, so parent does not fail */
rc =
mdbx_midl_append_list(&parent->mt_spill_pages, txn->mt_spill_pages);
rc = mdbx_pnl_append_list(&parent->mt_spill_pages, txn->mt_spill_pages);
if (unlikely(rc != MDBX_SUCCESS))
parent->mt_flags |= MDBX_TXN_ERROR;
mdbx_midl_free(txn->mt_spill_pages);
mdbx_midl_sort(parent->mt_spill_pages);
mdbx_pnl_free(txn->mt_spill_pages);
mdbx_pnl_sort(parent->mt_spill_pages);
} else {
parent->mt_spill_pages = txn->mt_spill_pages;
}
@ -3494,7 +3512,7 @@ int mdbx_txn_commit(MDBX_txn *txn) {
parent->mt_loose_count += txn->mt_loose_count;
parent->mt_child = NULL;
mdbx_midl_free(((MDBX_ntxn *)txn)->mnt_pgstate.mf_reclaimed_pglist);
mdbx_pnl_free(((MDBX_ntxn *)txn)->mnt_pgstate.mf_reclaimed_pglist);
txn->mt_signature = 0;
free(txn);
return rc;
@ -3544,9 +3562,9 @@ int mdbx_txn_commit(MDBX_txn *txn) {
if (unlikely(rc != MDBX_SUCCESS))
goto fail;
mdbx_midl_free(env->me_reclaimed_pglist);
mdbx_pnl_free(env->me_reclaimed_pglist);
env->me_reclaimed_pglist = NULL;
mdbx_midl_shrink(&txn->mt_befree_pages);
mdbx_pnl_shrink(&txn->mt_befree_pages);
if (mdbx_audit_enabled())
mdbx_audit(txn);
@ -4136,13 +4154,12 @@ static void __cold mdbx_setup_pagesize(MDBX_env *env, const size_t pagesize) {
mdbx_ensure(env, mdbx_is_power2(pagesize));
mdbx_ensure(env, pagesize >= MIN_PAGESIZE);
mdbx_ensure(env, pagesize <= MAX_PAGESIZE);
env->me_psize = (unsigned)pagesize;
STATIC_ASSERT(mdbx_maxfree1pg(MIN_PAGESIZE) > 42);
STATIC_ASSERT(mdbx_maxfree1pg(MAX_PAGESIZE) < MDBX_IDL_DB_MAX);
STATIC_ASSERT(mdbx_maxfree1pg(MAX_PAGESIZE) < MDBX_PNL_DB_MAX);
const intptr_t maxfree_1pg = (pagesize - PAGEHDRSZ) / sizeof(pgno_t) - 1;
mdbx_ensure(env, maxfree_1pg > 42 && maxfree_1pg < MDBX_IDL_DB_MAX);
mdbx_ensure(env, maxfree_1pg > 42 && maxfree_1pg < MDBX_PNL_DB_MAX);
env->me_maxfree_1pg = (unsigned)maxfree_1pg;
STATIC_ASSERT(mdbx_nodemax(MIN_PAGESIZE) > 42);
@ -4985,8 +5002,8 @@ int __cold mdbx_env_open_ex(MDBX_env *env, const char *path, unsigned flags,
flags &= ~(MDBX_WRITEMAP | MDBX_MAPASYNC | MDBX_NOSYNC | MDBX_NOMETASYNC |
MDBX_COALESCE | MDBX_LIFORECLAIM | MDBX_NOMEMINIT);
} else {
if (!((env->me_free_pgs = mdbx_midl_alloc(MDBX_IDL_UM_MAX)) &&
(env->me_dirtylist = calloc(MDBX_IDL_UM_SIZE, sizeof(MDBX_ID2)))))
if (!((env->me_free_pgs = mdbx_pnl_alloc(MDBX_PNL_UM_MAX)) &&
(env->me_dirtylist = calloc(MDBX_PNL_UM_SIZE, sizeof(MDBX_ID2)))))
rc = MDBX_ENOMEM;
}
env->me_flags = flags |= MDBX_ENV_ACTIVE;
@ -5143,7 +5160,7 @@ static void __cold mdbx_env_close0(MDBX_env *env) {
mdbx_txl_free(env->me_txn0->mt_lifo_reclaimed);
free(env->me_txn0);
}
mdbx_midl_free(env->me_free_pgs);
mdbx_pnl_free(env->me_free_pgs);
if (env->me_flags & MDBX_ENV_TXKEY) {
mdbx_rthc_remove(env->me_txkey);
@ -5503,7 +5520,7 @@ static int mdbx_page_get(MDBX_cursor *mc, pgno_t pgno, MDBX_page **ret,
* leave that unless page_touch happens again). */
if (tx2->mt_spill_pages) {
pgno_t pn = pgno << 1;
x = mdbx_midl_search(tx2->mt_spill_pages, pn);
x = mdbx_pnl_search(tx2->mt_spill_pages, pn);
if (x <= tx2->mt_spill_pages[0] && tx2->mt_spill_pages[x] == pn)
goto mapped;
}
@ -5728,7 +5745,7 @@ static int mdbx_ovpage_free(MDBX_cursor *mc, MDBX_page *mp) {
pgno_t pg = mp->mp_pgno;
unsigned x = 0, ovpages = mp->mp_pages;
MDBX_env *env = txn->mt_env;
MDBX_IDL sl = txn->mt_spill_pages;
MDBX_PNL sl = txn->mt_spill_pages;
pgno_t pn = pg << 1;
int rc;
@ -5743,11 +5760,11 @@ static int mdbx_ovpage_free(MDBX_cursor *mc, MDBX_page *mp) {
* range in ancestor txns' dirty and spilled lists. */
if (env->me_reclaimed_pglist && !txn->mt_parent &&
((mp->mp_flags & P_DIRTY) ||
(sl && (x = mdbx_midl_search(sl, pn)) <= sl[0] && sl[x] == pn))) {
(sl && (x = mdbx_pnl_search(sl, pn)) <= sl[0] && sl[x] == pn))) {
unsigned i, j;
pgno_t *mop;
MDBX_ID2 *dl, ix, iy;
rc = mdbx_midl_need(&env->me_reclaimed_pglist, ovpages);
rc = mdbx_pnl_need(&env->me_reclaimed_pglist, ovpages);
if (unlikely(rc))
return rc;
if (!(mp->mp_flags & P_DIRTY)) {
@ -5789,7 +5806,7 @@ static int mdbx_ovpage_free(MDBX_cursor *mc, MDBX_page *mp) {
mop[j--] = pg++;
mop[0] += ovpages;
} else {
rc = mdbx_midl_append_range(&txn->mt_befree_pages, pg, ovpages);
rc = mdbx_pnl_append_range(&txn->mt_befree_pages, pg, ovpages);
if (unlikely(rc))
return rc;
}
@ -8422,7 +8439,7 @@ static int mdbx_rebalance(MDBX_cursor *mc) {
mc->mc_db->md_root = P_INVALID;
mc->mc_db->md_depth = 0;
mc->mc_db->md_leaf_pages = 0;
rc = mdbx_midl_append(&mc->mc_txn->mt_befree_pages, mp->mp_pgno);
rc = mdbx_pnl_append(&mc->mc_txn->mt_befree_pages, mp->mp_pgno);
if (unlikely(rc))
return rc;
/* Adjust cursors pointing to mp */
@ -8450,7 +8467,7 @@ static int mdbx_rebalance(MDBX_cursor *mc) {
} else if (IS_BRANCH(mp) && NUMKEYS(mp) == 1) {
int i;
mdbx_debug("collapsing root page!");
rc = mdbx_midl_append(&mc->mc_txn->mt_befree_pages, mp->mp_pgno);
rc = mdbx_pnl_append(&mc->mc_txn->mt_befree_pages, mp->mp_pgno);
if (unlikely(rc))
return rc;
mc->mc_db->md_root = NODEPGNO(NODEPTR(mp, 0));
@ -10122,8 +10139,8 @@ static int mdbx_drop0(MDBX_cursor *mc, int subs) {
if (unlikely(rc))
goto done;
mdbx_cassert(mc, IS_OVERFLOW(omp));
rc = mdbx_midl_append_range(&txn->mt_befree_pages, pg,
omp->mp_pages);
rc =
mdbx_pnl_append_range(&txn->mt_befree_pages, pg, omp->mp_pages);
if (unlikely(rc))
goto done;
mc->mc_db->md_overflow_pages -= omp->mp_pages;
@ -10139,14 +10156,14 @@ static int mdbx_drop0(MDBX_cursor *mc, int subs) {
if (!subs && !mc->mc_db->md_overflow_pages)
goto pop;
} else {
if (unlikely((rc = mdbx_midl_need(&txn->mt_befree_pages, n)) != 0))
if (unlikely((rc = mdbx_pnl_need(&txn->mt_befree_pages, n)) != 0))
goto done;
for (i = 0; i < n; i++) {
pgno_t pg;
ni = NODEPTR(mp, i);
pg = NODEPGNO(ni);
/* free it */
mdbx_midl_xappend(txn->mt_befree_pages, pg);
mdbx_pnl_xappend(txn->mt_befree_pages, pg);
}
}
if (!mc->mc_top)
@ -10169,7 +10186,7 @@ static int mdbx_drop0(MDBX_cursor *mc, int subs) {
}
}
/* free it */
rc = mdbx_midl_append(&txn->mt_befree_pages, mc->mc_db->md_root);
rc = mdbx_pnl_append(&txn->mt_befree_pages, mc->mc_db->md_root);
done:
if (unlikely(rc))
txn->mt_flags |= MDBX_TXN_ERROR;

View File

@ -1,4 +1,4 @@
/* mdbx_chk.c - memory-mapped database check tool */
/* mdbx_chk.c - memory-mapped database check tool */
/*
* Copyright 2015-2017 Leonid Yuriev <leo@yuriev.ru>
@ -343,7 +343,7 @@ static int handle_freedb(const uint64_t record_number, const MDBX_val *key,
data->iov_len);
else {
number = *iptr++;
if (number >= MDBX_IDL_UM_MAX)
if (number >= MDBX_PNL_UM_MAX)
problem_add("entry", record_number, "wrong idl length", "%" PRIiPTR "",
number);
else if ((number + 1) * sizeof(pgno_t) != data->iov_len)