@@ -242,6 +242,7 @@ fn attempt_place_unassigned_shards(
242
242
place_unassigned_shards_single_source (
243
243
source,
244
244
indexers_with_most_available_capacity,
245
+ problem. num_indexers ( ) ,
245
246
& mut solution,
246
247
) ?;
247
248
}
@@ -278,6 +279,7 @@ fn place_unassigned_shards_with_affinity(
278
279
let _ = place_unassigned_shards_single_source (
279
280
source,
280
281
indexers_with_affinity_and_available_capacity,
282
+ problem. num_indexers ( ) ,
281
283
solution,
282
284
) ;
283
285
}
@@ -349,15 +351,28 @@ struct NotEnoughCapacity;
349
351
fn place_unassigned_shards_single_source (
350
352
source : & Source ,
351
353
mut indexer_with_capacities : impl Iterator < Item = ( IndexerOrd , CpuCapacity ) > ,
354
+ num_indexers : usize ,
352
355
solution : & mut SchedulingSolution ,
353
356
) -> Result < ( ) , NotEnoughCapacity > {
354
357
let mut num_shards = source. num_shards ;
358
+ // To ensure that merges can keep up, try not to assign more than 3
359
+ // shards per indexer for a source (except if there aren't enough nodes)
360
+ let limit_num_shards_per_indexer_per_source = 3 . max ( num_shards. div_ceil ( num_indexers as u32 ) ) ;
355
361
while num_shards > 0 {
356
362
let Some ( ( indexer_ord, available_capacity) ) = indexer_with_capacities. next ( ) else {
357
363
return Err ( NotEnoughCapacity ) ;
358
364
} ;
359
- let num_placable_shards = available_capacity. cpu_millis ( ) / source. load_per_shard ;
360
- let num_shards_to_place = num_placable_shards. min ( num_shards) ;
365
+ let current_num_shards_for_indexer_and_source = * solution. indexer_assignments [ indexer_ord]
366
+ . num_shards_per_source
367
+ . get ( & source. source_ord )
368
+ . unwrap_or ( & 0 ) ;
369
+ let num_placable_shards_for_available_capacity =
370
+ available_capacity. cpu_millis ( ) / source. load_per_shard ;
371
+ let num_placable_shards_for_limit = limit_num_shards_per_indexer_per_source
372
+ . saturating_sub ( current_num_shards_for_indexer_and_source) ;
373
+ let num_shards_to_place = num_shards
374
+ . min ( num_placable_shards_for_available_capacity)
375
+ . min ( num_placable_shards_for_limit) ;
361
376
// Update the solution, the shard load, and the number of shards to place.
362
377
solution. indexer_assignments [ indexer_ord]
363
378
. add_shards ( source. source_ord , num_shards_to_place) ;
@@ -593,11 +608,15 @@ mod tests {
593
608
problem. add_source ( 4 , NonZeroU32 :: new ( 1_000 ) . unwrap ( ) ) ;
594
609
problem. add_source ( 4 , NonZeroU32 :: new ( 1_000 ) . unwrap ( ) ) ;
595
610
problem. inc_affinity ( 0 , 1 ) ;
611
+ problem. inc_affinity ( 0 , 1 ) ;
612
+ problem. inc_affinity ( 0 , 0 ) ;
596
613
problem. inc_affinity ( 1 , 0 ) ;
597
614
let mut solution = problem. new_solution ( ) ;
598
615
place_unassigned_shards_with_affinity ( & problem, & mut solution) ;
599
- assert_eq ! ( solution. indexer_assignments[ 0 ] . num_shards( 1 ) , 4 ) ;
600
- assert_eq ! ( solution. indexer_assignments[ 1 ] . num_shards( 0 ) , 4 ) ;
616
+ assert_eq ! ( solution. indexer_assignments[ 0 ] . num_shards( 1 ) , 3 ) ;
617
+ assert_eq ! ( solution. indexer_assignments[ 0 ] . num_shards( 0 ) , 1 ) ;
618
+ assert_eq ! ( solution. indexer_assignments[ 1 ] . num_shards( 0 ) , 3 ) ;
619
+ assert_eq ! ( solution. indexer_assignments[ 1 ] . num_shards( 1 ) , 0 ) ;
601
620
}
602
621
603
622
#[ test]
0 commit comments