@@ -340,35 +340,35 @@ public Builder(Index index) {
340
340
* Initializes a new empty index, as if it was created from an API.
341
341
*/
342
342
public Builder initializeAsNew (IndexMetadata indexMetadata ) {
343
- return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .INDEX_CREATED , null ));
343
+ return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .INDEX_CREATED , null ), null );
344
344
}
345
345
346
346
/**
347
347
* Initializes an existing index.
348
348
*/
349
349
public Builder initializeAsRecovery (IndexMetadata indexMetadata ) {
350
- return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .CLUSTER_RECOVERED , null ));
350
+ return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .CLUSTER_RECOVERED , null ), null );
351
351
}
352
352
353
353
/**
354
354
* Initializes a new index caused by dangling index imported.
355
355
*/
356
356
public Builder initializeAsFromDangling (IndexMetadata indexMetadata ) {
357
- return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .DANGLING_INDEX_IMPORTED , null ));
357
+ return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .DANGLING_INDEX_IMPORTED , null ), null );
358
358
}
359
359
360
360
/**
361
361
* Initializes a new empty index, as a result of opening a closed index.
362
362
*/
363
- public Builder initializeAsFromCloseToOpen (IndexMetadata indexMetadata ) {
364
- return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .INDEX_REOPENED , null ));
363
+ public Builder initializeAsFromCloseToOpen (IndexMetadata indexMetadata , IndexRoutingTable indexRoutingTable ) {
364
+ return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .INDEX_REOPENED , null ), indexRoutingTable );
365
365
}
366
366
367
367
/**
368
368
* Initializes a new empty index, as a result of closing an opened index.
369
369
*/
370
- public Builder initializeAsFromOpenToClose (IndexMetadata indexMetadata ) {
371
- return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .INDEX_CLOSED , null ));
370
+ public Builder initializeAsFromOpenToClose (IndexMetadata indexMetadata , IndexRoutingTable indexRoutingTable ) {
371
+ return initializeEmpty (indexMetadata , new UnassignedInfo (UnassignedInfo .Reason .INDEX_CLOSED , null ), indexRoutingTable );
372
372
}
373
373
374
374
/**
@@ -387,13 +387,17 @@ public Builder initializeAsNewRestore(
387
387
+ recoverySource .snapshot ().getSnapshotId ().getName ()
388
388
+ "]"
389
389
);
390
- return initializeAsRestore (indexMetadata , recoverySource , ignoreShards , true , unassignedInfo );
390
+ return initializeAsRestore (indexMetadata , recoverySource , ignoreShards , true , unassignedInfo , null );
391
391
}
392
392
393
393
/**
394
394
* Initializes an existing index, to be restored from a snapshot
395
395
*/
396
- public Builder initializeAsRestore (IndexMetadata indexMetadata , SnapshotRecoverySource recoverySource ) {
396
+ public Builder initializeAsRestore (
397
+ IndexMetadata indexMetadata ,
398
+ SnapshotRecoverySource recoverySource ,
399
+ IndexRoutingTable previousIndexRoutingTable
400
+ ) {
397
401
final UnassignedInfo unassignedInfo = new UnassignedInfo (
398
402
UnassignedInfo .Reason .EXISTING_INDEX_RESTORED ,
399
403
"restore_source["
@@ -402,7 +406,7 @@ public Builder initializeAsRestore(IndexMetadata indexMetadata, SnapshotRecovery
402
406
+ recoverySource .snapshot ().getSnapshotId ().getName ()
403
407
+ "]"
404
408
);
405
- return initializeAsRestore (indexMetadata , recoverySource , null , false , unassignedInfo );
409
+ return initializeAsRestore (indexMetadata , recoverySource , null , false , unassignedInfo , previousIndexRoutingTable );
406
410
}
407
411
408
412
/**
@@ -413,7 +417,8 @@ private Builder initializeAsRestore(
413
417
SnapshotRecoverySource recoverySource ,
414
418
Set <Integer > ignoreShards ,
415
419
boolean asNew ,
416
- UnassignedInfo unassignedInfo
420
+ UnassignedInfo unassignedInfo ,
421
+ @ Nullable IndexRoutingTable previousIndexRoutingTable
417
422
) {
418
423
assert indexMetadata .getIndex ().equals (index );
419
424
if (shards != null ) {
@@ -422,6 +427,7 @@ private Builder initializeAsRestore(
422
427
shards = new IndexShardRoutingTable .Builder [indexMetadata .getNumberOfShards ()];
423
428
for (int shardNumber = 0 ; shardNumber < indexMetadata .getNumberOfShards (); shardNumber ++) {
424
429
ShardId shardId = new ShardId (index , shardNumber );
430
+ final var previousNodes = getPreviousNodes (previousIndexRoutingTable , shardNumber );
425
431
IndexShardRoutingTable .Builder indexShardRoutingBuilder = IndexShardRoutingTable .builder (shardId );
426
432
for (int i = 0 ; i <= indexMetadata .getNumberOfReplicas (); i ++) {
427
433
boolean primary = i == 0 ;
@@ -441,7 +447,7 @@ private Builder initializeAsRestore(
441
447
shardId ,
442
448
primary ,
443
449
primary ? recoverySource : PeerRecoverySource .INSTANCE ,
444
- unassignedInfo
450
+ withLastAllocatedNodeId ( unassignedInfo , previousNodes , i )
445
451
)
446
452
);
447
453
}
@@ -454,14 +460,20 @@ private Builder initializeAsRestore(
454
460
/**
455
461
* Initializes a new empty index, with an option to control if its from an API or not.
456
462
*/
457
- private Builder initializeEmpty (IndexMetadata indexMetadata , UnassignedInfo unassignedInfo ) {
463
+ private Builder initializeEmpty (
464
+ IndexMetadata indexMetadata ,
465
+ UnassignedInfo unassignedInfo ,
466
+ @ Nullable IndexRoutingTable previousIndexRoutingTable
467
+ ) {
458
468
assert indexMetadata .getIndex ().equals (index );
469
+ assert previousIndexRoutingTable == null || previousIndexRoutingTable .size () == indexMetadata .getNumberOfShards ();
459
470
if (shards != null ) {
460
471
throw new IllegalStateException ("trying to initialize an index with fresh shards, but already has shards created" );
461
472
}
462
473
shards = new IndexShardRoutingTable .Builder [indexMetadata .getNumberOfShards ()];
463
474
for (int shardNumber = 0 ; shardNumber < indexMetadata .getNumberOfShards (); shardNumber ++) {
464
475
ShardId shardId = new ShardId (index , shardNumber );
476
+ final var previousNodes = getPreviousNodes (previousIndexRoutingTable , shardNumber );
465
477
final RecoverySource primaryRecoverySource ;
466
478
if (indexMetadata .inSyncAllocationIds (shardNumber ).isEmpty () == false ) {
467
479
// we have previous valid copies for this shard. use them for recovery
@@ -481,7 +493,7 @@ private Builder initializeEmpty(IndexMetadata indexMetadata, UnassignedInfo unas
481
493
shardId ,
482
494
primary ,
483
495
primary ? primaryRecoverySource : PeerRecoverySource .INSTANCE ,
484
- unassignedInfo
496
+ withLastAllocatedNodeId ( unassignedInfo , previousNodes , i )
485
497
)
486
498
);
487
499
}
@@ -490,6 +502,50 @@ private Builder initializeEmpty(IndexMetadata indexMetadata, UnassignedInfo unas
490
502
return this ;
491
503
}
492
504
505
+ private static List <String > getPreviousNodes (@ Nullable IndexRoutingTable previousIndexRoutingTable , int shardId ) {
506
+ if (previousIndexRoutingTable == null ) {
507
+ return null ;
508
+ }
509
+ final var previousShardRoutingTable = previousIndexRoutingTable .shard (shardId );
510
+ if (previousShardRoutingTable == null ) {
511
+ return null ;
512
+ }
513
+ final var primaryNodeId = previousShardRoutingTable .primaryShard ().currentNodeId ();
514
+ if (primaryNodeId == null ) {
515
+ return null ;
516
+ }
517
+ final var previousNodes = new ArrayList <String >(previousShardRoutingTable .size ());
518
+ previousNodes .add (primaryNodeId ); // primary is recreated first, so re-use its location
519
+ for (final var assignedShard : previousShardRoutingTable .assignedShards ()) {
520
+ if (assignedShard .initializing () && assignedShard .relocatingNodeId () != null ) {
521
+ continue ;
522
+ }
523
+ final var currentNodeId = assignedShard .currentNodeId ();
524
+ assert currentNodeId != null ;
525
+ if (primaryNodeId .equals (currentNodeId ) == false ) {
526
+ previousNodes .add (currentNodeId );
527
+ }
528
+ }
529
+ return previousNodes ;
530
+ }
531
+
532
+ private static UnassignedInfo withLastAllocatedNodeId (UnassignedInfo unassignedInfo , List <String > previousNodes , int shardCopy ) {
533
+ return previousNodes == null || previousNodes .size () <= shardCopy
534
+ ? unassignedInfo
535
+ : new UnassignedInfo (
536
+ unassignedInfo .getReason (),
537
+ unassignedInfo .getMessage (),
538
+ unassignedInfo .getFailure (),
539
+ unassignedInfo .getNumFailedAllocations (),
540
+ unassignedInfo .getUnassignedTimeInNanos (),
541
+ unassignedInfo .getUnassignedTimeInMillis (),
542
+ unassignedInfo .isDelayed (),
543
+ unassignedInfo .getLastAllocationStatus (),
544
+ unassignedInfo .getFailedNodeIds (),
545
+ previousNodes .get (shardCopy )
546
+ );
547
+ }
548
+
493
549
public Builder addReplica () {
494
550
assert shards != null ;
495
551
for (IndexShardRoutingTable .Builder existing : shards ) {
0 commit comments