org.elasticsearch.action.support.replication.PendingReplicationActions Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
package org.elasticsearch.action.support.replication;
import org.elasticsearch.action.support.RetryableAction;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.core.Releasable;
import org.elasticsearch.index.shard.IndexShardClosedException;
import org.elasticsearch.index.shard.ReplicationGroup;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.threadpool.ThreadPool;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
public class PendingReplicationActions implements Consumer, Releasable {
private final Map>> onGoingReplicationActions = ConcurrentCollections.newConcurrentMap();
private final ShardId shardId;
private final ThreadPool threadPool;
private volatile long replicationGroupVersion = -1;
public PendingReplicationActions(ShardId shardId, ThreadPool threadPool) {
this.shardId = shardId;
this.threadPool = threadPool;
}
public void addPendingAction(String allocationId, RetryableAction replicationAction) {
Set> ongoingActionsOnNode = onGoingReplicationActions.get(allocationId);
if (ongoingActionsOnNode != null) {
ongoingActionsOnNode.add(replicationAction);
if (onGoingReplicationActions.containsKey(allocationId) == false) {
replicationAction.cancel(
new IndexShardClosedException(
shardId,
"Replica unavailable - replica could have left ReplicationGroup or IndexShard might have closed"
)
);
}
} else {
replicationAction.cancel(
new IndexShardClosedException(
shardId,
"Replica unavailable - replica could have left ReplicationGroup or IndexShard might have closed"
)
);
}
}
public void removeReplicationAction(String allocationId, RetryableAction action) {
Set> ongoingActionsOnNode = onGoingReplicationActions.get(allocationId);
if (ongoingActionsOnNode != null) {
ongoingActionsOnNode.remove(action);
}
}
@Override
public void accept(ReplicationGroup replicationGroup) {
if (isNewerVersion(replicationGroup)) {
synchronized (this) {
if (isNewerVersion(replicationGroup)) {
acceptNewTrackedAllocationIds(replicationGroup.getTrackedAllocationIds());
replicationGroupVersion = replicationGroup.getVersion();
}
}
}
}
private boolean isNewerVersion(ReplicationGroup replicationGroup) {
// Relative comparison to mitigate long overflow
return replicationGroup.getVersion() - replicationGroupVersion > 0;
}
// Visible for testing
synchronized void acceptNewTrackedAllocationIds(Set trackedAllocationIds) {
for (String targetAllocationId : trackedAllocationIds) {
onGoingReplicationActions.putIfAbsent(targetAllocationId, ConcurrentCollections.newConcurrentSet());
}
ArrayList>> toCancel = new ArrayList<>();
for (String allocationId : onGoingReplicationActions.keySet()) {
if (trackedAllocationIds.contains(allocationId) == false) {
toCancel.add(onGoingReplicationActions.remove(allocationId));
}
}
cancelActions(toCancel, "Replica left ReplicationGroup");
}
@Override
public synchronized void close() {
ArrayList>> toCancel = new ArrayList<>(onGoingReplicationActions.values());
onGoingReplicationActions.clear();
cancelActions(toCancel, "Primary closed.");
}
private void cancelActions(ArrayList>> toCancel, String message) {
threadPool.executor(ThreadPool.Names.GENERIC)
.execute(
() -> toCancel.stream()
.flatMap(Collection::stream)
.forEach(action -> action.cancel(new IndexShardClosedException(shardId, message)))
);
}
}