aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--external/db_drivers/liblmdb/mdb.c41
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp69
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