use of org.opensearch.action.support.replication.ReplicationResponse.ShardInfo in project OpenSearch by opensearch-project.
the class ReplicationOperationTests method testPrimaryFailureHandlingReplicaResponse.
public void testPrimaryFailureHandlingReplicaResponse() throws Exception {
final String index = "test";
final ShardId shardId = new ShardId(index, "_na_", 0);
final Request request = new Request(shardId);
final ClusterState state = stateWithActivePrimary(index, true, 1, 0);
final IndexMetadata indexMetadata = state.getMetadata().index(index);
final long primaryTerm = indexMetadata.primaryTerm(0);
final ShardRouting primaryRouting = state.getRoutingTable().shardRoutingTable(shardId).primaryShard();
final Set<String> inSyncAllocationIds = indexMetadata.inSyncAllocationIds(0);
final IndexShardRoutingTable shardRoutingTable = state.routingTable().index(index).shard(shardId.id());
final Set<String> trackedShards = shardRoutingTable.getAllAllocationIds();
final ReplicationGroup initialReplicationGroup = new ReplicationGroup(shardRoutingTable, inSyncAllocationIds, trackedShards, 0);
final boolean fatal = randomBoolean();
final AtomicBoolean primaryFailed = new AtomicBoolean();
final ReplicationOperation.Primary<Request, Request, TestPrimary.Result> primary = new TestPrimary(primaryRouting, () -> initialReplicationGroup, threadPool) {
@Override
public void failShard(String message, Exception exception) {
primaryFailed.set(true);
}
@Override
public void updateLocalCheckpointForShard(String allocationId, long checkpoint) {
if (primaryRouting.allocationId().getId().equals(allocationId)) {
super.updateLocalCheckpointForShard(allocationId, checkpoint);
} else {
if (fatal) {
throw new NullPointerException();
} else {
throw new AlreadyClosedException("already closed");
}
}
}
};
final PlainActionFuture<TestPrimary.Result> listener = new PlainActionFuture<>();
final ReplicationOperation.Replicas<Request> replicas = new TestReplicaProxy(Collections.emptyMap());
TestReplicationOperation operation = new TestReplicationOperation(request, primary, listener, replicas, primaryTerm);
operation.execute();
assertThat(primaryFailed.get(), equalTo(fatal));
final ShardInfo shardInfo = listener.actionGet().getShardInfo();
assertThat(shardInfo.getFailed(), equalTo(0));
assertThat(shardInfo.getFailures(), arrayWithSize(0));
assertThat(shardInfo.getSuccessful(), equalTo(1 + getExpectedReplicas(shardId, state, trackedShards).size()));
}
use of org.opensearch.action.support.replication.ReplicationResponse.ShardInfo in project OpenSearch by opensearch-project.
the class ReplicationOperationTests method testReplication.
public void testReplication() throws Exception {
final String index = "test";
final ShardId shardId = new ShardId(index, "_na_", 0);
ClusterState initialState = stateWithActivePrimary(index, true, randomInt(5));
IndexMetadata indexMetadata = initialState.getMetadata().index(index);
final long primaryTerm = indexMetadata.primaryTerm(0);
final IndexShardRoutingTable indexShardRoutingTable = initialState.getRoutingTable().shardRoutingTable(shardId);
ShardRouting primaryShard = indexShardRoutingTable.primaryShard();
if (primaryShard.relocating() && randomBoolean()) {
// simulate execution of the replication phase on the relocation target node after relocation source was marked as relocated
initialState = ClusterState.builder(initialState).nodes(DiscoveryNodes.builder(initialState.nodes()).localNodeId(primaryShard.relocatingNodeId())).build();
primaryShard = primaryShard.getTargetRelocatingShard();
}
// add a few in-sync allocation ids that don't have corresponding routing entries
final Set<String> staleAllocationIds = Sets.newHashSet(generateRandomStringArray(4, 10, false));
final Set<String> inSyncAllocationIds = Sets.union(indexMetadata.inSyncAllocationIds(0), staleAllocationIds);
final Set<String> trackedShards = new HashSet<>();
final Set<String> untrackedShards = new HashSet<>();
addTrackingInfo(indexShardRoutingTable, primaryShard, trackedShards, untrackedShards);
trackedShards.addAll(staleAllocationIds);
final ReplicationGroup replicationGroup = new ReplicationGroup(indexShardRoutingTable, inSyncAllocationIds, trackedShards, 0);
final Set<ShardRouting> expectedReplicas = getExpectedReplicas(shardId, initialState, trackedShards);
final Map<ShardRouting, Exception> simulatedFailures = new HashMap<>();
final Map<ShardRouting, Exception> reportedFailures = new HashMap<>();
for (ShardRouting replica : expectedReplicas) {
if (randomBoolean()) {
Exception t;
boolean criticalFailure = randomBoolean();
if (criticalFailure) {
t = new CorruptIndexException("simulated", (String) null);
reportedFailures.put(replica, t);
} else {
t = new IndexShardNotStartedException(shardId, IndexShardState.RECOVERING);
}
logger.debug("--> simulating failure on {} with [{}]", replica, t.getClass().getSimpleName());
simulatedFailures.put(replica, t);
}
}
Request request = new Request(shardId);
PlainActionFuture<TestPrimary.Result> listener = new PlainActionFuture<>();
final TestReplicaProxy replicasProxy = new TestReplicaProxy(simulatedFailures);
final TestPrimary primary = new TestPrimary(primaryShard, () -> replicationGroup, threadPool);
final TestReplicationOperation op = new TestReplicationOperation(request, primary, listener, replicasProxy, primaryTerm);
op.execute();
assertThat("request was not processed on primary", request.processedOnPrimary.get(), equalTo(true));
assertThat(request.processedOnReplicas, equalTo(expectedReplicas));
assertThat(replicasProxy.failedReplicas, equalTo(simulatedFailures.keySet()));
assertThat(replicasProxy.markedAsStaleCopies, equalTo(staleAllocationIds));
assertThat("post replication operations not run on primary", request.runPostReplicationActionsOnPrimary.get(), equalTo(true));
assertTrue("listener is not marked as done", listener.isDone());
ShardInfo shardInfo = listener.actionGet().getShardInfo();
assertThat(shardInfo.getFailed(), equalTo(reportedFailures.size()));
assertThat(shardInfo.getFailures(), arrayWithSize(reportedFailures.size()));
assertThat(shardInfo.getSuccessful(), equalTo(1 + expectedReplicas.size() - simulatedFailures.size()));
final List<ShardRouting> unassignedShards = indexShardRoutingTable.shardsWithState(ShardRoutingState.UNASSIGNED);
final int totalShards = 1 + expectedReplicas.size() + unassignedShards.size() + untrackedShards.size();
assertThat(replicationGroup.toString(), shardInfo.getTotal(), equalTo(totalShards));
assertThat(primary.knownLocalCheckpoints.remove(primaryShard.allocationId().getId()), equalTo(primary.localCheckpoint));
assertThat(primary.knownLocalCheckpoints, equalTo(replicasProxy.generatedLocalCheckpoints));
assertThat(primary.knownGlobalCheckpoints.remove(primaryShard.allocationId().getId()), equalTo(primary.globalCheckpoint));
assertThat(primary.knownGlobalCheckpoints, equalTo(replicasProxy.generatedGlobalCheckpoints));
}
use of org.opensearch.action.support.replication.ReplicationResponse.ShardInfo in project OpenSearch by opensearch-project.
the class RandomObjects method randomShardInfo.
/**
* Returns a tuple that contains a randomized {@link ShardInfo} value (left side) and its corresponding
* value (right side) after it has been printed out as a {@link ToXContent} and parsed back using a parsing
* method like {@link ShardInfo#fromXContent(XContentParser)}. A `withShardFailures` parameter indicates if
* the randomized ShardInfo must or must not contain shard failures.
*
* @param random Random generator
* @param withShardFailures indicates if the generated ShardInfo must contain shard failures
*/
public static Tuple<ShardInfo, ShardInfo> randomShardInfo(Random random, boolean withShardFailures) {
int total = randomIntBetween(random, 1, 10);
if (withShardFailures == false) {
return Tuple.tuple(new ShardInfo(total, total), new ShardInfo(total, total));
}
int successful = randomIntBetween(random, 1, Math.max(1, (total - 1)));
int failures = Math.max(1, (total - successful));
Failure[] actualFailures = new Failure[failures];
Failure[] expectedFailures = new Failure[failures];
for (int i = 0; i < failures; i++) {
Tuple<Failure, Failure> failure = randomShardInfoFailure(random);
actualFailures[i] = failure.v1();
expectedFailures[i] = failure.v2();
}
return Tuple.tuple(new ShardInfo(total, successful, actualFailures), new ShardInfo(total, successful, expectedFailures));
}
use of org.opensearch.action.support.replication.ReplicationResponse.ShardInfo in project OpenSearch by opensearch-project.
the class DocWriteResponseTests method testToXContentDoesntIncludeForcedRefreshUnlessForced.
/**
* Tests that {@link DocWriteResponse#toXContent(XContentBuilder, ToXContent.Params)} doesn't include {@code forced_refresh} unless it
* is true. We can't assert this in the yaml tests because "not found" is also "false" there....
*/
public void testToXContentDoesntIncludeForcedRefreshUnlessForced() throws IOException {
DocWriteResponse response = new DocWriteResponse(new ShardId("index", "uuid", 0), "id", SequenceNumbers.UNASSIGNED_SEQ_NO, 17, 0, Result.CREATED) {
};
response.setShardInfo(new ShardInfo(1, 1));
response.setForcedRefresh(false);
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) {
assertThat(parser.map(), not(hasKey("forced_refresh")));
}
}
response.setForcedRefresh(true);
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) {
assertThat(parser.map(), hasEntry("forced_refresh", true));
}
}
}
use of org.opensearch.action.support.replication.ReplicationResponse.ShardInfo in project OpenSearch by opensearch-project.
the class ReplicationOperationTests method testRetryTransientReplicationFailure.
public void testRetryTransientReplicationFailure() throws Exception {
final String index = "test";
final ShardId shardId = new ShardId(index, "_na_", 0);
ClusterState initialState = stateWithActivePrimary(index, true, randomInt(5));
IndexMetadata indexMetadata = initialState.getMetadata().index(index);
final long primaryTerm = indexMetadata.primaryTerm(0);
final IndexShardRoutingTable indexShardRoutingTable = initialState.getRoutingTable().shardRoutingTable(shardId);
ShardRouting primaryShard = indexShardRoutingTable.primaryShard();
if (primaryShard.relocating() && randomBoolean()) {
// simulate execution of the replication phase on the relocation target node after relocation source was marked as relocated
initialState = ClusterState.builder(initialState).nodes(DiscoveryNodes.builder(initialState.nodes()).localNodeId(primaryShard.relocatingNodeId())).build();
primaryShard = primaryShard.getTargetRelocatingShard();
}
// add a few in-sync allocation ids that don't have corresponding routing entries
final Set<String> staleAllocationIds = Sets.newHashSet(generateRandomStringArray(4, 10, false));
final Set<String> inSyncAllocationIds = Sets.union(indexMetadata.inSyncAllocationIds(0), staleAllocationIds);
final Set<String> trackedShards = new HashSet<>();
final Set<String> untrackedShards = new HashSet<>();
addTrackingInfo(indexShardRoutingTable, primaryShard, trackedShards, untrackedShards);
trackedShards.addAll(staleAllocationIds);
final ReplicationGroup replicationGroup = new ReplicationGroup(indexShardRoutingTable, inSyncAllocationIds, trackedShards, 0);
final Set<ShardRouting> expectedReplicas = getExpectedReplicas(shardId, initialState, trackedShards);
final Map<ShardRouting, Exception> simulatedFailures = new HashMap<>();
for (ShardRouting replica : expectedReplicas) {
Exception cause;
Exception exception;
if (randomBoolean()) {
if (randomBoolean()) {
cause = new CircuitBreakingException("broken", CircuitBreaker.Durability.PERMANENT);
} else {
cause = new OpenSearchRejectedExecutionException("rejected");
}
exception = new RemoteTransportException("remote", cause);
} else {
TransportAddress address = new TransportAddress(InetAddress.getLoopbackAddress(), 9300);
DiscoveryNode node = new DiscoveryNode("replica", address, Version.CURRENT);
cause = new ConnectTransportException(node, "broken");
exception = cause;
}
logger.debug("--> simulating failure on {} with [{}]", replica, exception.getClass().getSimpleName());
simulatedFailures.put(replica, exception);
}
Request request = new Request(shardId);
PlainActionFuture<TestPrimary.Result> listener = new PlainActionFuture<>();
final TestReplicaProxy replicasProxy = new TestReplicaProxy(simulatedFailures, true);
final TestPrimary primary = new TestPrimary(primaryShard, () -> replicationGroup, threadPool);
final TestReplicationOperation op = new TestReplicationOperation(request, primary, listener, replicasProxy, primaryTerm, TimeValue.timeValueMillis(20), TimeValue.timeValueSeconds(60));
op.execute();
assertThat("request was not processed on primary", request.processedOnPrimary.get(), equalTo(true));
assertThat(request.processedOnReplicas, equalTo(expectedReplicas));
assertThat(replicasProxy.failedReplicas.size(), equalTo(0));
assertThat(replicasProxy.markedAsStaleCopies, equalTo(staleAllocationIds));
assertThat("post replication operations not run on primary", request.runPostReplicationActionsOnPrimary.get(), equalTo(true));
ShardInfo shardInfo = listener.actionGet().getShardInfo();
assertThat(shardInfo.getSuccessful(), equalTo(1 + expectedReplicas.size()));
final List<ShardRouting> unassignedShards = indexShardRoutingTable.shardsWithState(ShardRoutingState.UNASSIGNED);
final int totalShards = 1 + expectedReplicas.size() + unassignedShards.size() + untrackedShards.size();
assertThat(replicationGroup.toString(), shardInfo.getTotal(), equalTo(totalShards));
assertThat(primary.knownLocalCheckpoints.remove(primaryShard.allocationId().getId()), equalTo(primary.localCheckpoint));
assertThat(primary.knownLocalCheckpoints, equalTo(replicasProxy.generatedLocalCheckpoints));
assertThat(primary.knownGlobalCheckpoints.remove(primaryShard.allocationId().getId()), equalTo(primary.globalCheckpoint));
assertThat(primary.knownGlobalCheckpoints, equalTo(replicasProxy.generatedGlobalCheckpoints));
}
Aggregations