31
31
32
32
import java .net .InetSocketAddress ;
33
33
import java .security .Principal ;
34
+ import java .util .ArrayList ;
34
35
import java .util .Arrays ;
35
36
import java .util .Collection ;
36
37
import java .util .HashMap ;
37
38
import java .util .Iterator ;
39
+ import java .util .List ;
38
40
import java .util .Map ;
39
41
import java .util .concurrent .ConcurrentHashMap ;
40
42
import java .util .concurrent .atomic .AtomicInteger ;
56
58
import org .dcache .nfs .v4 .xdr .verifier4 ;
57
59
import org .dcache .nfs .util .Opaque ;
58
60
61
+ import javax .annotation .concurrent .GuardedBy ;
62
+
59
63
public class NFS4Client {
60
64
61
65
private static final Logger _log = LoggerFactory .getLogger (NFS4Client .class );
@@ -195,6 +199,11 @@ from that which the server has previously recorded the client (as
195
199
*/
196
200
private final Clock _clock ;
197
201
202
+ /**
203
+ * List of listeners to be notified when client is disposed.
204
+ */
205
+ private final List <DisposeListener <NFS4Client >> _disposeListeners = new ArrayList <>();
206
+
198
207
public NFS4Client (NFSv4StateHandler stateHandler , clientid4 clientId , int minorVersion , InetSocketAddress clientAddress , InetSocketAddress localAddress ,
199
208
byte [] ownerID , verifier4 verifier , Principal principal , Duration leaseTime , boolean calbackNeeded ) {
200
209
@@ -211,7 +220,7 @@ public NFS4Client(NFSv4StateHandler stateHandler, clientid4 clientId, int minorV
211
220
_leaseTime = leaseTime ;
212
221
_callbackNeeded = calbackNeeded ;
213
222
_minorVersion = minorVersion ;
214
- _reclaim_completed = _minorVersion == 0 ; // no reclaim for NFSv4.0 clients
223
+ _reclaim_completed = _minorVersion == 0 ; // no reclaim for NFSv4.0 clients
215
224
_log .debug ("New client: {}" , this );
216
225
}
217
226
@@ -480,7 +489,8 @@ public void detachState(NFS4State state) {
480
489
_clientStates .remove (state .stateid ());
481
490
}
482
491
483
- private synchronized void drainStates () {
492
+ @ GuardedBy ("this" )
493
+ private void drainStates () {
484
494
Iterator <NFS4State > i = _clientStates .values ().iterator ();
485
495
while (i .hasNext ()) {
486
496
NFS4State state = i .next ();
@@ -493,8 +503,29 @@ private synchronized void drainStates() {
493
503
* Release resources used by this client if not released yet. Any subsequent
494
504
* call will have no effect.
495
505
*/
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 () {
497
520
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 ();
498
529
}
499
530
500
531
/**
@@ -572,4 +603,11 @@ public synchronized void releaseOwner(byte[] owner) throws StaleClientidExceptio
572
603
throw new StaleClientidException ();
573
604
}
574
605
}
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
+ }
575
613
}
0 commit comments