|
14 | 14 | import org.opensearch.cluster.metadata.IndexMetadata; |
15 | 15 | import org.opensearch.cluster.routing.ShardRouting; |
16 | 16 | import org.opensearch.common.settings.Settings; |
| 17 | +import org.opensearch.common.unit.TimeValue; |
17 | 18 | import org.opensearch.core.action.ActionListener; |
18 | 19 | import org.opensearch.index.engine.InternalEngineFactory; |
19 | 20 | import org.opensearch.index.engine.NRTReplicationEngineFactory; |
20 | 21 | import org.opensearch.index.replication.OpenSearchIndexLevelReplicationTestCase; |
21 | 22 | import org.opensearch.index.shard.IndexShard; |
22 | 23 | import org.opensearch.index.shard.IndexShardState; |
23 | | -import org.opensearch.index.shard.RemoteStoreRefreshListenerTests; |
| 24 | +import org.opensearch.index.shard.RemoteStoreRefreshListenerTests.TestFilterDirectory; |
24 | 25 | import org.opensearch.index.store.RemoteSegmentStoreDirectory; |
| 26 | +import org.opensearch.index.store.RemoteSegmentStoreDirectory.UploadedSegmentMetadata; |
25 | 27 | import org.opensearch.index.store.Store; |
26 | 28 | import org.opensearch.index.store.StoreFileMetadata; |
| 29 | +import org.opensearch.indices.recovery.RecoverySettings; |
27 | 30 | import org.opensearch.indices.replication.checkpoint.MergedSegmentCheckpoint; |
28 | 31 | import org.opensearch.indices.replication.checkpoint.RemoteStoreMergedSegmentCheckpoint; |
29 | 32 | import org.opensearch.indices.replication.checkpoint.ReplicationCheckpoint; |
|
38 | 41 | import java.util.Map; |
39 | 42 | import java.util.concurrent.CountDownLatch; |
40 | 43 | import java.util.concurrent.ExecutionException; |
| 44 | +import java.util.concurrent.TimeoutException; |
41 | 45 | import java.util.concurrent.atomic.AtomicReference; |
42 | 46 | import java.util.stream.Collectors; |
43 | 47 |
|
44 | 48 | import static org.mockito.Mockito.mock; |
| 49 | +import static org.mockito.Mockito.spy; |
45 | 50 | import static org.mockito.Mockito.when; |
46 | 51 |
|
47 | 52 | public class RemoteStoreReplicationSourceTests extends OpenSearchIndexLevelReplicationTestCase { |
@@ -190,8 +195,7 @@ public void testGetMergedSegmentFiles() throws IOException, ExecutionException, |
190 | 195 | final ReplicationCheckpoint checkpoint = primaryShard.getLatestReplicationCheckpoint(); |
191 | 196 | Map<String, String> localToRemoteFilenameMap = new HashMap<>() { |
192 | 197 | { |
193 | | - Map<String, RemoteSegmentStoreDirectory.UploadedSegmentMetadata> segmentsUploadedToRemoteStore = primaryShard |
194 | | - .getRemoteDirectory() |
| 198 | + Map<String, UploadedSegmentMetadata> segmentsUploadedToRemoteStore = primaryShard.getRemoteDirectory() |
195 | 199 | .getSegmentsUploadedToRemoteStore(); |
196 | 200 | segmentsUploadedToRemoteStore.forEach((segment, metadata) -> { |
197 | 201 | if (segment.startsWith("segments_") == false) put(segment, metadata.getUploadedFilename()); |
@@ -228,6 +232,70 @@ public void testGetMergedSegmentFiles() throws IOException, ExecutionException, |
228 | 232 | closeShards(replicaShard); |
229 | 233 | } |
230 | 234 |
|
| 235 | + public void testGetMergedSegmentFilesDownloadTimeout() throws IOException, ExecutionException, InterruptedException { |
| 236 | + final ReplicationCheckpoint checkpoint = primaryShard.getLatestReplicationCheckpoint(); |
| 237 | + Map<String, String> localToRemoteFilenameMap = new HashMap<>() { |
| 238 | + { |
| 239 | + Map<String, UploadedSegmentMetadata> segmentsUploadedToRemoteStore = primaryShard.getRemoteDirectory() |
| 240 | + .getSegmentsUploadedToRemoteStore(); |
| 241 | + segmentsUploadedToRemoteStore.forEach((segment, metadata) -> { |
| 242 | + if (segment.startsWith("segments_") == false) put(segment, metadata.getUploadedFilename()); |
| 243 | + }); |
| 244 | + } |
| 245 | + }; |
| 246 | + replicaShard.getRemoteDirectory().markPendingMergedSegmentsDownload(localToRemoteFilenameMap); |
| 247 | + RemoteStoreMergedSegmentCheckpoint mergedSegmentCheckpoint = new RemoteStoreMergedSegmentCheckpoint( |
| 248 | + new MergedSegmentCheckpoint( |
| 249 | + replicaShard.shardId(), |
| 250 | + primaryTerm, |
| 251 | + checkpoint.getSegmentInfosVersion(), |
| 252 | + checkpoint.getLength(), |
| 253 | + checkpoint.getCodec(), |
| 254 | + checkpoint.getMetadataMap(), |
| 255 | + "_0" |
| 256 | + ), |
| 257 | + localToRemoteFilenameMap |
| 258 | + ); |
| 259 | + List<StoreFileMetadata> filesToFetch = new ArrayList<>(primaryShard.getSegmentMetadataMap().values()); |
| 260 | + replicationSource = new RemoteStoreReplicationSource(primaryShard); |
| 261 | + IndexShard replica = spy(replicaShard); |
| 262 | + RecoverySettings mockRecoverySettings = mock(RecoverySettings.class); |
| 263 | + when(mockRecoverySettings.getMergedSegmentReplicationTimeout()).thenReturn(TimeValue.ZERO); |
| 264 | + when(replica.getRecoverySettings()).thenReturn(mockRecoverySettings); |
| 265 | + AtomicReference<Exception> failureRef = new AtomicReference<>(); |
| 266 | + CountDownLatch latch = new CountDownLatch(1); |
| 267 | + |
| 268 | + ActionListener<GetSegmentFilesResponse> listener = new ActionListener<>() { |
| 269 | + @Override |
| 270 | + public void onResponse(GetSegmentFilesResponse response) { |
| 271 | + fail("Expected onFailure to be called"); |
| 272 | + } |
| 273 | + |
| 274 | + @Override |
| 275 | + public void onFailure(Exception e) { |
| 276 | + failureRef.set(e); |
| 277 | + latch.countDown(); |
| 278 | + } |
| 279 | + }; |
| 280 | + replicationSource.getMergedSegmentFiles( |
| 281 | + REPLICATION_ID, |
| 282 | + mergedSegmentCheckpoint, |
| 283 | + filesToFetch, |
| 284 | + replica, |
| 285 | + (fileName, bytesRecovered) -> {}, |
| 286 | + listener |
| 287 | + ); |
| 288 | + latch.await(); |
| 289 | + assertNotNull("onFailure should have been called", failureRef.get()); |
| 290 | + Exception observedException = failureRef.get(); |
| 291 | + assertTrue(observedException instanceof TimeoutException); |
| 292 | + assertTrue( |
| 293 | + observedException.getMessage() != null |
| 294 | + && observedException.getMessage().equals("Timed out waiting for merged segments download from remote store") |
| 295 | + ); |
| 296 | + closeShards(replicaShard); |
| 297 | + } |
| 298 | + |
231 | 299 | public void testGetMergedSegmentFilesFailure() throws IOException, ExecutionException, InterruptedException { |
232 | 300 | // Testing failure scenario where segments are not a part of RemoteSegmentStoreDirectory.pendingMergedSegmentsDownloads |
233 | 301 | final ReplicationCheckpoint checkpoint = primaryShard.getLatestReplicationCheckpoint(); |
@@ -285,7 +353,7 @@ private void buildIndexShardBehavior(IndexShard mockShard, IndexShard indexShard |
285 | 353 | Store remoteStore = mock(Store.class); |
286 | 354 | when(mockShard.remoteStore()).thenReturn(remoteStore); |
287 | 355 | RemoteSegmentStoreDirectory remoteSegmentStoreDirectory = (RemoteSegmentStoreDirectory) ((FilterDirectory) ((FilterDirectory) indexShard.remoteStore().directory()).getDelegate()).getDelegate(); |
288 | | - FilterDirectory remoteStoreFilterDirectory = new RemoteStoreRefreshListenerTests.TestFilterDirectory(new RemoteStoreRefreshListenerTests.TestFilterDirectory(remoteSegmentStoreDirectory)); |
| 356 | + FilterDirectory remoteStoreFilterDirectory = new TestFilterDirectory(new TestFilterDirectory(remoteSegmentStoreDirectory)); |
289 | 357 | when(remoteStore.directory()).thenReturn(remoteStoreFilterDirectory); |
290 | 358 | } |
291 | 359 | } |
0 commit comments