Search in sources :

Example 1 with ReplicationResponse

use of org.opensearch.action.support.replication.ReplicationResponse in project OpenSearch by opensearch-project.

the class RetentionLeaseIT method testRetentionLeasesSyncOnExpiration.

public void testRetentionLeasesSyncOnExpiration() throws Exception {
    final int numberOfReplicas = 2 - scaledRandomIntBetween(0, 2);
    internalCluster().ensureAtLeastNumDataNodes(1 + numberOfReplicas);
    final long estimatedTimeIntervalMillis = ThreadPool.ESTIMATED_TIME_INTERVAL_SETTING.get(Settings.EMPTY).millis();
    final TimeValue retentionLeaseTimeToLive = TimeValue.timeValueMillis(randomLongBetween(estimatedTimeIntervalMillis, 2 * estimatedTimeIntervalMillis));
    final Settings settings = Settings.builder().put("index.number_of_shards", 1).put("index.number_of_replicas", numberOfReplicas).put(IndexService.RETENTION_LEASE_SYNC_INTERVAL_SETTING.getKey(), TimeValue.timeValueSeconds(1)).build();
    createIndex("index", settings);
    ensureGreen("index");
    final String primaryShardNodeId = clusterService().state().routingTable().index("index").shard(0).primaryShard().currentNodeId();
    final String primaryShardNodeName = clusterService().state().nodes().get(primaryShardNodeId).getName();
    final IndexShard primary = internalCluster().getInstance(IndicesService.class, primaryShardNodeName).getShardOrNull(new ShardId(resolveIndex("index"), 0));
    // we will add multiple retention leases, wait for some to expire, and assert a consistent view between the primary and the replicas
    final int length = randomIntBetween(1, 8);
    for (int i = 0; i < length; i++) {
        // update the index for retention leases to live a long time
        final AcknowledgedResponse longTtlResponse = client().admin().indices().prepareUpdateSettings("index").setSettings(Settings.builder().putNull(IndexSettings.INDEX_SOFT_DELETES_RETENTION_LEASE_PERIOD_SETTING.getKey()).build()).get();
        assertTrue(longTtlResponse.isAcknowledged());
        final String id = randomAlphaOfLength(8);
        final long retainingSequenceNumber = randomLongBetween(0, Long.MAX_VALUE);
        final String source = randomAlphaOfLength(8);
        final CountDownLatch latch = new CountDownLatch(1);
        final ActionListener<ReplicationResponse> listener = countDownLatchListener(latch);
        final RetentionLease currentRetentionLease = primary.addRetentionLease(id, retainingSequenceNumber, source, listener);
        final long now = System.nanoTime();
        latch.await();
        // check current retention leases have been synced to all replicas
        for (final ShardRouting replicaShard : clusterService().state().routingTable().index("index").shard(0).replicaShards()) {
            final String replicaShardNodeId = replicaShard.currentNodeId();
            final String replicaShardNodeName = clusterService().state().nodes().get(replicaShardNodeId).getName();
            final IndexShard replica = internalCluster().getInstance(IndicesService.class, replicaShardNodeName).getShardOrNull(new ShardId(resolveIndex("index"), 0));
            assertThat(RetentionLeaseUtils.toMapExcludingPeerRecoveryRetentionLeases(replica.getRetentionLeases()).values(), anyOf(empty(), contains(currentRetentionLease)));
        }
        // update the index for retention leases to short a long time, to force expiration
        final AcknowledgedResponse shortTtlResponse = client().admin().indices().prepareUpdateSettings("index").setSettings(Settings.builder().put(IndexSettings.INDEX_SOFT_DELETES_RETENTION_LEASE_PERIOD_SETTING.getKey(), retentionLeaseTimeToLive).build()).get();
        assertTrue(shortTtlResponse.isAcknowledged());
        // sleep long enough that the current retention lease has expired
        final long later = System.nanoTime();
        Thread.sleep(Math.max(0, retentionLeaseTimeToLive.millis() - TimeUnit.NANOSECONDS.toMillis(later - now)));
        assertBusy(() -> assertThat(RetentionLeaseUtils.toMapExcludingPeerRecoveryRetentionLeases(primary.getRetentionLeases()).entrySet(), empty()));
        // now that all retention leases are expired should have been synced to all replicas
        assertBusy(() -> {
            for (final ShardRouting replicaShard : clusterService().state().routingTable().index("index").shard(0).replicaShards()) {
                final String replicaShardNodeId = replicaShard.currentNodeId();
                final String replicaShardNodeName = clusterService().state().nodes().get(replicaShardNodeId).getName();
                final IndexShard replica = internalCluster().getInstance(IndicesService.class, replicaShardNodeName).getShardOrNull(new ShardId(resolveIndex("index"), 0));
                assertThat(RetentionLeaseUtils.toMapExcludingPeerRecoveryRetentionLeases(replica.getRetentionLeases()).entrySet(), empty());
            }
        });
    }
}
Also used : IndexShard(org.opensearch.index.shard.IndexShard) AcknowledgedResponse(org.opensearch.action.support.master.AcknowledgedResponse) IndicesService(org.opensearch.indices.IndicesService) CountDownLatch(java.util.concurrent.CountDownLatch) ReplicationResponse(org.opensearch.action.support.replication.ReplicationResponse) ShardId(org.opensearch.index.shard.ShardId) ShardRouting(org.opensearch.cluster.routing.ShardRouting) TimeValue(org.opensearch.common.unit.TimeValue) Settings(org.opensearch.common.settings.Settings) IndexSettings(org.opensearch.index.IndexSettings)

