9
9
#include < util/bitset.h>
10
10
#include < util/check.h>
11
11
#include < util/feefrac.h>
12
+ #include < util/vector.h>
12
13
13
14
#include < compare>
14
15
#include < memory>
@@ -322,6 +323,8 @@ class TxGraphImpl final : public TxGraph
322
323
ChunkIndex m_main_chunkindex;
323
324
/* * Number of index-observing objects in existence (BlockBuilderImpls). */
324
325
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;
325
328
326
329
/* * A Locator that describes whether, where, and in which Cluster an Entry appears.
327
330
* Every Entry has MAX_LEVELS locators, as it may appear in one Cluster per level.
@@ -441,6 +444,10 @@ class TxGraphImpl final : public TxGraph
441
444
void ClearLocator (int level, GraphIndex index) noexcept ;
442
445
/* * Find which Clusters in main conflict with ones in staging. */
443
446
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 ;
444
451
445
452
// Functions for handling Refs.
446
453
@@ -594,6 +601,37 @@ class BlockBuilderImpl final : public TxGraph::BlockBuilder
594
601
void Skip () noexcept final ;
595
602
};
596
603
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
+
597
635
void TxGraphImpl::ClearLocator (int level, GraphIndex idx) noexcept
598
636
{
599
637
auto & entry = m_entries[idx];
@@ -616,25 +654,17 @@ void TxGraphImpl::ClearLocator(int level, GraphIndex idx) noexcept
616
654
--m_staging_clusterset->m_txcount ;
617
655
}
618
656
}
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);
624
658
}
625
659
626
660
void Cluster::Updated (TxGraphImpl& graph) noexcept
627
661
{
628
662
// Update all the Locators for this Cluster's Entry objects.
629
663
for (DepGraphIndex idx : m_linearization) {
630
664
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);
638
668
entry.m_locator [m_level].SetPresent (this , idx);
639
669
}
640
670
// 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
661
691
chunk.transactions .Reset (idx);
662
692
if (chunk.transactions .None ()) {
663
693
// 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);
667
695
break ;
668
696
}
669
697
}
@@ -922,13 +950,9 @@ void Cluster::Merge(TxGraphImpl& graph, Cluster& other) noexcept
922
950
// feerates, as Updated() will be invoked by Cluster::ApplyDependencies on the resulting
923
951
// merged Cluster later anyway).
924
952
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);
932
956
entry.m_locator [m_level].SetPresent (this , new_pos);
933
957
}
934
958
// Purge the other Cluster, now that everything has been moved.
@@ -1171,6 +1195,9 @@ void TxGraphImpl::Compact() noexcept
1171
1195
if (!m_staging_clusterset->m_removed .empty ()) return ;
1172
1196
}
1173
1197
1198
+ // Release memory used by discarded ChunkData index entries.
1199
+ ClearShrink (m_main_chunkindex_discarded);
1200
+
1174
1201
// Sort the GraphIndexes that need to be cleaned up. They are sorted in reverse, so the last
1175
1202
// ones get processed first. This means earlier-processed GraphIndexes will not cause moving of
1176
1203
// later-processed ones during the "swap with end of m_entries" step below (which might
0 commit comments