Loading src/client.cpp +18 −33 Original line number Diff line number Diff line Loading @@ -1328,48 +1328,36 @@ client::rebalance_result client::rebalance() { rebalance_result result; size_t n = k_ + m_; // Step 1: Collect all unique group IDs across all nodes (unlocked for listing) std::set<uint64_t> all_groups; // Step 1: Collect group presence per node (N round trips total, not N×G) std::map<uint64_t, std::set<size_t>> group_nodes; // gid → set of node indices for (size_t i = 0; i < nodes_.size(); ++i) { std::vector<uint64_t> node_groups; if (list_groups_on_node(i, node_groups)) { all_groups.insert(node_groups.begin(), node_groups.end()); for (uint64_t gid : node_groups) group_nodes[gid].insert(i); } } if (all_groups.empty()) if (group_nodes.empty()) return result; std::cerr << "[PARITY] rebalance: " << all_groups.size() << " group(s) to check" << std::endl; std::cerr << "[PARITY] rebalance: " << group_nodes.size() << " group(s) to check" << std::endl; // Step 2: For each group, check block placement and re-store if misplaced for (uint64_t gid : all_groups) { // List blocks on each node for this group auto node_blocks = list(gid); // acquires mutex internally // Check if blocks are correctly placed: block_index % n == node_index bool misplaced = false; size_t total_blocks = 0; for (const auto& [node_idx, blocks] : node_blocks) { for (uint32_t bidx : blocks) { ++total_blocks; size_t expected_node = bidx % n; if (expected_node != node_idx) { misplaced = true; } } } // Also check: each node should have at most one block per stripe // and total blocks should be a multiple of n if (!misplaced && total_blocks > 0 && total_blocks % n == 0) { // Step 2: Groups present on all n nodes are likely OK — only do the // expensive per-block placement check for groups that aren't on all nodes. // This skips the costly list(gid) call for the majority of groups. std::vector<uint64_t> candidates; for (auto& [gid, nodes_set] : group_nodes) { if (nodes_set.size() >= n) { ++result.already_ok; continue; } else { candidates.push_back(gid); } } // Group needs rebalancing: retrieve → delete → re-store // Step 3: Fix misplaced / under-replicated groups for (uint64_t gid : candidates) { try { // Retrieve full data (parity decode handles misplaced blocks) auto data = retrieve(gid); if (data.empty()) { std::cerr << "[PARITY] rebalance: gid=" << gid Loading @@ -1378,10 +1366,7 @@ client::rebalance_result client::rebalance() { continue; } // Delete old (misplaced) blocks remove(gid); // Re-store with correct placement store(gid, data); ++result.rebalanced; Loading @@ -1394,7 +1379,7 @@ client::rebalance_result client::rebalance() { } } // Step 3: Vacuum all nodes to reclaim space from deleted blocks // Step 4: Vacuum all nodes to reclaim space from deleted blocks if (result.rebalanced > 0) vacuum_all_nodes(); Loading Loading
src/client.cpp +18 −33 Original line number Diff line number Diff line Loading @@ -1328,48 +1328,36 @@ client::rebalance_result client::rebalance() { rebalance_result result; size_t n = k_ + m_; // Step 1: Collect all unique group IDs across all nodes (unlocked for listing) std::set<uint64_t> all_groups; // Step 1: Collect group presence per node (N round trips total, not N×G) std::map<uint64_t, std::set<size_t>> group_nodes; // gid → set of node indices for (size_t i = 0; i < nodes_.size(); ++i) { std::vector<uint64_t> node_groups; if (list_groups_on_node(i, node_groups)) { all_groups.insert(node_groups.begin(), node_groups.end()); for (uint64_t gid : node_groups) group_nodes[gid].insert(i); } } if (all_groups.empty()) if (group_nodes.empty()) return result; std::cerr << "[PARITY] rebalance: " << all_groups.size() << " group(s) to check" << std::endl; std::cerr << "[PARITY] rebalance: " << group_nodes.size() << " group(s) to check" << std::endl; // Step 2: For each group, check block placement and re-store if misplaced for (uint64_t gid : all_groups) { // List blocks on each node for this group auto node_blocks = list(gid); // acquires mutex internally // Check if blocks are correctly placed: block_index % n == node_index bool misplaced = false; size_t total_blocks = 0; for (const auto& [node_idx, blocks] : node_blocks) { for (uint32_t bidx : blocks) { ++total_blocks; size_t expected_node = bidx % n; if (expected_node != node_idx) { misplaced = true; } } } // Also check: each node should have at most one block per stripe // and total blocks should be a multiple of n if (!misplaced && total_blocks > 0 && total_blocks % n == 0) { // Step 2: Groups present on all n nodes are likely OK — only do the // expensive per-block placement check for groups that aren't on all nodes. // This skips the costly list(gid) call for the majority of groups. std::vector<uint64_t> candidates; for (auto& [gid, nodes_set] : group_nodes) { if (nodes_set.size() >= n) { ++result.already_ok; continue; } else { candidates.push_back(gid); } } // Group needs rebalancing: retrieve → delete → re-store // Step 3: Fix misplaced / under-replicated groups for (uint64_t gid : candidates) { try { // Retrieve full data (parity decode handles misplaced blocks) auto data = retrieve(gid); if (data.empty()) { std::cerr << "[PARITY] rebalance: gid=" << gid Loading @@ -1378,10 +1366,7 @@ client::rebalance_result client::rebalance() { continue; } // Delete old (misplaced) blocks remove(gid); // Re-store with correct placement store(gid, data); ++result.rebalanced; Loading @@ -1394,7 +1379,7 @@ client::rebalance_result client::rebalance() { } } // Step 3: Vacuum all nodes to reclaim space from deleted blocks // Step 4: Vacuum all nodes to reclaim space from deleted blocks if (result.rebalanced > 0) vacuum_all_nodes(); Loading