Skip to content
This repository has been archived by the owner on Sep 22, 2022. It is now read-only.

Commit

Permalink
mdbx: fix extra-rare MDBX_KEY_EXIST during mdbx_commit().
Browse files Browse the repository at this point in the history
The MDX_KEYEXISTS error could occur inside mdbx_update_gc() in the extremely rare case:

- no GC records was reclaimed before mdbx_txn_commit() called;

- there were few loose pages during the transaction;

- some reader prohibit reclaiming, therefore mdbx_page_alloc(MDBX_ALLOC_GC),
  which called for obtain present GC-record's Id, returns MDBX_NOTFOUND;

- immediately then the reader completes its transaction and unlocks reclaiming;

- mdbx_update_gc() decide that no reclaimable GC entries,
  i.e. no GC-entries with ID < find_oldest(),
  and it is safe to use find_oldest() - 1 to store loose page list;

- but find_oldest() actually returns new/larger ID than expected,
  So KEYEXISTS will returned if using this ID.

Change-Id: I9726217d6b5983f1e31a211c0eeb3edc8ff94282
  • Loading branch information
erthink committed Oct 26, 2020
1 parent 1804b78 commit 3fd0792
Showing 1 changed file with 9 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -7503,9 +7503,12 @@ static int mdbx_update_gc(MDBX_txn *txn) {
env->me_maxgc_ov1page) {

/* LY: need just a txn-id for save page list. */
couple.outer.mc_flags &= ~C_RECLAIMING;
bool need_cleanup = false;
txnid_t snap_oldest;
retry_rid:
couple.outer.mc_flags &= ~C_RECLAIMING;
do {
snap_oldest = mdbx_find_oldest(txn);
rc = mdbx_page_alloc(&couple.outer, 0, NULL, MDBX_ALLOC_GC);
if (likely(rc == MDBX_SUCCESS)) {
mdbx_trace("%s: took @%" PRIaTXN " from GC", dbg_prefix_mode,
Expand Down Expand Up @@ -7533,9 +7536,13 @@ static int mdbx_update_gc(MDBX_txn *txn) {
gc_rid = MDBX_PNL_LAST(txn->tw.lifo_reclaimed);
} else {
mdbx_tassert(txn, txn->tw.last_reclaimed == 0);
if (unlikely(mdbx_find_oldest(txn) != snap_oldest))
/* should retry mdbx_page_alloc(MDBX_ALLOC_GC)
* if the oldest reader changes since the last attempt */
goto retry_rid;
/* no reclaimable GC entries,
* therefore no entries with ID < mdbx_find_oldest(txn) */
txn->tw.last_reclaimed = gc_rid = mdbx_find_oldest(txn) - 1;
txn->tw.last_reclaimed = gc_rid = snap_oldest - 1;
mdbx_trace("%s: none recycled yet, set rid to @%" PRIaTXN,
dbg_prefix_mode, gc_rid);
}
Expand Down

0 comments on commit 3fd0792

Please sign in to comment.