@ SuppressWarnings ( "FutureReturnValueIgnored" ) void refreshIfNeeded ( Node < K , V > node , long now ) { if ( ! refreshAfterWrite ( ) ) { return ; } K key ; V oldValue ; long oldWriteTime = node . getWriteTime ( ) ; long refreshWriteTime = ( now + ASYNC_EXPIRY ) ; if ( ( ( now - oldWriteTime ) > refreshAfterWriteNanos ( ) ) && ( ( key = node . getKey ( ) ) != null ) && ( ( oldValue = node . getValue ( ) ) != null ) && node . casWriteTime ( oldWriteTime , refreshWriteTime ) ) { try { CompletableFuture < V > refreshFuture ; long startTime = statsTicker ( ) . read ( ) ; if ( isAsync ) { @ SuppressWarnings ( "unchecked" ) CompletableFuture < V > future = ( CompletableFuture < V > ) oldValue ; if ( Async . isReady ( future ) ) { @ SuppressWarnings ( "NullAway" ) CompletableFuture < V > refresh = future . thenCompose ( value -> cacheLoader . asyncReload ( key , value , executor ) ) ; refreshFuture = refresh ; } else { // no-op if load is pending node . casWriteTime ( refreshWriteTime , oldWriteTime ) ; return ; } } else { @ SuppressWarnings ( "NullAway" ) CompletableFuture < V > refresh = cacheLoader . asyncReload ( key , oldValue , executor ) ; refreshFuture = refresh ; } refreshFuture . whenComplete ( ( newValue , error ) -> { long loadTime = statsTicker ( ) . read ( ) - startTime ; if ( error != null ) { logger . log ( Level . WARNING , "Exception thrown during refresh" , error ) ; node . casWriteTime ( refreshWriteTime , oldWriteTime ) ; statsCounter ( ) . recordLoadFailure ( loadTime ) ; return ; } @ SuppressWarnings ( "unchecked" ) V value = ( isAsync && ( newValue != null ) ) ? ( V ) refreshFuture : newValue ; boolean [ ] discard = new boolean [ 1 ] ; compute ( key , ( k , currentValue ) -> { if ( currentValue == null ) { return value ; } else if ( ( currentValue == oldValue ) && ( node . getWriteTime ( ) == refreshWriteTime ) ) { return value ; } discard [ 0 ] = true ; return currentValue ; } , /* recordMiss */ false , /* recordLoad */ false , /* recordLoadFailure */ true ) ; if ( discard [ 0 ] && hasRemovalListener ( ) ) { notifyRemoval ( key , value , RemovalCause . REPLACED ) ; } if ( newValue == null ) { statsCounter ( ) . recordLoadFailure ( loadTime ) ; } else { statsCounter ( ) . recordLoadSuccess ( loadTime ) ; } } ) ; } catch ( Throwable t ) { node . casWriteTime ( refreshWriteTime , oldWriteTime ) ; logger . log ( Level . SEVERE , "Exception thrown when submitting refresh task" , t ) ; } } }
Asynchronously refreshes the entry if eligible .