|
12 | 12 | import org.opensearch.ExceptionsHelper;
|
13 | 13 | import org.opensearch.OpenSearchException;
|
14 | 14 | import org.opensearch.Version;
|
| 15 | +import org.opensearch.cluster.ClusterChangedEvent; |
| 16 | +import org.opensearch.cluster.ClusterName; |
15 | 17 | import org.opensearch.cluster.ClusterState;
|
16 | 18 | import org.opensearch.cluster.metadata.IndexMetadata;
|
17 | 19 | import org.opensearch.cluster.node.DiscoveryNode;
|
18 | 20 | import org.opensearch.cluster.node.DiscoveryNodes;
|
| 21 | +import org.opensearch.cluster.routing.IndexRoutingTable; |
| 22 | +import org.opensearch.cluster.routing.RecoverySource; |
19 | 23 | import org.opensearch.cluster.routing.RoutingTable;
|
| 24 | +import org.opensearch.cluster.routing.ShardRouting; |
| 25 | +import org.opensearch.cluster.routing.ShardRoutingState; |
| 26 | +import org.opensearch.cluster.routing.UnassignedInfo; |
20 | 27 | import org.opensearch.cluster.service.ClusterService;
|
21 | 28 | import org.opensearch.common.settings.ClusterSettings;
|
22 | 29 | import org.opensearch.common.settings.Settings;
|
23 | 30 | import org.opensearch.common.util.CancellableThreads;
|
24 | 31 | import org.opensearch.core.action.ActionListener;
|
25 | 32 | import org.opensearch.core.index.shard.ShardId;
|
26 | 33 | import org.opensearch.core.transport.TransportResponse;
|
| 34 | +import org.opensearch.index.IndexService; |
27 | 35 | import org.opensearch.index.engine.NRTReplicationEngineFactory;
|
28 | 36 | import org.opensearch.index.replication.TestReplicationSource;
|
29 | 37 | import org.opensearch.index.shard.IndexShard;
|
|
51 | 59 | import java.io.IOException;
|
52 | 60 | import java.util.Collections;
|
53 | 61 | import java.util.List;
|
| 62 | +import java.util.Set; |
54 | 63 | import java.util.concurrent.CountDownLatch;
|
55 | 64 | import java.util.concurrent.TimeUnit;
|
56 | 65 | import java.util.function.BiConsumer;
|
@@ -91,6 +100,8 @@ public class SegmentReplicationTargetServiceTests extends IndexShardTestCase {
|
91 | 100 | private SegmentReplicationState state;
|
92 | 101 | private ReplicationCheckpoint initialCheckpoint;
|
93 | 102 |
|
| 103 | + private ClusterState clusterState; |
| 104 | + |
94 | 105 | private static final long TRANSPORT_TIMEOUT = 30000;// 30sec
|
95 | 106 |
|
96 | 107 | @Override
|
@@ -129,7 +140,7 @@ public void setUp() throws Exception {
|
129 | 140 |
|
130 | 141 | indicesService = mock(IndicesService.class);
|
131 | 142 | ClusterService clusterService = mock(ClusterService.class);
|
132 |
| - ClusterState clusterState = mock(ClusterState.class); |
| 143 | + clusterState = mock(ClusterState.class); |
133 | 144 | RoutingTable mockRoutingTable = mock(RoutingTable.class);
|
134 | 145 | when(clusterService.state()).thenReturn(clusterState);
|
135 | 146 | when(clusterState.routingTable()).thenReturn(mockRoutingTable);
|
@@ -465,9 +476,22 @@ public void testStartReplicationListenerFailure() throws InterruptedException {
|
465 | 476 | verify(spy, (never())).updateVisibleCheckpoint(eq(0L), eq(replicaShard));
|
466 | 477 | }
|
467 | 478 |
|
468 |
| - public void testDoNotProcessLatestCheckpointIfItIsbehind() { |
469 |
| - sut.updateLatestReceivedCheckpoint(replicaShard.getLatestReplicationCheckpoint(), replicaShard); |
470 |
| - assertFalse(sut.processLatestReceivedCheckpoint(replicaShard, null)); |
| 479 | + public void testDoNotProcessLatestCheckpointIfCheckpointIsBehind() { |
| 480 | + SegmentReplicationTargetService service = spy(sut); |
| 481 | + doReturn(mock(SegmentReplicationTarget.class)).when(service).startReplication(any(), any(), any()); |
| 482 | + ReplicationCheckpoint checkpoint = replicaShard.getLatestReplicationCheckpoint(); |
| 483 | + service.updateLatestReceivedCheckpoint(checkpoint, replicaShard); |
| 484 | + service.processLatestReceivedCheckpoint(replicaShard, null); |
| 485 | + verify(service, times(0)).startReplication(eq(replicaShard), eq(checkpoint), any()); |
| 486 | + } |
| 487 | + |
| 488 | + public void testProcessLatestCheckpointIfCheckpointAhead() { |
| 489 | + SegmentReplicationTargetService service = spy(sut); |
| 490 | + doNothing().when(service).startReplication(any()); |
| 491 | + doReturn(mock(SegmentReplicationTarget.class)).when(service).startReplication(any(), any(), any()); |
| 492 | + service.updateLatestReceivedCheckpoint(aheadCheckpoint, replicaShard); |
| 493 | + service.processLatestReceivedCheckpoint(replicaShard, null); |
| 494 | + verify(service, times(1)).startReplication(eq(replicaShard), eq(aheadCheckpoint), any()); |
471 | 495 | }
|
472 | 496 |
|
473 | 497 | public void testOnNewCheckpointInvokedOnClosedShardDoesNothing() throws IOException {
|
@@ -617,4 +641,46 @@ public void onReplicationFailure(SegmentReplicationState state, ReplicationFaile
|
617 | 641 | target.cancel("test");
|
618 | 642 | sut.startReplication(target);
|
619 | 643 | }
|
| 644 | + |
| 645 | + public void testProcessCheckpointOnClusterStateUpdate() { |
| 646 | + // set up mocks on indicies & index service to return our replica's index & shard. |
| 647 | + IndexService indexService = mock(IndexService.class); |
| 648 | + when(indexService.iterator()).thenReturn(Set.of(replicaShard).iterator()); |
| 649 | + when(indexService.getIndexSettings()).thenReturn(replicaShard.indexSettings()); |
| 650 | + when(indexService.index()).thenReturn(replicaShard.routingEntry().index()); |
| 651 | + when(indicesService.iterator()).thenReturn(Set.of(indexService).iterator()); |
| 652 | + |
| 653 | + // create old & new cluster states |
| 654 | + final String targetNodeId = "targetNodeId"; |
| 655 | + ShardRouting initialRouting = primaryShard.routingEntry().relocate(targetNodeId, 0L); |
| 656 | + assertEquals(ShardRoutingState.RELOCATING, initialRouting.state()); |
| 657 | + |
| 658 | + ShardRouting targetRouting = ShardRouting.newUnassigned( |
| 659 | + primaryShard.shardId(), |
| 660 | + true, |
| 661 | + RecoverySource.PeerRecoverySource.INSTANCE, |
| 662 | + new UnassignedInfo(UnassignedInfo.Reason.REINITIALIZED, "test") |
| 663 | + ).initialize(targetNodeId, initialRouting.allocationId().getId(), 0L).moveToStarted(); |
| 664 | + assertEquals(targetNodeId, targetRouting.currentNodeId()); |
| 665 | + assertEquals(ShardRoutingState.STARTED, targetRouting.state()); |
| 666 | + ClusterState oldState = ClusterState.builder(ClusterName.DEFAULT) |
| 667 | + .routingTable( |
| 668 | + RoutingTable.builder() |
| 669 | + .add(IndexRoutingTable.builder(primaryShard.shardId().getIndex()).addShard(initialRouting).build()) |
| 670 | + .build() |
| 671 | + ) |
| 672 | + .build(); |
| 673 | + ClusterState newState = ClusterState.builder(ClusterName.DEFAULT) |
| 674 | + .routingTable( |
| 675 | + RoutingTable.builder() |
| 676 | + .add(IndexRoutingTable.builder(primaryShard.shardId().getIndex()).addShard(targetRouting).build()) |
| 677 | + .build() |
| 678 | + ) |
| 679 | + .build(); |
| 680 | + |
| 681 | + // spy so we can verify process is invoked |
| 682 | + SegmentReplicationTargetService spy = spy(sut); |
| 683 | + spy.clusterChanged(new ClusterChangedEvent("ignored", oldState, newState)); |
| 684 | + verify(spy, times(1)).processLatestReceivedCheckpoint(eq(replicaShard), any()); |
| 685 | + } |
620 | 686 | }
|
0 commit comments