mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-27 05:13:25 +01:00
Merge pull request #538
d462c62
db_lmdb: always use a batch tx if possible (moneromooo-monero)
This commit is contained in:
commit
617b8c4376
@ -29,6 +29,7 @@
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/current_function.hpp>
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <cstring> // memcpy
|
||||
#include <random>
|
||||
@ -1232,28 +1233,45 @@ void BlockchainLMDB::unlock()
|
||||
check_open();
|
||||
}
|
||||
|
||||
#define TXN_PREFIX(flags); \
|
||||
mdb_txn_safe auto_txn; \
|
||||
mdb_txn_safe* txn_ptr = &auto_txn; \
|
||||
if (m_batch_active) \
|
||||
txn_ptr = m_write_txn; \
|
||||
else \
|
||||
{ \
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, flags, auto_txn)) \
|
||||
throw0(DB_ERROR(lmdb_error(std::string("Failed to create a transaction for the db in ")+__FUNCTION__+": ", mdb_res).c_str())); \
|
||||
} \
|
||||
|
||||
#define TXN_PREFIX_RDONLY(); TXN_PREFIX(MDB_RDONLY);
|
||||
|
||||
#define TXN_POSTFIX_SUCCESS() \
|
||||
do { \
|
||||
if (! m_batch_active) \
|
||||
auto_txn.commit(); \
|
||||
} while(0)
|
||||
|
||||
bool BlockchainLMDB::block_exists(const crypto::hash& h) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<crypto::hash> key(h);
|
||||
MDB_val result;
|
||||
auto get_result = mdb_get(txn, m_block_heights, &key, &result);
|
||||
auto get_result = mdb_get(*txn_ptr, m_block_heights, &key, &result);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
{
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
LOG_PRINT_L3("Block with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
|
||||
return false;
|
||||
}
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("DB error attempting to fetch block index from hash"));
|
||||
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1270,21 +1288,18 @@ uint64_t BlockchainLMDB::get_block_height(const crypto::hash& h) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
uint64_t ret;
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<crypto::hash> key(h);
|
||||
MDB_val result;
|
||||
auto get_result = mdb_get(txn, m_block_heights, &key, &result);
|
||||
auto get_result = mdb_get(*txn_ptr, m_block_heights, &key, &result);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
throw1(BLOCK_DNE("Attempted to retrieve non-existent block height"));
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve a block height from the db"));
|
||||
|
||||
ret = *(const uint64_t *)result.mv_data;
|
||||
txn.commit();
|
||||
uint64_t ret = *(const uint64_t *)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1302,13 +1317,11 @@ block BlockchainLMDB::get_block_from_height(const uint64_t& height) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> key(height);
|
||||
MDB_val result;
|
||||
auto get_result = mdb_get(txn, m_blocks, &key, &result);
|
||||
auto get_result = mdb_get(*txn_ptr, m_blocks, &key, &result);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
{
|
||||
throw0(BLOCK_DNE(std::string("Attempt to get block from height ").append(boost::lexical_cast<std::string>(height)).append(" failed -- block not in db").c_str()));
|
||||
@ -1323,7 +1336,7 @@ block BlockchainLMDB::get_block_from_height(const uint64_t& height) const
|
||||
if (!parse_and_validate_block_from_blob(bd, b))
|
||||
throw0(DB_ERROR("Failed to parse block from blob retrieved from the db"));
|
||||
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return b;
|
||||
}
|
||||
@ -1333,16 +1346,8 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
uint64_t ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> key(height);
|
||||
MDB_val result;
|
||||
auto get_result = mdb_get(*txn_ptr, m_block_timestamps, &key, &result);
|
||||
@ -1353,9 +1358,8 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve a timestamp from the db"));
|
||||
|
||||
ret = *(const uint64_t *)result.mv_data;
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
uint64_t ret = *(const uint64_t *)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1378,17 +1382,8 @@ size_t BlockchainLMDB::get_block_size(const uint64_t& height) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
size_t ret;
|
||||
MDB_val_copy<uint64_t> key(height);
|
||||
MDB_val result;
|
||||
auto get_result = mdb_get(*txn_ptr, m_block_sizes, &key, &result);
|
||||
@ -1399,9 +1394,8 @@ size_t BlockchainLMDB::get_block_size(const uint64_t& height) const
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve a block size from the db"));
|
||||
|
||||
ret = *(const size_t *)result.mv_data;
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
size_t ret = *(const size_t *)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1410,16 +1404,8 @@ difficulty_type BlockchainLMDB::get_block_cumulative_difficulty(const uint64_t&
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__ << " height: " << height);
|
||||
check_open();
|
||||
|
||||
difficulty_type ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> key(height);
|
||||
MDB_val result;
|
||||
auto get_result = mdb_get(*txn_ptr, m_block_diffs, &key, &result);
|
||||
@ -1430,9 +1416,8 @@ difficulty_type BlockchainLMDB::get_block_cumulative_difficulty(const uint64_t&
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve a cumulative difficulty from the db"));
|
||||
|
||||
ret = *(difficulty_type*)result.mv_data;
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
difficulty_type ret = *(const difficulty_type*)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1458,16 +1443,7 @@ uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& heigh
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
uint64_t ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> key(height);
|
||||
MDB_val result;
|
||||
@ -1479,9 +1455,8 @@ uint64_t BlockchainLMDB::get_block_already_generated_coins(const uint64_t& heigh
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve a total generated coins from the db"));
|
||||
|
||||
ret = *(const uint64_t*)result.mv_data;
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
uint64_t ret = *(const uint64_t*)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1490,16 +1465,7 @@ crypto::hash BlockchainLMDB::get_block_hash_from_height(const uint64_t& height)
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
crypto::hash ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> key(height);
|
||||
MDB_val result;
|
||||
@ -1512,9 +1478,8 @@ crypto::hash BlockchainLMDB::get_block_hash_from_height(const uint64_t& height)
|
||||
throw0(DB_ERROR(std::string("Error attempting to retrieve a block hash from the db: ").
|
||||
append(mdb_strerror(get_result)).c_str()));
|
||||
|
||||
ret = *(crypto::hash*)result.mv_data;
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
crypto::hash ret = *(const crypto::hash*)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1585,15 +1550,7 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<crypto::hash> key(h);
|
||||
MDB_val result;
|
||||
@ -1602,8 +1559,9 @@ bool BlockchainLMDB::tx_exists(const crypto::hash& h) const
|
||||
auto get_result = mdb_get(*txn_ptr, m_txs, &key, &result);
|
||||
TIME_MEASURE_FINISH(time1);
|
||||
time_tx_exists += time1;
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
{
|
||||
LOG_PRINT_L1("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db");
|
||||
@ -1620,21 +1578,18 @@ uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
uint64_t ret;
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<crypto::hash> key(h);
|
||||
MDB_val result;
|
||||
auto get_result = mdb_get(txn, m_tx_unlocks, &key, &result);
|
||||
auto get_result = mdb_get(*txn_ptr, m_tx_unlocks, &key, &result);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
throw1(TX_DNE(std::string("tx unlock time with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str()));
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("DB error attempting to fetch tx unlock time from hash"));
|
||||
|
||||
ret = *(const uint64_t*)result.mv_data;
|
||||
txn.commit();
|
||||
uint64_t ret = *(const uint64_t*)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1643,15 +1598,7 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<crypto::hash> key(h);
|
||||
MDB_val result;
|
||||
@ -1667,8 +1614,8 @@ transaction BlockchainLMDB::get_tx(const crypto::hash& h) const
|
||||
transaction tx;
|
||||
if (!parse_and_validate_tx_from_blob(bd, tx))
|
||||
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return tx;
|
||||
}
|
||||
@ -1678,15 +1625,13 @@ uint64_t BlockchainLMDB::get_tx_count() const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_stat db_stats;
|
||||
if (mdb_stat(txn, m_txs, &db_stats))
|
||||
if (mdb_stat(*txn_ptr, m_txs, &db_stats))
|
||||
throw0(DB_ERROR("Failed to query m_txs"));
|
||||
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return db_stats.ms_entries;
|
||||
}
|
||||
@ -1710,16 +1655,7 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
uint64_t ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<crypto::hash> key(h);
|
||||
MDB_val result;
|
||||
@ -1731,10 +1667,8 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("DB error attempting to fetch tx height from hash"));
|
||||
|
||||
ret = *(const uint64_t*)result.mv_data;
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
|
||||
uint64_t ret = *(const uint64_t*)result.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1743,17 +1677,16 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
lmdb_cur cur(txn, m_output_amounts);
|
||||
lmdb_cur cur(*txn_ptr, m_output_amounts);
|
||||
|
||||
MDB_val_copy<uint64_t> k(amount);
|
||||
MDB_val v;
|
||||
auto result = mdb_cursor_get(cur, &k, &v, MDB_SET);
|
||||
if (result == MDB_NOTFOUND)
|
||||
{
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return 0;
|
||||
}
|
||||
else if (result)
|
||||
@ -1762,7 +1695,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
|
||||
size_t num_elems = 0;
|
||||
mdb_cursor_count(cur, &num_elems);
|
||||
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return num_elems;
|
||||
}
|
||||
@ -1772,21 +1705,18 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
output_data_t ret;
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> k(global_index);
|
||||
MDB_val_copy<uint64_t> k(global_index);
|
||||
MDB_val v;
|
||||
auto get_result = mdb_get(txn, m_output_keys, &k, &v);
|
||||
auto get_result = mdb_get(*txn_ptr, m_output_keys, &k, &v);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
throw1(OUTPUT_DNE("Attempting to get output pubkey by global index, but key does not exist"));
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db"));
|
||||
ret = *(output_data_t *) v.mv_data;
|
||||
txn.commit();
|
||||
return ret;
|
||||
output_data_t ret = *(const output_data_t *) v.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index)
|
||||
@ -1803,16 +1733,8 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
tx_out_index ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> k(index);
|
||||
MDB_val v;
|
||||
|
||||
@ -1822,7 +1744,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("DB error attempting to fetch output tx hash"));
|
||||
|
||||
crypto::hash tx_hash = *(crypto::hash*)v.mv_data;
|
||||
crypto::hash tx_hash = *(const crypto::hash*)v.mv_data;
|
||||
|
||||
get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
@ -1830,10 +1752,8 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t&
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("DB error attempting to fetch output tx index"));
|
||||
|
||||
ret = tx_out_index(tx_hash, *(const uint64_t *)v.mv_data);
|
||||
if (! m_batch_active)
|
||||
txn.commit();
|
||||
|
||||
tx_out_index ret = tx_out_index(tx_hash, *(const uint64_t *)v.mv_data);
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1856,11 +1776,9 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_output_indices(const crypto::hash&
|
||||
check_open();
|
||||
std::vector<uint64_t> index_vec;
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
lmdb_cur cur(txn, m_tx_outputs);
|
||||
lmdb_cur cur(*txn_ptr, m_tx_outputs);
|
||||
|
||||
MDB_val_copy<crypto::hash> k(h);
|
||||
MDB_val v;
|
||||
@ -1883,7 +1801,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_output_indices(const crypto::hash&
|
||||
}
|
||||
|
||||
cur.close();
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return index_vec;
|
||||
}
|
||||
@ -1901,9 +1819,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
|
||||
|
||||
transaction tx = get_tx(h);
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
uint64_t i = 0;
|
||||
uint64_t global_index;
|
||||
@ -1913,7 +1829,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
|
||||
|
||||
global_index = index_vec[i];
|
||||
|
||||
lmdb_cur cur(txn, m_output_amounts);
|
||||
lmdb_cur cur(*txn_ptr, m_output_amounts);
|
||||
|
||||
MDB_val_copy<uint64_t> k(amount);
|
||||
MDB_val v;
|
||||
@ -1952,7 +1868,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
|
||||
{
|
||||
// not found
|
||||
cur.close();
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
throw1(OUTPUT_DNE("specified output not found in db"));
|
||||
}
|
||||
|
||||
@ -1960,7 +1876,7 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const crypto:
|
||||
++i;
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return index_vec2;
|
||||
}
|
||||
@ -1972,19 +1888,17 @@ bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<crypto::key_image> val_key(img);
|
||||
MDB_val unused;
|
||||
if (mdb_get(txn, m_spent_keys, &val_key, &unused) == 0)
|
||||
if (mdb_get(*txn_ptr, m_spent_keys, &val_key, &unused) == 0)
|
||||
{
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return true;
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1993,15 +1907,13 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val k;
|
||||
MDB_val v;
|
||||
bool ret = true;
|
||||
|
||||
lmdb_cur cur(txn, m_spent_keys);
|
||||
lmdb_cur cur(*txn_ptr, m_spent_keys);
|
||||
MDB_cursor_op op = MDB_FIRST;
|
||||
while (1)
|
||||
{
|
||||
@ -2011,7 +1923,7 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
|
||||
break;
|
||||
if (ret < 0)
|
||||
throw0(DB_ERROR("Failed to enumerate key images"));
|
||||
const crypto::key_image k_image = *(crypto::key_image*)k.mv_data;
|
||||
const crypto::key_image k_image = *(const crypto::key_image*)k.mv_data;
|
||||
if (!f(k_image)) {
|
||||
ret = false;
|
||||
break;
|
||||
@ -2019,7 +1931,7 @@ bool BlockchainLMDB::for_all_key_images(std::function<bool(const crypto::key_ima
|
||||
}
|
||||
|
||||
cur.close();
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2029,15 +1941,13 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val k;
|
||||
MDB_val v;
|
||||
bool ret = true;
|
||||
|
||||
lmdb_cur cur(txn, m_blocks);
|
||||
lmdb_cur cur(*txn_ptr, m_blocks);
|
||||
MDB_cursor_op op = MDB_FIRST;
|
||||
while (1)
|
||||
{
|
||||
@ -2047,7 +1957,7 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
|
||||
break;
|
||||
if (ret)
|
||||
throw0(DB_ERROR("Failed to enumerate blocks"));
|
||||
uint64_t height = *(uint64_t*)k.mv_data;
|
||||
uint64_t height = *(const uint64_t*)k.mv_data;
|
||||
blobdata bd;
|
||||
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
|
||||
block b;
|
||||
@ -2063,7 +1973,7 @@ bool BlockchainLMDB::for_all_blocks(std::function<bool(uint64_t, const crypto::h
|
||||
}
|
||||
|
||||
cur.close();
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2073,15 +1983,13 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val k;
|
||||
MDB_val v;
|
||||
bool ret = true;
|
||||
|
||||
lmdb_cur cur(txn, m_txs);
|
||||
lmdb_cur cur(*txn_ptr, m_txs);
|
||||
MDB_cursor_op op = MDB_FIRST;
|
||||
while (1)
|
||||
{
|
||||
@ -2091,7 +1999,7 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
|
||||
break;
|
||||
if (ret)
|
||||
throw0(DB_ERROR("Failed to enumerate transactions"));
|
||||
const crypto::hash hash = *(crypto::hash*)k.mv_data;
|
||||
const crypto::hash hash = *(const crypto::hash*)k.mv_data;
|
||||
blobdata bd;
|
||||
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
|
||||
transaction tx;
|
||||
@ -2104,7 +2012,7 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
|
||||
}
|
||||
|
||||
cur.close();
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2114,15 +2022,13 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val k;
|
||||
MDB_val v;
|
||||
bool ret = true;
|
||||
|
||||
lmdb_cur cur(txn, m_output_amounts);
|
||||
lmdb_cur cur(*txn_ptr, m_output_amounts);
|
||||
MDB_cursor_op op = MDB_FIRST;
|
||||
while (1)
|
||||
{
|
||||
@ -2132,8 +2038,8 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
|
||||
break;
|
||||
if (ret)
|
||||
throw0(DB_ERROR("Failed to enumerate outputs"));
|
||||
uint64_t amount = *(uint64_t*)k.mv_data;
|
||||
uint64_t global_index = *(uint64_t*)v.mv_data;
|
||||
uint64_t amount = *(const uint64_t*)k.mv_data;
|
||||
uint64_t global_index = *(const uint64_t*)v.mv_data;
|
||||
tx_out_index toi = get_output_tx_and_index_from_global(global_index);
|
||||
if (!f(amount, toi.first, toi.second)) {
|
||||
ret = false;
|
||||
@ -2142,7 +2048,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
|
||||
}
|
||||
|
||||
cur.close();
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2335,15 +2241,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
|
||||
check_open();
|
||||
tx_out_indices.clear();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
for (const uint64_t &index : global_indices)
|
||||
{
|
||||
@ -2356,7 +2254,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("DB error attempting to fetch output tx hash"));
|
||||
|
||||
crypto::hash tx_hash = *(crypto::hash*) v.mv_data;
|
||||
crypto::hash tx_hash = *(const crypto::hash*) v.mv_data;
|
||||
|
||||
get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v);
|
||||
if (get_result == MDB_NOTFOUND)
|
||||
@ -2368,8 +2266,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
|
||||
tx_out_indices.push_back(result);
|
||||
}
|
||||
|
||||
if (!m_batch_active)
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
}
|
||||
|
||||
void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std::vector<uint64_t> &offsets,
|
||||
@ -2387,15 +2284,7 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
|
||||
max = index;
|
||||
}
|
||||
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if(m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
lmdb_cur cur(*txn_ptr, m_output_amounts);
|
||||
|
||||
@ -2474,8 +2363,7 @@ void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std
|
||||
}
|
||||
|
||||
cur.close();
|
||||
if(!m_batch_active)
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
|
||||
TIME_MEASURE_FINISH(txx);
|
||||
LOG_PRINT_L3("txx: " << txx << " db1: " << t_dbmul << " db2: " << t_dbscan);
|
||||
@ -2493,15 +2381,8 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
|
||||
|
||||
if (global_indices.size() > 0)
|
||||
{
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
for (const uint64_t &index : global_indices)
|
||||
{
|
||||
MDB_val_copy<uint64_t> k(index);
|
||||
@ -2513,12 +2394,11 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector<ui
|
||||
else if (get_result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db"));
|
||||
|
||||
output_data_t data = *(output_data_t *) v.mv_data;
|
||||
output_data_t data = *(const output_data_t *) v.mv_data;
|
||||
outputs.push_back(data);
|
||||
}
|
||||
|
||||
if (!m_batch_active)
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
}
|
||||
|
||||
TIME_MEASURE_FINISH(db3);
|
||||
@ -2548,24 +2428,14 @@ void BlockchainLMDB::set_hard_fork_starting_height(uint8_t version, uint64_t hei
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
txn_ptr = &txn;
|
||||
}
|
||||
TXN_PREFIX(0);
|
||||
|
||||
MDB_val_copy<uint8_t> val_key(version);
|
||||
MDB_val_copy<uint64_t> val_value(height);
|
||||
if (auto result = mdb_put(*txn_ptr, m_hf_starting_heights, &val_key, &val_value, 0))
|
||||
throw1(DB_ERROR(std::string("Error adding hard fork starting height to db transaction: ").append(mdb_strerror(result)).c_str()));
|
||||
|
||||
if (!m_batch_active)
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
}
|
||||
|
||||
uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const
|
||||
@ -2573,17 +2443,7 @@ uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
uint64_t ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
txn_ptr = &txn;
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint8_t> val_key(version);
|
||||
MDB_val val_ret;
|
||||
@ -2593,9 +2453,8 @@ uint64_t BlockchainLMDB::get_hard_fork_starting_height(uint8_t version) const
|
||||
if (result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve a hard fork starting height from the db"));
|
||||
|
||||
ret = *(const uint64_t*)val_ret.mv_data;
|
||||
if (!m_batch_active)
|
||||
txn.commit();
|
||||
uint64_t ret = *(const uint64_t*)val_ret.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2604,25 +2463,14 @@ void BlockchainLMDB::set_hard_fork_version(uint64_t height, uint8_t version)
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
//LOG_PRINT_L1("BlockchainLMDB::set_hard_fork_version: batch " << m_batch_active << ", height " << height << ", version " << (int)version);
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, 0, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
txn_ptr = &txn;
|
||||
}
|
||||
TXN_PREFIX(0);
|
||||
|
||||
MDB_val_copy<uint64_t> val_key(height);
|
||||
MDB_val_copy<uint8_t> val_value(version);
|
||||
if (auto result = mdb_put(*txn_ptr, m_hf_versions, &val_key, &val_value, 0))
|
||||
throw1(DB_ERROR(std::string("Error adding hard fork version to db transaction: ").append(mdb_strerror(result)).c_str()));
|
||||
|
||||
if (!m_batch_active)
|
||||
txn.commit();
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
}
|
||||
|
||||
uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
|
||||
@ -2630,17 +2478,7 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
uint8_t ret;
|
||||
mdb_txn_safe txn;
|
||||
mdb_txn_safe* txn_ptr = &txn;
|
||||
if (m_batch_active)
|
||||
txn_ptr = m_write_txn;
|
||||
else
|
||||
{
|
||||
if (auto mdb_res = mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
|
||||
txn_ptr = &txn;
|
||||
}
|
||||
TXN_PREFIX_RDONLY();
|
||||
|
||||
MDB_val_copy<uint64_t> val_key(height);
|
||||
MDB_val val_ret;
|
||||
@ -2648,9 +2486,8 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
|
||||
if (result == MDB_NOTFOUND || result)
|
||||
throw0(DB_ERROR("Error attempting to retrieve a hard fork version from the db"));
|
||||
|
||||
ret = *(const uint8_t*)val_ret.mv_data;
|
||||
if (!m_batch_active)
|
||||
txn.commit();
|
||||
uint8_t ret = *(const uint8_t*)val_ret.mv_data;
|
||||
TXN_POSTFIX_SUCCESS();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user