@@ -805,4 +805,35 @@ mod tests {
805
805
806
806
assert_eq ! ( solution. capacity_scaling_iterations, 1 ) ;
807
807
}
808
+
809
+ #[ test]
810
+ fn test_shard_fragmentation_when_iterating ( ) {
811
+ // Create a problem where affinity constraints cause suboptimal placement
812
+ // requiring iterative scaling despite initial capacity scaling.
813
+ let mut problem =
814
+ SchedulingProblem :: with_indexer_cpu_capacities ( vec ! [ mcpu( 3000 ) , mcpu( 3000 ) ] ) ;
815
+ problem. add_source ( 1 , NonZeroU32 :: new ( 1000 ) . unwrap ( ) ) ;
816
+ problem. add_source ( 1 , NonZeroU32 :: new ( 1000 ) . unwrap ( ) ) ;
817
+ problem. add_source ( 1 , NonZeroU32 :: new ( 1000 ) . unwrap ( ) ) ;
818
+ let empty_solution = problem. new_solution ( ) ;
819
+ let first_solution = solve ( problem, empty_solution) ;
820
+
821
+ let mut updated_problem =
822
+ SchedulingProblem :: with_indexer_cpu_capacities ( vec ! [ mcpu( 3000 ) , mcpu( 3000 ) ] ) ;
823
+ updated_problem. add_source ( 2 , NonZeroU32 :: new ( 1000 ) . unwrap ( ) ) ;
824
+ updated_problem. add_source ( 2 , NonZeroU32 :: new ( 1000 ) . unwrap ( ) ) ;
825
+ updated_problem. add_source ( 2 , NonZeroU32 :: new ( 1000 ) . unwrap ( ) ) ;
826
+
827
+ let second_solution = solve ( updated_problem, first_solution) ;
828
+
829
+ for source in 0 ..2 {
830
+ let num_shards_per_indexer = second_solution
831
+ . indexer_assignments
832
+ . iter ( )
833
+ . map ( |indexer_assignment| indexer_assignment. num_shards ( source) )
834
+ . collect_vec ( ) ;
835
+ assert ! ( num_shards_per_indexer. contains( & 2 ) ) ;
836
+ assert ! ( num_shards_per_indexer. contains( & 0 ) ) ;
837
+ }
838
+ }
808
839
}
0 commit comments