Example 2 with ReplicationResponse

use of org.opensearch.action.support.replication.ReplicationResponse in project OpenSearch by opensearch-project.

the class RetentionLeaseIT method runUnderBlockTest.

private void runUnderBlockTest(final String idForInitialRetentionLease, final long initialRetainingSequenceNumber, final BiConsumer<IndexShard, ActionListener<ReplicationResponse>> primaryConsumer, final Consumer<IndexShard> afterSync) throws InterruptedException {
    final Settings settings = Settings.builder().put("index.number_of_shards", 1).put("index.number_of_replicas", 0).put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true).put(IndexService.RETENTION_LEASE_SYNC_INTERVAL_SETTING.getKey(), TimeValue.timeValueSeconds(1)).build();
    assertAcked(prepareCreate("index").setSettings(settings));
    ensureGreen("index");
    final String primaryShardNodeId = clusterService().state().routingTable().index("index").shard(0).primaryShard().currentNodeId();
    final String primaryShardNodeName = clusterService().state().nodes().get(primaryShardNodeId).getName();
    final IndexShard primary = internalCluster().getInstance(IndicesService.class, primaryShardNodeName).getShardOrNull(new ShardId(resolveIndex("index"), 0));
    final String source = randomAlphaOfLength(8);
    final CountDownLatch latch = new CountDownLatch(1);
    final ActionListener<ReplicationResponse> listener = countDownLatchListener(latch);
    primary.addRetentionLease(idForInitialRetentionLease, initialRetainingSequenceNumber, source, listener);
    latch.await();
    final String block = randomFrom("read_only", "read_only_allow_delete", "read", "write", "metadata");
    client().admin().indices().prepareUpdateSettings("index").setSettings(Settings.builder().put("index.blocks." + block, true).build()).get();
    try {
        final CountDownLatch actionLatch = new CountDownLatch(1);
        final AtomicBoolean success = new AtomicBoolean();
        primaryConsumer.accept(primary, new ActionListener<ReplicationResponse>() {

            @Override
            public void onResponse(final ReplicationResponse replicationResponse) {
                success.set(true);
                actionLatch.countDown();
            }

            @Override
            public void onFailure(final Exception e) {
                failWithException(e);
            }
        });
        actionLatch.await();
        assertTrue(success.get());
        afterSync.accept(primary);
    } finally {
        client().admin().indices().prepareUpdateSettings("index").setSettings(Settings.builder().putNull("index.blocks." + block).build()).get();
    }
}
Also used : ShardId(org.opensearch.index.shard.ShardId) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) IndexShard(org.opensearch.index.shard.IndexShard) IndicesService(org.opensearch.indices.IndicesService) CountDownLatch(java.util.concurrent.CountDownLatch) Settings(org.opensearch.common.settings.Settings) IndexSettings(org.opensearch.index.IndexSettings) OpenSearchException(org.opensearch.OpenSearchException) ReplicationResponse(org.opensearch.action.support.replication.ReplicationResponse)

