public synchronized BufferResult get( String outputId, long startingSequenceId, DataSize maxSize, Duration maxWait) throws InterruptedException { Preconditions.checkNotNull(outputId, "outputId is null"); Preconditions.checkArgument(maxSize.toBytes() > 0, "maxSize must be at least 1 byte"); Preconditions.checkNotNull(maxWait, "maxWait is null"); NamedQueue namedQueue = namedQueues.get(outputId); if (namedQueue == null) { throw new NoSuchBufferException(outputId, namedQueues.keySet()); } if (state == QueueState.FINISHED) { return emptyResults(namedQueue.getSequenceId(), true); } // wait for pages to arrive if (namedQueue.isEmpty()) { long remainingNanos = maxWait.roundTo(NANOSECONDS); long end = System.nanoTime() + remainingNanos; while (remainingNanos > 0 && namedQueue.isEmpty() && !namedQueue.isFinished()) { // wait for timeout or notification NANOSECONDS.timedWait(this, remainingNanos); remainingNanos = end - System.nanoTime(); } } // remove queue from set before calling getPages because getPages changes // the sequence number of the queue which is used for identity comparison in the // sorted set openQueuesBySequenceId.remove(namedQueue); // get the pages BufferResult results = namedQueue.getPages(startingSequenceId, maxSize); // only add back the queue if it is still open if (!closed.get() || !results.isBufferClosed()) { openQueuesBySequenceId.add(namedQueue); } else { namedQueue.setFinished(); } updateState(); return results; }
private synchronized void updateState() { if (closed.get()) { // remove all empty queues for (Iterator<NamedQueue> iterator = openQueuesBySequenceId.iterator(); iterator.hasNext(); ) { NamedQueue namedQueue = iterator.next(); if (namedQueue.isEmpty()) { namedQueue.setFinished(); iterator.remove(); } } // discard queued pages (not officially in the buffer) and waiters for (QueuedPage queuedPage : queuedPages) { queuedPage.getFuture().set(null); } queuedPages.clear(); } if (state == QueueState.NO_MORE_QUEUES && !openQueuesBySequenceId.isEmpty()) { // advance master sequence id long oldMasterSequenceId = masterSequenceId; masterSequenceId = openQueuesBySequenceId.iterator().next().getSequenceId(); // drop consumed pages int pagesToRemove = Ints.checkedCast(masterSequenceId - oldMasterSequenceId); Preconditions.checkState( pagesToRemove >= 0, "Master sequence id moved backwards: oldMasterSequenceId=%s, newMasterSequenceId=%s", oldMasterSequenceId, masterSequenceId); for (int i = 0; i < pagesToRemove; i++) { Page page = masterQueue.removeFirst(); bufferedBytes -= page.getDataSize().toBytes(); } // refill buffer from queued pages while (!queuedPages.isEmpty() && bufferedBytes < maxBufferedBytes) { QueuedPage queuedPage = queuedPages.removeFirst(); addInternal(queuedPage.getPage()); queuedPage.getFuture().set(null); } } if (state == QueueState.NO_MORE_QUEUES && closed.get() && openQueuesBySequenceId.isEmpty()) { destroy(); } this.notifyAll(); }