Skip to content

Commit 604acc2

Browse files
committed
txgraph: Reuse discarded chunkindex entries (optimization)
1 parent c734081 commit 604acc2

File tree

1 file changed

+49
-22
lines changed

1 file changed

+49
-22
lines changed

src/txgraph.cpp

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <util/bitset.h>
1010
#include <util/check.h>
1111
#include <util/feefrac.h>
12+
#include <util/vector.h>
1213

1314
#include <compare>
1415
#include <memory>
@@ -322,6 +323,8 @@ class TxGraphImpl final : public TxGraph
322323
ChunkIndex m_main_chunkindex;
323324
/** Number of index-observing objects in existence (BlockBuilderImpls). */
324325
size_t m_main_chunkindex_observers{0};
326+
/** Cache of discarded ChunkIndex node handles to re-use, avoiding additional allocation. */
327+
std::vector<ChunkIndex::node_type> m_main_chunkindex_discarded;
325328

326329
/** A Locator that describes whether, where, and in which Cluster an Entry appears.
327330
* Every Entry has MAX_LEVELS locators, as it may appear in one Cluster per level.
@@ -441,6 +444,10 @@ class TxGraphImpl final : public TxGraph
441444
void ClearLocator(int level, GraphIndex index) noexcept;
442445
/** Find which Clusters in main conflict with ones in staging. */
443446
std::vector<Cluster*> GetConflicts() const noexcept;
447+
/** Clear an Entry's ChunkData. */
448+
void ClearChunkData(Entry& entry) noexcept;
449+
/** Give an Entry a ChunkData object. */
450+
void CreateChunkData(GraphIndex idx, LinearizationIndex chunk_count) noexcept;
444451

445452
// Functions for handling Refs.
446453

@@ -594,6 +601,37 @@ class BlockBuilderImpl final : public TxGraph::BlockBuilder
594601
void Skip() noexcept final;
595602
};
596603

604+
void TxGraphImpl::ClearChunkData(Entry& entry) noexcept
605+
{
606+
if (entry.m_main_chunkindex_iterator != m_main_chunkindex.end()) {
607+
Assume(m_main_chunkindex_observers == 0);
608+
// If the Entry has a non-empty m_main_chunkindex_iterator, extract it, and move the handle
609+
// to the cache of discarded chunkindex entries.
610+
m_main_chunkindex_discarded.emplace_back(m_main_chunkindex.extract(entry.m_main_chunkindex_iterator));
611+
entry.m_main_chunkindex_iterator = m_main_chunkindex.end();
612+
}
613+
}
614+
615+
void TxGraphImpl::CreateChunkData(GraphIndex idx, LinearizationIndex chunk_count) noexcept
616+
{
617+
auto& entry = m_entries[idx];
618+
if (!m_main_chunkindex_discarded.empty()) {
619+
// Reuse an discarded node handle.
620+
auto& node = m_main_chunkindex_discarded.back().value();
621+
node.m_graph_index = idx;
622+
node.m_chunk_count = chunk_count;
623+
auto insert_result = m_main_chunkindex.insert(std::move(m_main_chunkindex_discarded.back()));
624+
Assume(insert_result.inserted);
625+
entry.m_main_chunkindex_iterator = insert_result.position;
626+
m_main_chunkindex_discarded.pop_back();
627+
} else {
628+
// Construct a new entry.
629+
auto emplace_result = m_main_chunkindex.emplace(idx, chunk_count);
630+
Assume(emplace_result.second);
631+
entry.m_main_chunkindex_iterator = emplace_result.first;
632+
}
633+
}
634+
597635
void TxGraphImpl::ClearLocator(int level, GraphIndex idx) noexcept
598636
{
599637
auto& entry = m_entries[idx];
@@ -616,25 +654,17 @@ void TxGraphImpl::ClearLocator(int level, GraphIndex idx) noexcept
616654
--m_staging_clusterset->m_txcount;
617655
}
618656
}
619-
if (level == 0 && entry.m_main_chunkindex_iterator != m_main_chunkindex.end()) {
620-
Assume(m_main_chunkindex_observers == 0);
621-
m_main_chunkindex.erase(entry.m_main_chunkindex_iterator);
622-
entry.m_main_chunkindex_iterator = m_main_chunkindex.end();
623-
}
657+
if (level == 0) ClearChunkData(entry);
624658
}
625659

