org.elasticsearch.indices.recovery.RecoveryTarget#restoreFileFromSnapshot does not check for cancellation during the download of a file. This means that if a recovery is cancelled mid-way, we will still not release the store/shard-lock until the file is fully downloaded.
For large files or slow downloads this can lead to problems when the shard is (re-)allocated to a node that is still executing such an interrupted recovery.

-> we need to add some checks for cancellation here like we have for other recovery modes.
server/src/main/java/org/elasticsearch/indices/recovery/PeerRecoveryTargetService.java
import org.elasticsearch.transport.TransportService;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import static org.elasticsearch.core.Strings.format;
import static org.elasticsearch.core.TimeValue.timeValueMillis;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
/**
 * The recovery target handles recoveries of peer shards of the shard+node to recover to.
 * <p>
 * Note, it can be safely assumed that there will only be a single recovery per shard (index+id) and
 * not several of them (since we don't allocate several shard replicas to the same node).
 */
public class PeerRecoveryTargetService implements IndexEventListener {
    private static final Logger logger = LogManager.getLogger(PeerRecoveryTargetService.class);
    public static class Actions {
        public static final String FILES_INFO = "internal:index/shard/recovery/filesInfo";
        public static final String RESTORE_FILE_FROM_SNAPSHOT = "internal:index/shard/recovery/restore_file_from_snapshot";
        public static final String FILE_CHUNK = "internal:index/shard/recovery/file_chunk";
        public static final String CLEAN_FILES = "internal:index/shard/recovery/clean_files";
        public static final String TRANSLOG_OPS = "internal:index/shard/recovery/translog_ops";
        public static final String PREPARE_TRANSLOG = "internal:index/shard/recovery/prepare_translog";
        public static final String FINALIZE = "internal:index/shard/recovery/finalize";
        public static final String HANDOFF_PRIMARY_CONTEXT = "internal:index/shard/recovery/handoff_primary_context";
    }
    private final ThreadPool threadPool;
    private final TransportService transportService;
    private final RecoverySettings recoverySettings;
    private final ClusterService clusterService;
    private final SnapshotFilesProvider snapshotFilesProvider;