diff options
-rw-r--r-- | external/db_drivers/liblmdb/mdb.c | 41 | ||||
-rw-r--r-- | src/blockchain_db/berkeleydb/db_bdb.cpp | 69 |
2 files changed, 62 insertions, 48 deletions
diff --git a/external/db_drivers/liblmdb/mdb.c b/external/db_drivers/liblmdb/mdb.c index d524d3523..7be13997a 100644 --- a/external/db_drivers/liblmdb/mdb.c +++ b/external/db_drivers/liblmdb/mdb.c @@ -5829,7 +5829,7 @@ retry: if (rc) goto fail; if (!el[x].mref) { - munmap(el[x].mptr, el[x].mcnt); + munmap(el[x].mptr, env->me_psize * el[x].mcnt); el[x].mptr = id3.mptr; el[x].mcnt = id3.mcnt; } else { @@ -5881,36 +5881,15 @@ fail: pthread_mutex_unlock(&env->me_rpmutex); return rc; } - /* If this page is far enough from the end of the env, scan for - * any overflow pages that would spill onto another block. - * Note we must compare against mt_last_pgno, the last written - * page in the environment. Not mt_next_pgno, which increases - * for every newly allocated (but not yet written) page. If - * we scanned beyond the last written page we'd get a bus error. - */ - if (pgno + MDB_RPAGE_CHUNK <= txn->mt_last_pgno) { - int i; - char *cp = (char *)id3.mptr + rem * env->me_psize; - for (i=rem; i<MDB_RPAGE_CHUNK;) { - p = (MDB_page *)cp; - if (IS_OVERFLOW(p)) { - int nop = p->mp_pages; - if (nop + i > MDB_RPAGE_CHUNK) { - munmap(id3.mptr, len); - id3.mcnt = nop + i; - len = id3.mcnt * env->me_psize; - MAP(rc, env, id3.mptr, len, off); - if (rc) - goto fail; - break; - } - i += nop; - cp += nop * env->me_psize; - } else { - i++; - cp += env->me_psize; - } - } + /* check for overflow size */ + p = (MDB_page *)((char *)id3.mptr + rem * env->me_psize); + if (IS_OVERFLOW(p) && p->mp_pages + rem > id3.mcnt) { + id3.mcnt = p->mp_pages + rem; + munmap(id3.mptr, len); + len = id3.mcnt * env->me_psize; + MAP(rc, env, id3.mptr, len, off); + if (rc) + goto fail; } mdb_mid3l_insert(el, &id3); pthread_mutex_unlock(&env->me_rpmutex); diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp index 02fdaba2f..832fb8f8d 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ b/src/blockchain_db/berkeleydb/db_bdb.cpp @@ -354,9 +354,11 @@ void BlockchainBDB::remove_transaction_data(const crypto::hash& tx_hash, const t remove_tx_outputs(tx_hash, tx); - if (m_tx_outputs->del(DB_DEFAULT_TX, &val_h, 0)) + auto result = m_tx_outputs->del(DB_DEFAULT_TX, &val_h, 0); + if (result == DB_NOTFOUND) + LOG_PRINT_L1("tx has no outputs to remove: " << tx_hash); + else if (result) throw1(DB_ERROR("Failed to add removal of tx outputs to db transaction")); - } void BlockchainBDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) @@ -411,7 +413,7 @@ void BlockchainBDB::remove_tx_outputs(const crypto::hash& tx_hash, const transac auto result = cur->get(&k, &v, DB_SET); if (result == DB_NOTFOUND) { - throw0(OUTPUT_DNE("Attempting to remove a tx's outputs, but none found.")); + LOG_PRINT_L2("tx has no outputs, so no global output indices"); } else if (result) { @@ -419,16 +421,26 @@ void BlockchainBDB::remove_tx_outputs(const crypto::hash& tx_hash, const transac } else { + result = cur->get(&k, &v, DB_NEXT_NODUP); + if (result != 0 && result != DB_NOTFOUND) + throw0(DB_ERROR("DB error attempting to get next non-duplicate tx hash")); + + if (result == 0) + result = cur->get(&k, &v, DB_PREV); + else if (result == DB_NOTFOUND) + result = cur->get(&k, &v, DB_LAST); + db_recno_t num_elems = 0; cur->count(&num_elems, 0); - for (uint64_t i = 0; i < num_elems; ++i) + // remove in order: from newest to oldest + for (uint64_t i = num_elems; i > 0; --i) { - const tx_out tx_output = tx.vout[i]; + const tx_out tx_output = tx.vout[i-1]; remove_output(v, tx_output.amount); - if (i < num_elems - 1) + if (i > 1) { - cur->get(&k, &v, DB_NEXT_DUP); + cur->get(&k, &v, DB_PREV_DUP); } } } @@ -504,20 +516,43 @@ void BlockchainBDB::remove_amount_output_index(const uint64_t amount, const uint db_recno_t num_elems = 0; cur->count(&num_elems, 0); + // workaround for Berkeley DB to start at end of k's duplicate list: + // if next key exists: + // - move cursor to start of next key's duplicate list, then move back one + // duplicate element to reach the end of the original key's duplicate + // list. + // + // else if the next key doesn't exist: + // - that means we're already on the last key. + // - move cursor to last element in the db, which is the last element of + // the desired key's duplicate list. + + result = cur->get(&k, &v, DB_NEXT_NODUP); + if (result != 0 && result != DB_NOTFOUND) + throw0(DB_ERROR("DB error attempting to get next non-duplicate output amount")); + + if (result == 0) + result = cur->get(&k, &v, DB_PREV); + else if (result == DB_NOTFOUND) + result = cur->get(&k, &v, DB_LAST); + + bool found_index = false; uint64_t amount_output_index = 0; uint64_t goi = 0; - bool found_index = false; - for (uint64_t i = 0; i < num_elems; ++i) + + for (uint64_t i = num_elems; i > 0; --i) { - goi = v; - if (goi == global_output_index) - { - amount_output_index = i; - found_index = true; - break; - } - cur->get(&k, &v, DB_NEXT_DUP); + goi = v; + if (goi == global_output_index) + { + amount_output_index = i-1; + found_index = true; + break; + } + if (i > 1) + cur->get(&k, &v, DB_PREV_DUP); } + if (found_index) { // found the amount output index |