626660
void Cluster::Updated(TxGraphImpl& graph) noexcept
627661
{
628662
// Update all the Locators for this Cluster's Entry objects.
629663
for (DepGraphIndex idx : m_linearization) {
630664
auto& entry = graph.m_entries[m_mapping[idx]];
631-
if (m_level == 0 && entry.m_main_chunkindex_iterator != graph.m_main_chunkindex.end()) {
632-
// Destroy any potential ChunkData prior to modifying the Cluster (as that could
633-
// invalidate its ordering).
634-
Assume(graph.m_main_chunkindex_observers == 0);
635-
graph.m_main_chunkindex.erase(entry.m_main_chunkindex_iterator);
636-
entry.m_main_chunkindex_iterator = graph.m_main_chunkindex.end();
637-
}
665+
// Discard any potential ChunkData prior to modifying the Cluster (as that could
666+
// invalidate its ordering).
667+
if (m_level == 0) graph.ClearChunkData(entry);
638668
entry.m_locator[m_level].SetPresent(this, idx);
639669
}
640670
// If this is for the main graph (level = 0), and the Cluster's quality is ACCEPTABLE or
@@ -661,9 +691,7 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept
661691
chunk.transactions.Reset(idx);
662692
if (chunk.transactions.None()) {
663693
// Last transaction in the chunk.
664-
auto [it, inserted] = graph.m_main_chunkindex.emplace(graph_idx, chunk_count);
665-
Assume(inserted);
666-
entry.m_main_chunkindex_iterator = it;
694+
graph.CreateChunkData(graph_idx, chunk_count);
667695
break;
668696
}
669697
}
@@ -922,13 +950,9 @@ void Cluster::Merge(TxGraphImpl& graph, Cluster& other) noexcept
922950
// feerates, as Updated() will be invoked by Cluster::ApplyDependencies on the resulting
923951
// merged Cluster later anyway).
924952
auto& entry = graph.m_entries[idx];
925-
if (m_level == 0 && entry.m_main_chunkindex_iterator != graph.m_main_chunkindex.end()) {
926-
// Destroy any potential ChunkData prior to modifying the Cluster (as that could
927-
// invalidate its ordering).
928-
Assume(graph.m_main_chunkindex_observers == 0);
929-
graph.m_main_chunkindex.erase(entry.m_main_chunkindex_iterator);
930-
entry.m_main_chunkindex_iterator = graph.m_main_chunkindex.end();
931-
}
953+
// Discard any potential ChunkData prior to modifying the Cluster (as that could
954+
// invalidate its ordering).
955+
if (m_level == 0) graph.ClearChunkData(entry);
932956
entry.m_locator[m_level].SetPresent(this, new_pos);
933957
}
934958
// Purge the other Cluster, now that everything has been moved.
@@ -1171,6 +1195,9 @@ void TxGraphImpl::Compact() noexcept
11711195
if (!m_staging_clusterset->m_removed.empty()) return;
11721196
}
11731197

1198+
// Release memory used by discarded ChunkData index entries.
1199+
ClearShrink(m_main_chunkindex_discarded);
1200+
11741201
// Sort the GraphIndexes that need to be cleaned up. They are sorted in reverse, so the last
11751202
// ones get processed first. This means earlier-processed GraphIndexes will not cause moving of
11761203
// later-processed ones during the "swap with end of m_entries" step below (which might

0 commit comments

Comments
 (0)