Skip to content

Commit 1171953

Browse files
committed
txgraph: Avoid representative lookup for each dependency (optimization)
The m_deps_to_add vector is sorted by child Cluster*, which matches the order of an_clusters. This means we can walk through m_deps_to_add while doing the representative lookups for an_clusters, and reuse them.
1 parent 64f69ec commit 1171953

File tree

1 file changed

+25
-12
lines changed

1 file changed

+25
-12
lines changed

src/txgraph.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,15 @@ void TxGraphImpl::GroupClusters() noexcept
734734
std::sort(an_clusters.begin(), an_clusters.end());
735735
an_clusters.erase(std::unique(an_clusters.begin(), an_clusters.end()), an_clusters.end());
736736

737+
// Sort the dependencies by child Cluster.
738+
std::sort(m_deps_to_add.begin(), m_deps_to_add.end(), [&](auto& a, auto& b) noexcept {
739+
auto [_a_par, a_chl] = a;
740+
auto [_b_par, b_chl] = b;
741+
auto a_chl_cluster = m_entries[a_chl].m_locator.cluster;
742+
auto b_chl_cluster = m_entries[b_chl].m_locator.cluster;
743+
return std::less{}(a_chl_cluster, b_chl_cluster);
744+
});
745+
737746
// Run the union-find algorithm to to find partitions of the input Clusters which need to be
738747
// grouped together. See https://en.wikipedia.org/wiki/Disjoint-set_data_structure.
739748
{
@@ -813,25 +822,29 @@ void TxGraphImpl::GroupClusters() noexcept
813822
// Populate the an_clusters and an_deps data structures with the list of input Clusters,
814823
// and the input dependencies, annotated with the representative of the Cluster partition
815824
// it applies to.
825+
an_deps.reserve(m_deps_to_add.size());
826+
auto deps_it = m_deps_to_add.begin();
816827
for (size_t i = 0; i < partition_data.size(); ++i) {
817828
auto& data = partition_data[i];
818829
// Find the representative of the partition Cluster i is in, and store it with the
819830
// Cluster.
820831
auto rep = find_root_fn(&data)->cluster;
821832
Assume(an_clusters[i].second == nullptr);
822833
an_clusters[i].second = rep;
823-
}
824-
an_deps.reserve(m_deps_to_add.size());
825-
for (auto [par, chl] : m_deps_to_add) {
826-
auto chl_cluster = m_entries[chl].m_locator.cluster;
827-
auto par_cluster = m_entries[par].m_locator.cluster;
828-
// Nothing to do if either parent or child transaction is removed already.
829-
if (par_cluster == nullptr || chl_cluster == nullptr) continue;
830-
// Find the representative of the partition which this dependency's child is in (which
831-
// should be the same as the one for the parent).
832-
auto rep = find_root_fn(locate_fn(chl_cluster))->cluster;
833-
// Create an_deps entry.
834-
an_deps.emplace_back(std::pair{par, chl}, rep);
834+
// Find all dependencies whose child Cluster is Cluster i, and annotate them with rep.
835+
while (deps_it != m_deps_to_add.end()) {
836+
auto [par, chl] = *deps_it;
837+
auto chl_cluster = m_entries[chl].m_locator.cluster;
838+
if (std::greater{}(chl_cluster, data.cluster)) break;
839+
// Skip dependencies that apply to earlier Clusters (those necessary are for
840+
// deleted transactions, as otherwise we'd have processed them already).
841+
if (chl_cluster == data.cluster) {
842+
auto par_cluster = m_entries[par].m_locator.cluster;
843+
// Also filter out dependencies applying to a removed parent.
844+
if (par_cluster != nullptr) an_deps.emplace_back(*deps_it, rep);
845+
}
846+
++deps_it;
847+
}
835848
}
836849
}
837850

0 commit comments

Comments
 (0)