| 1437 | } |
| 1438 | |
| 1439 | bool GenericClusterImpl::Split(TxGraphImpl& graph, int level) noexcept |
| 1440 | { |
| 1441 | // This function can only be called when the Cluster needs splitting. |
| 1442 | Assume(NeedsSplitting()); |
| 1443 | // Determine the new quality the split-off Clusters will have. |
| 1444 | QualityLevel new_quality = IsTopological() ? QualityLevel::NEEDS_RELINEARIZE : QualityLevel::NEEDS_FIX; |
| 1445 | /** Which positions are still left in this Cluster. */ |
| 1446 | auto todo = m_depgraph.Positions(); |
| 1447 | /** Mapping from transaction positions in this Cluster to the Cluster where it ends up, and |
| 1448 | * its position therein. */ |
| 1449 | std::vector<std::pair<Cluster*, DepGraphIndex>> remap(m_depgraph.PositionRange()); |
| 1450 | std::vector<Cluster*> new_clusters; |
| 1451 | bool first{true}; |
| 1452 | // Iterate over the connected components of this Cluster's m_depgraph. |
| 1453 | while (todo.Any()) { |
| 1454 | auto component = m_depgraph.FindConnectedComponent(todo); |
| 1455 | auto component_size = component.Count(); |
| 1456 | auto split_quality = component_size <= 1 ? QualityLevel::OPTIMAL : new_quality; |
| 1457 | if (first && component == todo && SetType::Fill(component_size) == component && component_size >= MIN_INTENDED_TX_COUNT) { |
| 1458 | // The existing Cluster is an entire component, without holes. Leave it be, but update |
| 1459 | // its quality. If there are holes, we continue, so that the Cluster is reconstructed |
| 1460 | // without holes, reducing memory usage. If the component's size is below the intended |
| 1461 | // transaction count for this Cluster implementation, continue so that it can get |
| 1462 | // converted. |
| 1463 | Assume(todo == m_depgraph.Positions()); |
| 1464 | graph.SetClusterQuality(level, m_quality, m_setindex, split_quality); |
| 1465 | // If this made the quality ACCEPTABLE or OPTIMAL, we need to compute and cache its |
| 1466 | // chunking. |
| 1467 | Updated(graph, /*level=*/level, /*rename=*/false); |
| 1468 | return false; |
| 1469 | } |
| 1470 | first = false; |
| 1471 | // Construct a new Cluster to hold the found component. |
| 1472 | auto new_cluster = graph.CreateEmptyCluster(component_size); |
| 1473 | new_clusters.push_back(new_cluster.get()); |
| 1474 | // Remember that all the component's transactions go to this new Cluster. The positions |
| 1475 | // will be determined below, so use -1 for now. |
| 1476 | for (auto i : component) { |
| 1477 | remap[i] = {new_cluster.get(), DepGraphIndex(-1)}; |
| 1478 | } |
| 1479 | graph.InsertCluster(level, std::move(new_cluster), split_quality); |
| 1480 | todo -= component; |
| 1481 | } |
| 1482 | // We have to split the Cluster up. Remove accounting for the existing one first. |
| 1483 | graph.GetClusterSet(level).m_cluster_usage -= TotalMemoryUsage(); |
| 1484 | // Redistribute the transactions. |
| 1485 | for (auto i : m_linearization) { |
| 1486 | /** The cluster which transaction originally in position i is moved to. */ |
| 1487 | Cluster* new_cluster = remap[i].first; |
| 1488 | // Copy the transaction to the new cluster's depgraph, and remember the position. |
| 1489 | remap[i].second = new_cluster->AppendTransaction(m_mapping[i], FeePerWeight::FromFeeFrac(m_depgraph.FeeRate(i))); |
| 1490 | } |
| 1491 | // Redistribute the dependencies. |
| 1492 | for (auto i : m_linearization) { |
| 1493 | /** The cluster transaction in position i is moved to. */ |
| 1494 | Cluster* new_cluster = remap[i].first; |
| 1495 | // Copy its parents, translating positions. |
| 1496 | SetType new_parents; |
nothing calls this directly
no test coverage detected