Skip to content

Commit 7ebffd0

Browse files
vj-menonmeta-codesync[bot]
authored andcommitted
Honor specialFastColdContainer field in SingleChainFastMoveType
Summary: `SINGLE_CHAIN_FAST` was ignoring its `specialFastColdContainer` parameter. Even with a fixed cold container configured, the hot object could still move to any container. Root cause is that `findBestMove()` built its own cold-container set from all containers and never called `getCustomColdContainers()`, the base-class function that applies the special cold container. We fix this by seeding the cold set from `getCustomColdContainers()`, the same way the base type does. We also forward the fast spec's partition name and `specialFastColdContainer` into the base `SingleChainMoveTypeSpec`, so the fast type reuses the base machinery and no longer needs its own members or overrides. `specialFastColdContainer` is not being used by any use case currently and this is likely we didn't see this bug before. Reviewed By: polmauri Differential Revision: D112341411 fbshipit-source-id: 53f74636e684de15e351960247a0ee1e6f4fb540
1 parent 5122e61 commit 7ebffd0

3 files changed

Lines changed: 54 additions & 20 deletions

File tree

algopt/rebalancer/solver/moves/SingleChainFastMoveType.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,25 @@
2121

2222
namespace facebook::rebalancer {
2323

24+
namespace {
25+
interface::SingleChainMoveTypeSpec toSingleChainMoveTypeSpec(
26+
const interface::SingleChainFastMoveTypeSpec& spec) {
27+
interface::SingleChainMoveTypeSpec baseSpec;
28+
baseSpec.partitionNameToExploreChainsWithinObjectGroup().copy_from(
29+
spec.partitionNameToExploreFastChainsWithinObjectGroup());
30+
baseSpec.specialColdContainer().copy_from(spec.specialFastColdContainer());
31+
return baseSpec;
32+
}
33+
} // namespace
34+
2435
std::string SingleChainFastMoveType::name() const {
2536
return kSingleChainFastMoveTypeName.str();
2637
}
2738

2839
SingleChainFastMoveType::SingleChainFastMoveType(
2940
const interface::LocalSearchSolverSpec& solverConfigs,
3041
const interface::SingleChainFastMoveTypeSpec& spec)
31-
: SingleChainMoveType(solverConfigs, interface::SingleChainMoveTypeSpec()) {
32-
partitionNameToExploreFastChainsWithinObjectGroup_ =
33-
spec.partitionNameToExploreFastChainsWithinObjectGroup().to_optional();
34-
specialFastColdContainer_ = spec.specialFastColdContainer().to_optional();
35-
}
42+
: SingleChainMoveType(solverConfigs, toSingleChainMoveTypeSpec(spec)) {}
3643

3744
MoveResult SingleChainFastMoveType::findBestMove(
3845
const MovesEvaluator& evaluator,
@@ -45,8 +52,10 @@ MoveResult SingleChainFastMoveType::findBestMove(
4552
const ObjectDeduper dedupedObjs(
4653
&problem.getEquivalenceSets(), dynamicObjects);
4754

55+
const auto customColdContainers =
56+
getCustomColdContainers(evaluator, hotContainer);
4857
auto coldContainers = Filter(
49-
problem.containers,
58+
customColdContainers ? *customColdContainers : problem.containers,
5059
[&problem, hotContainer](entities::ContainerId container) {
5160
return container != hotContainer &&
5261
!problem.not_accepting_containers.contains(container);

algopt/rebalancer/solver/moves/SingleChainFastMoveType.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,6 @@ class SingleChainFastMoveType : public SingleChainMoveType {
5151
MoveStatsAggregator& stats,
5252
const SearchHints& hints,
5353
double timeLimit) override;
54-
55-
protected:
56-
std::optional<std::string> getPartitionNameToExploreChainsWithinObjectGroup()
57-
const override {
58-
return partitionNameToExploreFastChainsWithinObjectGroup_;
59-
}
60-
std::optional<std::string> getSpecialColdContainer() const override {
61-
return specialFastColdContainer_;
62-
}
63-
64-
private:
65-
std::optional<std::string>
66-
partitionNameToExploreFastChainsWithinObjectGroup_ = std::nullopt;
67-
std::optional<std::string> specialFastColdContainer_ = std::nullopt;
6854
};
6955

7056
} // namespace facebook::rebalancer

algopt/rebalancer/solver/moves/tests/SingleChainFastMoveTypeTest.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <folly/coro/BlockingWait.h>
2424
#include <gtest/gtest.h>
2525

26+
#include <limits>
27+
2628
namespace facebook::rebalancer::packer::tests {
2729

2830
class MockSingleChainFastMoveType : public SingleChainFastMoveType {
@@ -291,6 +293,43 @@ CO_TEST_F(SingleChainFastMoveTypeTest, TestTotalNumberOfEvaluations) {
291293
EXPECT_EQ(8, getTotalMovesEvaluated());
292294
}
293295

296+
// specialFastColdContainer should send the hot object only to that cold
297+
// container, so setting it should evaluate fewer moves. The const-0 objective
298+
// makes all objects equal, so no move improves (nothing is skipped early) and
299+
// each container counts as one object. A chain is 2 moves: the hot object goes
300+
// to a cold container, and one object from another container moves into the hot
301+
// container.
302+
CO_TEST_F(
303+
SingleChainFastMoveTypeTest,
304+
FindBestMoveHonorsSpecialFastColdContainer) {
305+
const auto universe = co_await setUpUniverse();
306+
createProblem({const_expr(0, *universe)}, const_expr(0, *universe));
307+
308+
const auto movesEvaluated =
309+
[&](const interface::SingleChainFastMoveTypeSpec& spec) {
310+
MockSingleChainFastMoveType(interface::LocalSearchSolverSpec{}, spec)
311+
.findBestMove(
312+
getMovesEvaluator(),
313+
container(1) /*hotContainer*/,
314+
getMoveStatsAggregator(),
315+
getEmptySearchHints(),
316+
std::numeric_limits<double>::max() /*timeLimit*/);
317+
return getTotalMovesEvaluated();
318+
};
319+
320+
interface::SingleChainFastMoveTypeSpec restricted;
321+
restricted.specialFastColdContainer() = "region2";
322+
323+
// Cold containers {region2, region3, region4}; region2 is empty:
324+
// into region2: from region3 and region4 = 2 chains = 4 moves
325+
// into region3: from region4 = 1 chain = 2 moves
326+
// into region4: from region3 = 1 chain = 2 moves
327+
EXPECT_EQ(8, movesEvaluated(interface::SingleChainFastMoveTypeSpec{}));
328+
329+
// Restricting to region2 keeps only the first line: 4 moves.
330+
EXPECT_EQ(4, movesEvaluated(restricted));
331+
}
332+
294333
TEST_F(SingleChainFastMoveTypeTest, Name) {
295334
auto mockSingleChainFastMoveType = MockSingleChainFastMoveType(
296335
interface::LocalSearchSolverSpec{},

0 commit comments

Comments
 (0)