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