@Override @Synchronized public void close() { log.trace("Closing {}", this); if (outstandingRequest != null) { log.trace("Cancel outstanding read request for segment {}", asyncInput.getSegmentId()); outstandingRequest.cancel(true); } asyncInput.close(); }
/** * Issues a request * - if there is enough room for another request, and we aren't already waiting on one and * - if we have not read up to the configured endOffset. */ private void issueRequestIfNeeded() { //compute read length based on current offset up to which the events are read. int updatedReadLength = computeReadLength(offset + buffer.dataAvailable()); if (!receivedEndOfSegment && !receivedTruncated && updatedReadLength > 0 && outstandingRequest == null) { log.trace("Issuing read request for segment {} of {} bytes", getSegmentId(), updatedReadLength); outstandingRequest = asyncInput.read(offset + buffer.dataAvailable(), updatedReadLength); } }
@Override @Synchronized public void setOffset(long offset) { log.trace("SetOffset {}", offset); Preconditions.checkArgument(offset >= 0); Exceptions.checkNotClosed(asyncInput.isClosed(), this); if (offset > this.offset) { receivedTruncated = false; } if (offset != this.offset) { this.offset = offset; buffer.clear(); receivedEndOfSegment = false; outstandingRequest = null; } }
@Override public Segment getSegmentId() { return asyncInput.getSegmentId(); }
@Test public void testReadWithEndOffsetWithDataGreaterThanBuffer() throws Exception { byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; ByteBuffer wireData = createEventFromData(data); int wireDataSize = wireData.remaining(); //size of the data with header size. int bufferSize = wireDataSize / 2; //buffer is half the data length AsyncSegmentInputStream mockAsyncInputStream = mock(AsyncSegmentInputStream.class); when(mockAsyncInputStream.read(0, bufferSize)) .thenReturn(CompletableFuture.completedFuture(new WireCommands.SegmentRead(segment.getScopedName(), 0, false, false, ByteBufferUtils.slice(wireData, 0, bufferSize)))); when(mockAsyncInputStream.read(bufferSize, wireDataSize - bufferSize)) .thenReturn(CompletableFuture.completedFuture(new WireCommands.SegmentRead(segment.getScopedName(), bufferSize, false, false, ByteBufferUtils.slice(wireData, bufferSize, wireDataSize - bufferSize)))); //Create a SegmentInputStream where the Buffer can hold only part of the data. @Cleanup EventSegmentReaderImpl stream = SegmentInputStreamFactoryImpl.getEventSegmentReader(mockAsyncInputStream, 0, wireDataSize, bufferSize); ByteBuffer read = stream.read(); assertEquals(ByteBuffer.wrap(data), read); //verify we are reading the data. verify(mockAsyncInputStream, times(1)).read(0L, bufferSize); verify(mockAsyncInputStream, times(1)).read(bufferSize, wireDataSize - bufferSize); }
@Override @Synchronized public CompletableFuture<Void> fillBuffer() { log.trace("Filling buffer {}", this); Exceptions.checkNotClosed(asyncInput.isClosed(), this); try { issueRequestIfNeeded(); while (dataWaitingToGoInBuffer()) { handleRequest(); } } catch (SegmentTruncatedException e) { log.warn("Encountered exception filling buffer", e); return CompletableFuture.completedFuture(null); } return outstandingRequest == null ? CompletableFuture.completedFuture(null) : outstandingRequest.thenRun(Runnables.doNothing()); }
@Test public void testReadWithEndOffsetWithSmallerReads() throws Exception { byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; ByteBuffer wireData = createEventFromData(data); int wireDataSize = wireData.remaining(); //size of the data with header size. AsyncSegmentInputStream mockAsyncInputStream = mock(AsyncSegmentInputStream.class); when(mockAsyncInputStream.read(0, wireDataSize)) .thenReturn(CompletableFuture.completedFuture(new WireCommands.SegmentRead(segment.getScopedName(), 0, false, false, ByteBufferUtils.slice(wireData, 0, 2)))); when(mockAsyncInputStream.read(2, 16)) .thenReturn(CompletableFuture.completedFuture(new WireCommands.SegmentRead(segment.getScopedName(), 2, false, false, ByteBufferUtils.slice(wireData, 2, wireDataSize - 2)))); @Cleanup EventSegmentReaderImpl stream = SegmentInputStreamFactoryImpl.getEventSegmentReader(mockAsyncInputStream, 0, wireDataSize, SegmentInputStreamImpl.DEFAULT_BUFFER_SIZE); ByteBuffer read = stream.read(); assertEquals(ByteBuffer.wrap(data), read); //verify we are reading the data. verify(mockAsyncInputStream, times(1)).read(0L, wireDataSize); verify(mockAsyncInputStream, times(1)).read(2L, wireDataSize - 2); }
@Synchronized public int read(ByteBuffer toFill, long timeout) throws EndOfSegmentException, SegmentTruncatedException { Exceptions.checkNotClosed(asyncInput.isClosed(), this); if (this.offset >= this.endOffset) { log.debug("All events up to the configured end offset:{} have been read", endOffset);
@Test(expected = EndOfSegmentException.class) public void testReadWithEndOffset() throws Exception { byte[] data = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; ByteBuffer wireData = createEventFromData(data); int wireDataSize = wireData.remaining(); //size of the data with header size. AsyncSegmentInputStream mockAsyncInputStream = mock(AsyncSegmentInputStream.class); when(mockAsyncInputStream.read(0, wireDataSize)) .thenReturn(CompletableFuture.completedFuture(new WireCommands.SegmentRead(segment.getScopedName(), 0, false, false, wireData.slice()))); @Cleanup EventSegmentReaderImpl stream = SegmentInputStreamFactoryImpl.getEventSegmentReader(mockAsyncInputStream, 0, wireDataSize, SegmentInputStreamImpl.DEFAULT_BUFFER_SIZE); ByteBuffer read = stream.read(); assertEquals(ByteBuffer.wrap(data), read); //verify we are reading the data. verify(mockAsyncInputStream, times(1)).read(0L, wireDataSize); //ensure there is one invocation. stream.read(); // this should throw EndOfSegmentExceptiono as we have reached the endOffset }
when(mockAsyncInputStream.read(0, bufferSize)).thenReturn( completedFuture(new SegmentRead(segment.getScopedName(), 0, false, false, wireData.slice()))); when(mockAsyncInputStream.read(wireDataSize, expectedReadSize)).thenReturn( completedFuture(new SegmentRead(segment.getScopedName(), wireDataSize, false, false, wireData.slice()))); verify(mockAsyncInputStream, times(1)).read(0L, bufferSize); verify(mockAsyncInputStream, times(1)).read(wireDataSize, expectedReadSize); when(mockAsyncInputStream.read(0, wireDataSize)).thenReturn( completedFuture(new SegmentRead(segment.getScopedName(), 0, false, false, wireData.slice()))); verify(mockAsyncInputStream, times(1)).read(0L, wireDataSize); when(mockAsyncInputStream.read(0, 100)).thenReturn( completedFuture(new SegmentRead(segment.getScopedName(), 0, false, false, wireData.slice()))); @Cleanup verify(mockAsyncInputStream, times(1)).read(0L, 100);