Example 3 with ReplicationResponse

use of org.opensearch.action.support.replication.ReplicationResponse in project OpenSearch by opensearch-project.

the class RetentionLeaseIT method testRetentionLeasesSyncOnRecovery.

public void testRetentionLeasesSyncOnRecovery() throws Exception {
    final int numberOfReplicas = 2 - scaledRandomIntBetween(0, 2);
    internalCluster().ensureAtLeastNumDataNodes(1 + numberOfReplicas);
    /*
         * We effectively disable the background sync to ensure that the retention leases are not synced in the background so that the only
         * source of retention leases on the replicas would be from recovery.
         */
    final Settings.Builder settings = Settings.builder().put("index.number_of_shards", 1).put("index.number_of_replicas", 0).put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true).put(IndexService.RETENTION_LEASE_SYNC_INTERVAL_SETTING.getKey(), TimeValue.timeValueHours(24));
    // when we increase the number of replicas below we want to exclude the replicas from being allocated so that they do not recover
    assertAcked(prepareCreate("index", 1, settings));
    ensureYellow("index");
    final AcknowledgedResponse response = client().admin().indices().prepareUpdateSettings("index").setSettings(Settings.builder().put("index.number_of_replicas", numberOfReplicas).build()).get();
    assertTrue(response.isAcknowledged());
    final String primaryShardNodeId = clusterService().state().routingTable().index("index").shard(0).primaryShard().currentNodeId();
    final String primaryShardNodeName = clusterService().state().nodes().get(primaryShardNodeId).getName();
    final IndexShard primary = internalCluster().getInstance(IndicesService.class, primaryShardNodeName).getShardOrNull(new ShardId(resolveIndex("index"), 0));
    final int length = randomIntBetween(1, 8);
    final Map<String, RetentionLease> currentRetentionLeases = new LinkedHashMap<>();
    logger.info("adding retention [{}}] leases", length);
    for (int i = 0; i < length; i++) {
        final String id = randomValueOtherThanMany(currentRetentionLeases.keySet()::contains, () -> randomAlphaOfLength(8));
        final long retainingSequenceNumber = randomLongBetween(0, Long.MAX_VALUE);
        final String source = randomAlphaOfLength(8);
        final CountDownLatch latch = new CountDownLatch(1);
        final ActionListener<ReplicationResponse> listener = countDownLatchListener(latch);
        currentRetentionLeases.put(id, primary.addRetentionLease(id, retainingSequenceNumber, source, listener));
        latch.await();
    }
    logger.info("finished adding [{}] retention leases", length);
    // cause some recoveries to fail to ensure that retention leases are handled properly when retrying a recovery
    assertAcked(client().admin().cluster().prepareUpdateSettings().setPersistentSettings(Settings.builder().put(INDICES_RECOVERY_RETRY_DELAY_NETWORK_SETTING.getKey(), TimeValue.timeValueMillis(100))));
    final Semaphore recoveriesToDisrupt = new Semaphore(scaledRandomIntBetween(0, 4));
    final MockTransportService primaryTransportService = (MockTransportService) internalCluster().getInstance(TransportService.class, primaryShardNodeName);
    primaryTransportService.addSendBehavior((connection, requestId, action, request, options) -> {
        if (action.equals(PeerRecoveryTargetService.Actions.FINALIZE) && recoveriesToDisrupt.tryAcquire()) {
            if (randomBoolean()) {
                // return a ConnectTransportException to the START_RECOVERY action
                final TransportService replicaTransportService = internalCluster().getInstance(TransportService.class, connection.getNode().getName());
                final DiscoveryNode primaryNode = primaryTransportService.getLocalNode();
                replicaTransportService.disconnectFromNode(primaryNode);
                replicaTransportService.connectToNode(primaryNode);
            } else {
                // return an exception to the FINALIZE action
                throw new OpenSearchException("failing recovery for test purposes");
            }
        }
        connection.sendRequest(requestId, action, request, options);
    });
    logger.info("allow [{}] replicas to allocate", numberOfReplicas);
    // now allow the replicas to be allocated and wait for recovery to finalize
    allowNodes("index", 1 + numberOfReplicas);
    ensureGreen("index");
    // check current retention leases have been synced to all replicas
    for (final ShardRouting replicaShard : clusterService().state().routingTable().index("index").shard(0).replicaShards()) {
        final String replicaShardNodeId = replicaShard.currentNodeId();
        final String replicaShardNodeName = clusterService().state().nodes().get(replicaShardNodeId).getName();
        final IndexShard replica = internalCluster().getInstance(IndicesService.class, replicaShardNodeName).getShardOrNull(new ShardId(resolveIndex("index"), 0));
        final Map<String, RetentionLease> retentionLeasesOnReplica = RetentionLeaseUtils.toMapExcludingPeerRecoveryRetentionLeases(replica.getRetentionLeases());
        assertThat(retentionLeasesOnReplica, equalTo(currentRetentionLeases));
        // check retention leases have been written on the replica; see RecoveryTarget#finalizeRecovery
        assertThat(currentRetentionLeases, equalTo(RetentionLeaseUtils.toMapExcludingPeerRecoveryRetentionLeases(replica.loadRetentionLeases())));
    }
}
Also used : DiscoveryNode(org.opensearch.cluster.node.DiscoveryNode) MockTransportService(org.opensearch.test.transport.MockTransportService) IndexShard(org.opensearch.index.shard.IndexShard) AcknowledgedResponse(org.opensearch.action.support.master.AcknowledgedResponse) IndicesService(org.opensearch.indices.IndicesService) Semaphore(java.util.concurrent.Semaphore) CountDownLatch(java.util.concurrent.CountDownLatch) LinkedHashMap(java.util.LinkedHashMap) ReplicationResponse(org.opensearch.action.support.replication.ReplicationResponse) ShardId(org.opensearch.index.shard.ShardId) MockTransportService(org.opensearch.test.transport.MockTransportService) TransportService(org.opensearch.transport.TransportService) OpenSearchException(org.opensearch.OpenSearchException) ShardRouting(org.opensearch.cluster.routing.ShardRouting) Settings(org.opensearch.common.settings.Settings) IndexSettings(org.opensearch.index.IndexSettings)

