@@ -88,7 +88,7 @@ public void testPartitionMetadataManagerProcessingThroughSegmentChangesSinglePar
88
88
89
89
SegmentPartitionMetadataManager partitionMetadataManager =
90
90
new SegmentPartitionMetadataManager (OFFLINE_TABLE_NAME , PARTITION_COLUMN , PARTITION_COLUMN_FUNC ,
91
- NUM_PARTITIONS );
91
+ NUM_PARTITIONS , false );
92
92
SegmentZkMetadataFetcher segmentZkMetadataFetcher =
93
93
new SegmentZkMetadataFetcher (OFFLINE_TABLE_NAME , _propertyStore );
94
94
segmentZkMetadataFetcher .register (partitionMetadataManager );
@@ -272,6 +272,191 @@ public void testPartitionMetadataManagerProcessingThroughSegmentChangesSinglePar
272
272
assertTrue (tablePartitionReplicatedServersInfo .getSegmentsWithInvalidPartition ().isEmpty ());
273
273
}
274
274
275
+ @ Test
276
+ public void testPartitionIdRemappingLogic () {
277
+ ExternalView externalView = new ExternalView (OFFLINE_TABLE_NAME );
278
+ Map <String , Map <String , String >> segmentAssignment = externalView .getRecord ().getMapFields ();
279
+ Map <String , String > onlineInstanceStateMap = ImmutableMap .of (SERVER_0 , ONLINE , SERVER_1 , ONLINE );
280
+ Set <String > onlineSegments = new HashSet <>();
281
+ IdealState idealState = new IdealState (OFFLINE_TABLE_NAME );
282
+
283
+ // Create partition metadata manager with remapping enabled (4 table partitions from 8 segment partitions)
284
+ SegmentPartitionMetadataManager partitionMetadataManager =
285
+ new SegmentPartitionMetadataManager (OFFLINE_TABLE_NAME , PARTITION_COLUMN , PARTITION_COLUMN_FUNC , 4 , true );
286
+ SegmentZkMetadataFetcher segmentZkMetadataFetcher =
287
+ new SegmentZkMetadataFetcher (OFFLINE_TABLE_NAME , _propertyStore );
288
+ segmentZkMetadataFetcher .register (partitionMetadataManager );
289
+
290
+ // Initial state should be empty
291
+ segmentZkMetadataFetcher .init (idealState , externalView , onlineSegments );
292
+ TablePartitionReplicatedServersInfo tablePartitionReplicatedServersInfo = partitionMetadataManager
293
+ .getTablePartitionReplicatedServersInfo ();
294
+ assertEquals (tablePartitionReplicatedServersInfo .getPartitionInfoMap (),
295
+ new TablePartitionReplicatedServersInfo .PartitionInfo [4 ]);
296
+
297
+ // Add segments with partition IDs 0, 4 (should both map to partition 0 via modulo)
298
+ String segment0 = "segment_partition_0" ;
299
+ String segment4 = "segment_partition_4" ;
300
+ onlineSegments .add (segment0 );
301
+ onlineSegments .add (segment4 );
302
+ segmentAssignment .put (segment0 , Collections .singletonMap (SERVER_0 , ONLINE ));
303
+ segmentAssignment .put (segment4 , Collections .singletonMap (SERVER_1 , ONLINE ));
304
+
305
+ // Set metadata for segments with 8 total partitions (will be remapped to 4)
306
+ setSegmentZKMetadata (segment0 , PARTITION_COLUMN_FUNC , 8 , 0 , 0L );
307
+ setSegmentZKMetadata (segment4 , PARTITION_COLUMN_FUNC , 8 , 4 , 0L );
308
+
309
+ segmentZkMetadataFetcher .onAssignmentChange (idealState , externalView , onlineSegments );
310
+ tablePartitionReplicatedServersInfo = partitionMetadataManager .getTablePartitionReplicatedServersInfo ();
311
+ TablePartitionReplicatedServersInfo .PartitionInfo [] partitionInfoMap = tablePartitionReplicatedServersInfo
312
+ .getPartitionInfoMap ();
313
+
314
+ // Both segments should be in partition 0 (0 % 4 = 0, 4 % 4 = 0)
315
+ assertNull (partitionInfoMap [1 ]);
316
+ assertNull (partitionInfoMap [2 ]);
317
+ assertNull (partitionInfoMap [3 ]);
318
+ // No single server has all segments in partition 0, so fullyReplicatedServers should be empty
319
+ assertTrue (partitionInfoMap [0 ]._fullyReplicatedServers .isEmpty ());
320
+ assertEqualsNoOrder (partitionInfoMap [0 ]._segments .toArray (), new String []{segment0 , segment4 });
321
+
322
+ // Add segments with partition IDs 1, 5 (should both map to partition 1)
323
+ String segment1 = "segment_partition_1" ;
324
+ String segment5 = "segment_partition_5" ;
325
+ onlineSegments .add (segment1 );
326
+ onlineSegments .add (segment5 );
327
+ segmentAssignment .put (segment1 , Collections .singletonMap (SERVER_0 , ONLINE ));
328
+ segmentAssignment .put (segment5 , Collections .singletonMap (SERVER_0 , ONLINE ));
329
+
330
+ setSegmentZKMetadata (segment1 , PARTITION_COLUMN_FUNC , 8 , 1 , 0L );
331
+ setSegmentZKMetadata (segment5 , PARTITION_COLUMN_FUNC , 8 , 5 , 0L );
332
+
333
+ segmentZkMetadataFetcher .onAssignmentChange (idealState , externalView , onlineSegments );
334
+ tablePartitionReplicatedServersInfo = partitionMetadataManager .getTablePartitionReplicatedServersInfo ();
335
+ partitionInfoMap = tablePartitionReplicatedServersInfo .getPartitionInfoMap ();
336
+
337
+ // Partition 1 should have both segments on SERVER_0, making it fully replicated
338
+ assertEquals (partitionInfoMap [1 ]._fullyReplicatedServers , Collections .singleton (SERVER_0 ));
339
+ assertEqualsNoOrder (partitionInfoMap [1 ]._segments .toArray (), new String []{segment1 , segment5 });
340
+
341
+ // Add segments with partition IDs 2, 6 (should both map to partition 2)
342
+ String segment2 = "segment_partition_2" ;
343
+ String segment6 = "segment_partition_6" ;
344
+ onlineSegments .add (segment2 );
345
+ onlineSegments .add (segment6 );
346
+ segmentAssignment .put (segment2 , ImmutableMap .of (SERVER_0 , ONLINE , SERVER_1 , ONLINE ));
347
+ segmentAssignment .put (segment6 , ImmutableMap .of (SERVER_0 , ONLINE , SERVER_1 , ONLINE ));
348
+
349
+ setSegmentZKMetadata (segment2 , PARTITION_COLUMN_FUNC , 8 , 2 , 0L );
350
+ setSegmentZKMetadata (segment6 , PARTITION_COLUMN_FUNC , 8 , 6 , 0L );
351
+
352
+ segmentZkMetadataFetcher .onAssignmentChange (idealState , externalView , onlineSegments );
353
+ tablePartitionReplicatedServersInfo = partitionMetadataManager .getTablePartitionReplicatedServersInfo ();
354
+ partitionInfoMap = tablePartitionReplicatedServersInfo .getPartitionInfoMap ();
355
+
356
+ // Partition 2 should have both segments on both servers, making both servers fully replicated
357
+ assertEquals (partitionInfoMap [2 ]._fullyReplicatedServers , ImmutableSet .of (SERVER_0 , SERVER_1 ));
358
+ assertEqualsNoOrder (partitionInfoMap [2 ]._segments .toArray (), new String []{segment2 , segment6 });
359
+
360
+ assertTrue (tablePartitionReplicatedServersInfo .getSegmentsWithInvalidPartition ().isEmpty ());
361
+ }
362
+
363
+ @ Test
364
+ public void testPartitionIdRemappingInvalidCases () {
365
+ ExternalView externalView = new ExternalView (OFFLINE_TABLE_NAME );
366
+ Map <String , Map <String , String >> segmentAssignment = externalView .getRecord ().getMapFields ();
367
+ Set <String > onlineSegments = new HashSet <>();
368
+ IdealState idealState = new IdealState (OFFLINE_TABLE_NAME );
369
+
370
+ // Create partition metadata manager with remapping enabled but invalid divisibility (3 table partitions from 8
371
+ // segment partitions)
372
+ SegmentPartitionMetadataManager partitionMetadataManager =
373
+ new SegmentPartitionMetadataManager (OFFLINE_TABLE_NAME , PARTITION_COLUMN , PARTITION_COLUMN_FUNC , 3 , true );
374
+ SegmentZkMetadataFetcher segmentZkMetadataFetcher =
375
+ new SegmentZkMetadataFetcher (OFFLINE_TABLE_NAME , _propertyStore );
376
+ segmentZkMetadataFetcher .register (partitionMetadataManager );
377
+
378
+ segmentZkMetadataFetcher .init (idealState , externalView , onlineSegments );
379
+
380
+ // Add segment with partition ID from 8-partition scheme (should be invalid because 8 % 3 != 0)
381
+ String invalidSegment = "invalid_segment" ;
382
+ onlineSegments .add (invalidSegment );
383
+ segmentAssignment .put (invalidSegment , Collections .singletonMap (SERVER_0 , ONLINE ));
384
+ setSegmentZKMetadata (invalidSegment , PARTITION_COLUMN_FUNC , 8 , 0 , 0L );
385
+
386
+ segmentZkMetadataFetcher .onAssignmentChange (idealState , externalView , onlineSegments );
387
+ TablePartitionReplicatedServersInfo tablePartitionReplicatedServersInfo = partitionMetadataManager
388
+ .getTablePartitionReplicatedServersInfo ();
389
+
390
+ // Segment should be marked as invalid due to non-divisible partition count
391
+ assertEquals (tablePartitionReplicatedServersInfo .getSegmentsWithInvalidPartition (),
392
+ Collections .singletonList (invalidSegment ));
393
+ assertEquals (tablePartitionReplicatedServersInfo .getPartitionInfoMap (),
394
+ new TablePartitionReplicatedServersInfo .PartitionInfo [3 ]);
395
+ }
396
+
397
+ @ Test
398
+ public void testPartitionIdRemappingDisabled () {
399
+ ExternalView externalView = new ExternalView (OFFLINE_TABLE_NAME );
400
+ Map <String , Map <String , String >> segmentAssignment = externalView .getRecord ().getMapFields ();
401
+ Set <String > onlineSegments = new HashSet <>();
402
+ IdealState idealState = new IdealState (OFFLINE_TABLE_NAME );
403
+
404
+ // Create partition metadata manager with remapping DISABLED (4 table partitions, remapping = false)
405
+ SegmentPartitionMetadataManager partitionMetadataManager =
406
+ new SegmentPartitionMetadataManager (OFFLINE_TABLE_NAME , PARTITION_COLUMN , PARTITION_COLUMN_FUNC , 4 , false );
407
+ SegmentZkMetadataFetcher segmentZkMetadataFetcher =
408
+ new SegmentZkMetadataFetcher (OFFLINE_TABLE_NAME , _propertyStore );
409
+ segmentZkMetadataFetcher .register (partitionMetadataManager );
410
+
411
+ segmentZkMetadataFetcher .init (idealState , externalView , onlineSegments );
412
+
413
+ // Add segment with matching partition count (4 partitions) - should be valid
414
+ String validSegment = "valid_segment" ;
415
+ onlineSegments .add (validSegment );
416
+ segmentAssignment .put (validSegment , Collections .singletonMap (SERVER_0 , ONLINE ));
417
+ setSegmentZKMetadata (validSegment , PARTITION_COLUMN_FUNC , 4 , 0 , 0L );
418
+
419
+ segmentZkMetadataFetcher .onAssignmentChange (idealState , externalView , onlineSegments );
420
+ TablePartitionReplicatedServersInfo tablePartitionReplicatedServersInfo = partitionMetadataManager
421
+ .getTablePartitionReplicatedServersInfo ();
422
+ TablePartitionReplicatedServersInfo .PartitionInfo [] partitionInfoMap = tablePartitionReplicatedServersInfo
423
+ .getPartitionInfoMap ();
424
+
425
+ // Valid segment should be placed in partition 0
426
+ assertEquals (partitionInfoMap [0 ]._fullyReplicatedServers , Collections .singleton (SERVER_0 ));
427
+ assertEquals (partitionInfoMap [0 ]._segments , Collections .singleton (validSegment ));
428
+ assertTrue (tablePartitionReplicatedServersInfo .getSegmentsWithInvalidPartition ().isEmpty ());
429
+
430
+ // Add segment with different partition count (8 partitions) - should be invalid when remapping is disabled
431
+ String invalidSegment = "invalid_segment_8_partitions" ;
432
+ onlineSegments .add (invalidSegment );
433
+ segmentAssignment .put (invalidSegment , Collections .singletonMap (SERVER_1 , ONLINE ));
434
+ setSegmentZKMetadata (invalidSegment , PARTITION_COLUMN_FUNC , 8 , 0 , 0L );
435
+
436
+ segmentZkMetadataFetcher .onAssignmentChange (idealState , externalView , onlineSegments );
437
+ tablePartitionReplicatedServersInfo = partitionMetadataManager .getTablePartitionReplicatedServersInfo ();
438
+ partitionInfoMap = tablePartitionReplicatedServersInfo .getPartitionInfoMap ();
439
+
440
+ // Invalid segment should be marked as invalid, valid segment should remain in partition 0
441
+ assertEquals (partitionInfoMap [0 ]._fullyReplicatedServers , Collections .singleton (SERVER_0 ));
442
+ assertEquals (partitionInfoMap [0 ]._segments , Collections .singleton (validSegment ));
443
+ assertEquals (tablePartitionReplicatedServersInfo .getSegmentsWithInvalidPartition (),
444
+ Collections .singletonList (invalidSegment ));
445
+
446
+ // Add another segment with different partition count (2 partitions) - should also be invalid
447
+ String invalidSegment2 = "invalid_segment_2_partitions" ;
448
+ onlineSegments .add (invalidSegment2 );
449
+ segmentAssignment .put (invalidSegment2 , Collections .singletonMap (SERVER_0 , ONLINE ));
450
+ setSegmentZKMetadata (invalidSegment2 , PARTITION_COLUMN_FUNC , 2 , 0 , 0L );
451
+
452
+ segmentZkMetadataFetcher .onAssignmentChange (idealState , externalView , onlineSegments );
453
+ tablePartitionReplicatedServersInfo = partitionMetadataManager .getTablePartitionReplicatedServersInfo ();
454
+
455
+ // Both invalid segments should be marked as invalid
456
+ assertEqualsNoOrder (tablePartitionReplicatedServersInfo .getSegmentsWithInvalidPartition ().toArray (),
457
+ new String []{invalidSegment , invalidSegment2 });
458
+ }
459
+
275
460
private void setSegmentZKMetadata (String segment , String partitionFunction , int numPartitions , int partitionId ,
276
461
long creationTimeMs ) {
277
462
SegmentZKMetadata segmentZKMetadata = new SegmentZKMetadata (segment );
0 commit comments