From acc7d05885e35241cfa16cad6297ede0fbca6b5e Mon Sep 17 00:00:00 2001 From: j-berman Date: Thu, 5 Sep 2024 12:27:45 -0700 Subject: [PATCH] fcmp++ LMDB: use dummy key optimization on leaves table - Save 8 bytes per leaf by using DUPFIXED table and dummy "zerokval" key and attaching leaf_idx as prefix to data to serve as DUPSORT key --- src/blockchain_db/lmdb/db_lmdb.cpp | 51 ++++++++++++++++++------------ 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 70b719e19..4ee7adb42 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -214,7 +214,8 @@ namespace * attached as a prefix on the Data to serve as the DUPSORT key. * (DUPFIXED saves 8 bytes per record.) * - * The output_amounts and layers tables don't use a dummy key, but use DUPSORT + * The output_amounts, locked_outputs, and layers tables don't use a + * dummy key, but use DUPSORT. */ const char* const LMDB_BLOCKS = "blocks"; const char* const LMDB_BLOCK_HEIGHTS = "block_heights"; @@ -375,10 +376,15 @@ typedef struct outtx { uint64_t local_index; } outtx; -struct layer_val { +typedef struct mdb_leaf { + uint64_t leaf_idx; + fcmp_pp::curve_trees::OutputContext output_context; +} mdb_leaf; + +typedef struct layer_val { uint64_t child_chunk_idx; std::array child_chunk_hash; -}; +} layer_val; std::atomic mdb_txn_safe::num_active_txns{0}; std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT; @@ -1400,17 +1406,18 @@ void BlockchainLMDB::grow_tree(std::vector // Use the number of leaf tuples and the existing last hashes to get a struct we can use to extend the tree CHECK_AND_ASSERT_THROW_MES(m_curve_trees != nullptr, "curve trees must be set"); - const auto tree_extension = m_curve_trees->get_tree_extension(old_n_leaf_tuples, last_hashes, std::move(new_outputs)); + auto tree_extension = m_curve_trees->get_tree_extension(old_n_leaf_tuples, last_hashes, std::move(new_outputs)); // Insert the leaves // TODO: grow_leaves - const auto &leaves = tree_extension.leaves; + auto &leaves = tree_extension.leaves; for (uint64_t i = 0; i < leaves.tuples.size(); ++i) { - MDB_val_copy k(i + leaves.start_leaf_tuple_idx); - MDB_val_set(v, leaves.tuples[i]); + const uint64_t leaf_idx = i + leaves.start_leaf_tuple_idx; + mdb_leaf val{.leaf_idx = leaf_idx, .output_context = std::move(leaves.tuples[i])}; + MDB_val_set(v, val); - int result = mdb_cursor_put(m_cur_leaves, &k, &v, MDB_APPEND); + int result = mdb_cursor_put(m_cur_leaves, (MDB_val *)&zerokval, &v, MDB_APPENDDUP); if (result != MDB_SUCCESS) throw0(DB_ERROR(lmdb_error("Failed to add leaf: ", result).c_str())); } @@ -1550,8 +1557,8 @@ void BlockchainLMDB::trim_tree(const uint64_t trim_n_leaf_tuples, const uint64_t uint64_t leaf_tuple_idx = (old_n_leaf_tuples - trim_n_leaf_tuples + i); MDB_val_copy k(leaf_tuple_idx); - MDB_val v; - int result = mdb_cursor_get(m_cur_leaves, &k, &v, MDB_SET); + MDB_val v = k; + int result = mdb_cursor_get(m_cur_leaves, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); if (result == MDB_NOTFOUND) throw0(DB_ERROR("leaf not found")); // TODO: specific error type instead of DB_ERROR if (result != MDB_SUCCESS) @@ -1559,8 +1566,9 @@ void BlockchainLMDB::trim_tree(const uint64_t trim_n_leaf_tuples, const uint64_t // Re-add the output to the locked output table in order. The output should // be in the outputs tables. - const auto o = *(fcmp_pp::curve_trees::OutputContext *)v.mv_data; - MDB_val_set(v_output, o); + const auto *o = (mdb_leaf *)v.mv_data; + MDB_val_set(v_output, o->output_context); + MDEBUG("Re-adding locked output_id: " << o->output_context.output_id << " , unlock block: " << trim_block_id); result = mdb_cursor_put(m_cur_locked_outputs, &k_block_id, &v_output, MDB_APPENDDUP); if (result != MDB_SUCCESS) throw0(DB_ERROR(lmdb_error("Failed to re-add locked output: ", result).c_str())); @@ -1742,7 +1750,7 @@ uint64_t BlockchainLMDB::get_num_leaf_tuples() const if (result == MDB_NOTFOUND) n_leaf_tuples = 0; else if (result == MDB_SUCCESS) - n_leaf_tuples = (1 + (*(const uint64_t*)k.mv_data)); + n_leaf_tuples = 1 + ((const mdb_leaf*)v.mv_data)->leaf_idx; else throw0(DB_ERROR(lmdb_error("Failed to get last leaf: ", result).c_str())); } @@ -1896,22 +1904,22 @@ fcmp_pp::curve_trees::CurveTreesV1::LastChunkChildrenToTrim BlockchainLMDB::get_ const uint64_t leaf_tuple_idx = idx / fcmp_pp::curve_trees::CurveTreesV1::LEAF_TUPLE_SIZE; MDB_val_copy k(leaf_tuple_idx); + MDB_val v = k; - MDB_cursor_op leaf_op = MDB_SET; + MDB_cursor_op leaf_op = MDB_GET_BOTH; do { - MDB_val v; - int result = mdb_cursor_get(m_cur_leaves, &k, &v, leaf_op); + int result = mdb_cursor_get(m_cur_leaves, (MDB_val *)&zerokval, &v, leaf_op); leaf_op = MDB_NEXT; if (result == MDB_NOTFOUND) throw0(DB_ERROR("leaf not found")); // TODO: specific error type instead of DB_ERROR if (result != MDB_SUCCESS) throw0(DB_ERROR(lmdb_error("Failed to get leaf: ", result).c_str())); - const auto o = *(fcmp_pp::curve_trees::OutputContext *)v.mv_data; + const auto *db_leaf = (mdb_leaf *)v.mv_data; // TODO: parallelize calls to this function - auto leaf = m_curve_trees->leaf_tuple(o.output_pair); + auto leaf = m_curve_trees->leaf_tuple(db_leaf->output_context.output_pair); leaves_to_trim.emplace_back(std::move(leaf.O_x)); leaves_to_trim.emplace_back(std::move(leaf.I_x)); @@ -2088,8 +2096,8 @@ bool BlockchainLMDB::audit_tree(const uint64_t expected_n_leaf_tuples) const if (result != MDB_SUCCESS) throw0(DB_ERROR(lmdb_error("Failed to add leaf: ", result).c_str())); - const auto o = *(fcmp_pp::curve_trees::OutputContext *)v.mv_data; - auto leaf = m_curve_trees->leaf_tuple(o.output_pair); + const auto *o = (mdb_leaf *)v.mv_data; + auto leaf = m_curve_trees->leaf_tuple(o->output_context.output_pair); leaf_tuples_chunk.emplace_back(std::move(leaf)); @@ -2547,7 +2555,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) lmdb_db_open(txn, LMDB_SPENT_KEYS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_spent_keys, "Failed to open db handle for m_spent_keys"); lmdb_db_open(txn, LMDB_LOCKED_OUTPUTS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_locked_outputs, "Failed to open db handle for m_locked_outputs"); - lmdb_db_open(txn, LMDB_LEAVES, MDB_INTEGERKEY | MDB_CREATE, m_leaves, "Failed to open db handle for m_leaves"); + lmdb_db_open(txn, LMDB_LEAVES, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_leaves, "Failed to open db handle for m_leaves"); lmdb_db_open(txn, LMDB_LAYERS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_layers, "Failed to open db handle for m_layers"); lmdb_db_open(txn, LMDB_TXPOOL_META, MDB_CREATE, m_txpool_meta, "Failed to open db handle for m_txpool_meta"); @@ -2570,6 +2578,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) mdb_set_dupsort(txn, m_tx_indices, compare_hash32); mdb_set_dupsort(txn, m_output_amounts, compare_uint64); mdb_set_dupsort(txn, m_locked_outputs, compare_uint64); + mdb_set_dupsort(txn, m_leaves, compare_uint64); mdb_set_dupsort(txn, m_layers, compare_uint64); mdb_set_dupsort(txn, m_output_txs, compare_uint64); mdb_set_dupsort(txn, m_block_info, compare_uint64);