Example 4 with ReplicationResponse

use of org.opensearch.action.support.replication.ReplicationResponse in project OpenSearch by opensearch-project.

the class TransportShardRefreshAction method shardOperationOnPrimary.

@Override
protected void shardOperationOnPrimary(BasicReplicationRequest shardRequest, IndexShard primary, ActionListener<PrimaryResult<BasicReplicationRequest, ReplicationResponse>> listener) {
    ActionListener.completeWith(listener, () -> {
        primary.refresh("api");
        logger.trace("{} refresh request executed on primary", primary.shardId());
        return new PrimaryResult<>(shardRequest, new ReplicationResponse());
    });
}
Also used : ReplicationResponse(org.opensearch.action.support.replication.ReplicationResponse)

Example 5 with ReplicationResponse

use of org.opensearch.action.support.replication.ReplicationResponse in project OpenSearch by opensearch-project.

the class ReplicationTrackerRetentionLeaseTests method testCloneRetentionLease.

public void testCloneRetentionLease() {
    final AllocationId allocationId = AllocationId.newInitializing();
    final AtomicReference<ReplicationTracker> replicationTrackerRef = new AtomicReference<>();
    final AtomicLong timeReference = new AtomicLong();
    final AtomicBoolean synced = new AtomicBoolean();
    final ReplicationTracker replicationTracker = new ReplicationTracker(new ShardId("test", "_na", 0), allocationId.getId(), IndexSettingsModule.newIndexSettings("test", Settings.EMPTY), randomLongBetween(1, Long.MAX_VALUE), UNASSIGNED_SEQ_NO, value -> {
    }, timeReference::get, (leases, listener) -> {
        assertFalse(Thread.holdsLock(replicationTrackerRef.get()));
        assertTrue(synced.compareAndSet(false, true));
        listener.onResponse(new ReplicationResponse());
    }, OPS_BASED_RECOVERY_ALWAYS_REASONABLE);
    replicationTrackerRef.set(replicationTracker);
    replicationTracker.updateFromMaster(randomNonNegativeLong(), Collections.singleton(allocationId.getId()), routingTable(Collections.emptySet(), allocationId));
    replicationTracker.activatePrimaryMode(SequenceNumbers.NO_OPS_PERFORMED);
    final long addTime = randomLongBetween(timeReference.get(), Long.MAX_VALUE);
    timeReference.set(addTime);
    final long minimumRetainingSequenceNumber = randomLongBetween(SequenceNumbers.NO_OPS_PERFORMED, Long.MAX_VALUE);
    final PlainActionFuture<ReplicationResponse> addFuture = new PlainActionFuture<>();
    replicationTracker.addRetentionLease("source", minimumRetainingSequenceNumber, "test-source", addFuture);
    addFuture.actionGet();
    assertTrue(synced.get());
    synced.set(false);
    final long cloneTime = randomLongBetween(timeReference.get(), Long.MAX_VALUE);
    timeReference.set(cloneTime);
    final PlainActionFuture<ReplicationResponse> cloneFuture = new PlainActionFuture<>();
    final RetentionLease clonedLease = replicationTracker.cloneRetentionLease("source", "target", cloneFuture);
    cloneFuture.actionGet();
    assertTrue(synced.get());
    synced.set(false);
    assertThat(clonedLease.id(), equalTo("target"));
    assertThat(clonedLease.retainingSequenceNumber(), equalTo(minimumRetainingSequenceNumber));
    assertThat(clonedLease.timestamp(), equalTo(cloneTime));
    assertThat(clonedLease.source(), equalTo("test-source"));
    assertThat(replicationTracker.getRetentionLeases().get("target"), equalTo(clonedLease));
}
Also used : AllocationId(org.opensearch.cluster.routing.AllocationId) AtomicReference(java.util.concurrent.atomic.AtomicReference) ReplicationResponse(org.opensearch.action.support.replication.ReplicationResponse) ShardId(org.opensearch.index.shard.ShardId) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicLong(java.util.concurrent.atomic.AtomicLong) PlainActionFuture(org.opensearch.action.support.PlainActionFuture)

Aggregations

ReplicationResponse (org.opensearch.action.support.replication.ReplicationResponse)22 IndexShard (org.opensearch.index.shard.IndexShard)12 ShardId (org.opensearch.index.shard.ShardId)12 IndexSettings (org.opensearch.index.IndexSettings)11 Settings (org.opensearch.common.settings.Settings)10 ShardRouting (org.opensearch.cluster.routing.ShardRouting)8 CountDownLatch (java.util.concurrent.CountDownLatch)7 IndicesService (org.opensearch.indices.IndicesService)7 IOException (java.io.IOException)6 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)6 PlainActionFuture (org.opensearch.action.support.PlainActionFuture)5 Closeable (java.io.Closeable)4 ArrayList (java.util.ArrayList)4 Collections (java.util.Collections)4 List (java.util.List)4 Consumer (java.util.function.Consumer)4 ActionListener (org.opensearch.action.ActionListener)4 AtomicLong (java.util.concurrent.atomic.AtomicLong)3 ParameterizedMessage (org.apache.logging.log4j.message.ParameterizedMessage)3 OpenSearchException (org.opensearch.OpenSearchException)3