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
public void startRecovery(final IndexShard indexShard, final DiscoveryNode sourceNode, final RecoveryListener listener) {
        final Releasable snapshotFileDownloadsPermit = tryAcquireSnapshotDownloadPermits();
        
        final long recoveryId = onGoingRecoveries.startRecovery(
            indexShard,
            sourceNode,
            snapshotFilesProvider,
            listener,
            recoverySettings.activityTimeout(),
            snapshotFileDownloadsPermit
        );
        
        
        threadPool.generic().execute(new RecoveryRunner(recoveryId));
    }
    protected void retryRecovery(final long recoveryId, final Throwable reason, TimeValue retryAfter, TimeValue activityTimeout) {
        logger.trace(() -> format("will retry recovery with id [%s] in [%s]", recoveryId, retryAfter), reason);
        retryRecovery(recoveryId, retryAfter, activityTimeout);
    }
    protected void retryRecovery(final long recoveryId, final String reason, TimeValue retryAfter, TimeValue activityTimeout) {
        logger.trace("will retry recovery with id [{}] in [{}] (reason [{}])", recoveryId, retryAfter, reason);
        retryRecovery(recoveryId, retryAfter, activityTimeout);
    }
    private void retryRecovery(final long recoveryId, final TimeValue retryAfter, final TimeValue activityTimeout) {
        RecoveryTarget newTarget = onGoingRecoveries.resetRecovery(recoveryId, activityTimeout);
        if (newTarget != null) {
            threadPool.scheduleUnlessShuttingDown(retryAfter, ThreadPool.Names.GENERIC, new RecoveryRunner(newTarget.recoveryId()));
        }
    }
    protected void reestablishRecovery(final StartRecoveryRequest request, final String reason, TimeValue retryAfter) {