From ed8969190e1a5c4ce1bbe2adcd4de4c67ba1ef10 Mon Sep 17 00:00:00 2001 From: Tigran Mkrtchyan Date: Wed, 9 Sep 2026 15:24:54 +0200 Subject: [PATCH] retry mover start if redirect arrives before moverId Motivation: If mover redirect arrives at the door before reply to mover start message, or response to mover start get lost, door might fall into uninterruptable waiting state. In such situation, pool will detect a mover that has no client and will resend the redirect, which will be ignored by the door. Modification: On redirect message for a transfer without moverId door will resend `startMover` request. As startMover is idempotent operation, pool will re-send the moverId Result: NFS door recovery on lost moverId. Acked-by: Lennart Sack Target: master, 12.0, 11.2 Require-book: no Require-notes: yes (cherry picked from commit e035243c8014eedf434dd4bcb5387d424baf5efc) Signed-off-by: Tigran Mkrtchyan --- .../chimera/nfsv41/door/NFSv41Door.java | 31 ++++++++++++++++--- .../main/java/org/dcache/util/Transfer.java | 1 + 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/NFSv41Door.java b/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/NFSv41Door.java index ac0420ddaaa..948da280e7c 100644 --- a/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/NFSv41Door.java +++ b/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/NFSv41Door.java @@ -9,6 +9,7 @@ import com.google.common.collect.Sets; import com.google.common.net.InetAddresses; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.ThreadFactoryBuilder; import diskCacheV111.namespace.EventNotifier; import diskCacheV111.util.CacheException; @@ -631,13 +632,8 @@ public void destroy() throws IOException { public void messageArrived(PoolPassiveIoFileMessage message) { String poolName = message.getPoolName(); - long verifier = message.getVerifier(); - InetSocketAddress[] poolAddresses = message.socketAddresses(); - _log.debug("NFS mover ready: {}", poolName); - PoolDS device = _poolDeviceMap.getOrCreateDS(poolName, verifier, poolAddresses); - // REVISIT 11.0: remove drop legacy support. Old polls will send legacy stateid. // stateid4 stateid = message.challange(); @@ -652,6 +648,31 @@ public void messageArrived(PoolPassiveIoFileMessage message) { * Door reboot. */ if (transfer != null) { + + long verifier = message.getVerifier(); + InetSocketAddress[] poolAddresses = message.socketAddresses(); + + PoolDS device = _poolDeviceMap.getOrCreateDS(poolName, verifier, poolAddresses); + + if (transfer.getMoverId() == null) { + _log.warn("NFS mover ready for transfer without mover: {}", stateid); + // we have not got a reply from pool manager yet, try to start mover again. + // as mover start requests is idempotent, we can safely re-issue it. + // Only redirect once the (re-)started mover is actually known; otherwise the + // client would be sent to a pool without a running mover. Also guard against + // re-starting a mover for a transfer that is already being torn down. + if (!transfer.hasMover()) { + transfer.startMoverAsync(_poolStub.getTimeoutInMillis()).addListener(() -> { + if (transfer.getMoverId() != null) { + transfer.redirect(device); + } else { + _log.error("Failed to re-start mover for transfer without mover: {}", stateid); + } + }, MoreExecutors.directExecutor()); + } + return; + } + transfer.redirect(device); } } diff --git a/modules/dcache/src/main/java/org/dcache/util/Transfer.java b/modules/dcache/src/main/java/org/dcache/util/Transfer.java index cecbce1ade7..4121f60125c 100644 --- a/modules/dcache/src/main/java/org/dcache/util/Transfer.java +++ b/modules/dcache/src/main/java/org/dcache/util/Transfer.java @@ -1060,6 +1060,7 @@ public ListenableFuture selectPoolAsync(long timeout) { /** * Creates a mover for the transfer. + * @param timeout timeout in milliseconds */ public ListenableFuture startMoverAsync(long timeout) { FileAttributes fileAttributes = getFileAttributes();