/** * Closes any registered stream entries that have not yet been consumed */ public final synchronized void shutdown() { // synchronize on 'this' to avoid races with registerStreams stopped = true; // If the cleanup task is running tell it to stop looping, and then remove it from the scheduled executor if (cleanupTaskFuture != null) { cleanupTaskFuture.cancel(false); } // Close remaining streams for (Map.Entry<InputStreamKey, TimedStreamEntry> entry : streamMap.entrySet()) { InputStreamKey key = entry.getKey(); TimedStreamEntry timedStreamEntry = entry.getValue(); //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (timedStreamEntry) { // ensure there's no race with a request that got a ref before we removed it closeStreamEntry(timedStreamEntry, key.requestId, key.index); } } }
/** * Closes any registered stream entries that have not yet been consumed */ public final synchronized void shutdown() { // synchronize on 'this' to avoid races with registerStreams stopped = true; // If the cleanup task is running tell it to stop looping, and then remove it from the scheduled executor if (cleanupTaskFuture != null) { cleanupTaskFuture.cancel(false); } // Close remaining streams for (Map.Entry<InputStreamKey, TimedStreamEntry> entry : streamMap.entrySet()) { InputStreamKey key = entry.getKey(); TimedStreamEntry timedStreamEntry = entry.getValue(); //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (timedStreamEntry) { // ensure there's no race with a request that got a ref before we removed it closeStreamEntry(timedStreamEntry, key.requestId, key.index); } } }
/** Close and remove expired streams. Package protected to allow unit tests to invoke it. */ void gc() { if (stopped) { return; } long expirationTime = System.currentTimeMillis() - timeout; for (Iterator<Map.Entry<InputStreamKey, TimedStreamEntry>> iter = streamMap.entrySet().iterator(); iter.hasNext();) { if (stopped) { return; } Map.Entry<InputStreamKey, TimedStreamEntry> entry = iter.next(); TimedStreamEntry timedStreamEntry = entry.getValue(); if (timedStreamEntry.timestamp.get() <= expirationTime) { iter.remove(); InputStreamKey key = entry.getKey(); //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (timedStreamEntry) { // ensure there's no race with a request that got a ref before we removed it closeStreamEntry(timedStreamEntry, key.requestId, key.index); } } } }
/** Close and remove expired streams. Package protected to allow unit tests to invoke it. */ void gc() { if (stopped) { return; } long expirationTime = System.currentTimeMillis() - timeout; for (Iterator<Map.Entry<InputStreamKey, TimedStreamEntry>> iter = streamMap.entrySet().iterator(); iter.hasNext();) { if (stopped) { return; } Map.Entry<InputStreamKey, TimedStreamEntry> entry = iter.next(); TimedStreamEntry timedStreamEntry = entry.getValue(); if (timedStreamEntry.timestamp.get() <= expirationTime) { iter.remove(); InputStreamKey key = entry.getKey(); //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (timedStreamEntry) { // ensure there's no race with a request that got a ref before we removed it closeStreamEntry(timedStreamEntry, key.requestId, key.index); } } } }
/** * Registers a set of streams that were associated with a particular request. Does nothing if {@link #shutdown()} * has been invoked, in which case any use of the {@link #getReadHandler() read handler} will result in behavior * equivalent to what would be seen if the the registered stream had 0 bytes of content. * * @param operationId id of the request * @param streams the streams. Cannot be {@code null} but may be empty */ synchronized void registerStreams(int operationId, List<OperationResponse.StreamEntry> streams) { // ^^^ synchronize on 'this' to avoid races with shutdown if (!stopped) { // Streams share a timestamp so activity on any is sufficient to keep the rest alive AtomicLong timestamp = new AtomicLong(System.currentTimeMillis()); for (int i = 0; i < streams.size(); i++) { OperationResponse.StreamEntry stream = streams.get(i); InputStreamKey key = new InputStreamKey(operationId, i); streamMap.put(key, new TimedStreamEntry(stream, timestamp)); } } else { // Just close the streams, as no caller ever will for (int i = 0; i < streams.size(); i++) { closeStreamEntry(streams.get(i), operationId, i); } } }
/** * Registers a set of streams that were associated with a particular request. Does nothing if {@link #shutdown()} * has been invoked, in which case any use of the {@link #getReadHandler() read handler} will result in behavior * equivalent to what would be seen if the the registered stream had 0 bytes of content. * * @param operationId id of the request * @param streams the streams. Cannot be {@code null} but may be empty */ synchronized void registerStreams(int operationId, List<OperationResponse.StreamEntry> streams) { // ^^^ synchronize on 'this' to avoid races with shutdown if (!stopped) { // Streams share a timestamp so activity on any is sufficient to keep the rest alive AtomicLong timestamp = new AtomicLong(System.currentTimeMillis()); for (int i = 0; i < streams.size(); i++) { OperationResponse.StreamEntry stream = streams.get(i); InputStreamKey key = new InputStreamKey(operationId, i); streamMap.put(key, new TimedStreamEntry(stream, timestamp)); } } else { // Just close the streams, as no caller ever will for (int i = 0; i < streams.size(); i++) { closeStreamEntry(streams.get(i), operationId, i); } } }