Skip to content

Commit 014c314

Browse files
committed
nfs4: add NFS4Client#addDisposeListener
Motivation: NFS4Client object might be associated with some non-state resources, like delegation heuristic queues). Thus when client is disposed due to being inactive, those resources must be freed. Modification: add NFS4Client#addDisposeListener. Add NFS4Client#disposeIgnoreFailures (as tryToDispose should throw exceptions). Update NFSv4StateHandler to use NFS4Client#disposeIgnoreFailures. Result: A possibility to free non state resources associated with the client. Acked-by: Paul Millar Target: master
1 parent bc5c1b3 commit 014c314

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

core/src/main/java/org/dcache/nfs/v4/NFS4Client.java

+41-3
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@
3131

3232
import java.net.InetSocketAddress;
3333
import java.security.Principal;
34+
import java.util.ArrayList;
3435
import java.util.Arrays;
3536
import java.util.Collection;
3637
import java.util.HashMap;
3738
import java.util.Iterator;
39+
import java.util.List;
3840
import java.util.Map;
3941
import java.util.concurrent.ConcurrentHashMap;
4042
import java.util.concurrent.atomic.AtomicInteger;
@@ -56,6 +58,8 @@
5658
import org.dcache.nfs.v4.xdr.verifier4;
5759
import org.dcache.nfs.util.Opaque;
5860

61+
import javax.annotation.concurrent.GuardedBy;
62+
5963
public class NFS4Client {
6064

6165
private static final Logger _log = LoggerFactory.getLogger(NFS4Client.class);
@@ -195,6 +199,11 @@ from that which the server has previously recorded the client (as
195199
*/
196200
private final Clock _clock;
197201

202+
/**
203+
* List of listeners to be notified when client is disposed.
204+
*/
205+
private final List<DisposeListener<NFS4Client>> _disposeListeners = new ArrayList<>();
206+
198207
public NFS4Client(NFSv4StateHandler stateHandler, clientid4 clientId, int minorVersion, InetSocketAddress clientAddress, InetSocketAddress localAddress,
199208
byte[] ownerID, verifier4 verifier, Principal principal, Duration leaseTime, boolean calbackNeeded) {
200209

@@ -211,7 +220,7 @@ public NFS4Client(NFSv4StateHandler stateHandler, clientid4 clientId, int minorV
211220
_leaseTime = leaseTime;
212221
_callbackNeeded = calbackNeeded;
213222
_minorVersion = minorVersion;
214-
_reclaim_completed = _minorVersion == 0; // no reclaim for NFSv4.0 clients
223+
_reclaim_completed = _minorVersion == 0; // no reclaim for NFSv4.0 clients
215224
_log.debug("New client: {}", this);
216225
}
217226

@@ -480,7 +489,8 @@ public void detachState(NFS4State state) {
480489
_clientStates.remove(state.stateid());
481490
}
482491

483-
private synchronized void drainStates() {
492+
@GuardedBy("this")
493+
private void drainStates() {
484494
Iterator<NFS4State> i = _clientStates.values().iterator();
485495
while (i.hasNext()) {
486496
NFS4State state = i.next();
@@ -493,8 +503,29 @@ private synchronized void drainStates() {
493503
* Release resources used by this client if not released yet. Any subsequent
494504
* call will have no effect.
495505
*/
496-
public final void tryDispose() {
506+
public synchronized final void tryDispose() throws ChimeraNFSException {
507+
drainStates();
508+
Iterator<DisposeListener<NFS4Client>> i = _disposeListeners.iterator();
509+
while(i.hasNext()) {
510+
DisposeListener<NFS4Client> listener = i.next();
511+
listener.notifyDisposed(this);
512+
i.remove();
513+
}
514+
}
515+
516+
/**
517+
* Release resources used by this client if not released yet. Ignore any errors.
518+
*/
519+
public synchronized final void disposeIgnoreFailures() {
497520
drainStates();
521+
_disposeListeners.forEach( l -> {
522+
try {
523+
l.notifyDisposed(NFS4Client.this);
524+
} catch (ChimeraNFSException e) {
525+
_log.warn("failed to notify client dispose listener {} : {}",l , e.getMessage());
526+
}
527+
});
528+
_disposeListeners.clear();
498529
}
499530

500531
/**
@@ -572,4 +603,11 @@ public synchronized void releaseOwner(byte[] owner) throws StaleClientidExceptio
572603
throw new StaleClientidException();
573604
}
574605
}
606+
607+
/**
608+
* Add listener to be notified when client is disposed.
609+
*/
610+
synchronized public void addDisposeListener(DisposeListener<NFS4Client> disposeListener) {
611+
_disposeListeners.add(disposeListener);
612+
}
575613
}

core/src/main/java/org/dcache/nfs/v4/NFSv4StateHandler.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009 - 2023 Deutsches Elektronen-Synchroton,
2+
* Copyright (c) 2009 - 2025 Deutsches Elektronen-Synchroton,
33
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY
44
*
55
* This library is free software; you can redistribute it and/or modify
@@ -165,7 +165,7 @@ public void removeClient(NFS4Client client) {
165165
} finally {
166166
_writeLock.unlock();
167167
}
168-
client.tryDispose();
168+
client.disposeIgnoreFailures();
169169
}
170170

171171
private void addClient(NFS4Client newClient) {
@@ -353,7 +353,7 @@ private DeadClientCollector(ClientRecoveryStore clientStore) {
353353
@Override
354354
public void notifyExpired(Cache<clientid4, NFS4Client> cache, NFS4Client client) {
355355
_log.info("Removing expired client: {}", client);
356-
client.tryDispose();
356+
client.disposeIgnoreFailures();
357357
clientStore.removeClient(client.getOwnerId());
358358
}
359359
}
@@ -387,7 +387,7 @@ public synchronized void wantReclaim(byte[] owner) throws ChimeraNFSException {
387387
private void drainClients() {
388388
_clientsByServerId.stream()
389389
.forEach(c -> {
390-
c.tryDispose();
390+
c.disposeIgnoreFailures();
391391
_clientsByServerId.remove(c.getId());
392392
});
393393
}

0 commit comments

Comments
 (0)