private void verifyIsAtCorrectOffset(WireCommands.SegmentRead segmentRead) { long offsetRead = segmentRead.getOffset() + segmentRead.getData().position(); long expectedOffset = offset + buffer.dataAvailable(); checkState(offsetRead == expectedOffset, "ReadSegment returned data for the wrong offset %s vs %s", offsetRead, expectedOffset); }
@Override @Synchronized public int bytesInBuffer() { int result = buffer.dataAvailable(); boolean atEnd = receivedEndOfSegment || receivedTruncated || (outstandingRequest != null && outstandingRequest.isCompletedExceptionally()); if (outstandingRequest != null && Futures.isSuccessful(outstandingRequest)) { SegmentRead request = outstandingRequest.join(); result += request.getData().remaining(); atEnd |= request.isEndOfSegment(); } if (result <= 0 && atEnd) { result = -1; } log.trace("bytesInBuffer {} on segment {} status is {}", result, getSegmentId(), this); return result; }
private void handleRequest() throws SegmentTruncatedException { SegmentRead segmentRead; try { segmentRead = outstandingRequest.join(); } catch (Exception e) { outstandingRequest = null; if (Exceptions.unwrap(e) instanceof SegmentTruncatedException) { receivedTruncated = true; throw new SegmentTruncatedException(e); } throw e; } verifyIsAtCorrectOffset(segmentRead); if (segmentRead.getData().hasRemaining()) { buffer.fill(segmentRead.getData()); } if (segmentRead.isEndOfSegment()) { receivedEndOfSegment = true; } if (!segmentRead.getData().hasRemaining()) { outstandingRequest = null; issueRequestIfNeeded(); } }
SegmentRead reply = new SegmentRead(segment, request.getOffset(), atTail, endOfSegment, data); connection.send(reply); dynamicLogger.incCounterValue(globalMetricName(SEGMENT_READ_BYTES), reply.getData().array().length); dynamicLogger.incCounterValue(nameFromSegment(SEGMENT_READ_BYTES, segment), reply.getData().array().length); } else if (truncated) { SegmentRead reply = new SegmentRead(segment, nonCachedEntry.getStreamSegmentOffset(), false, endOfSegment, data); connection.send(reply); dynamicLogger.incCounterValue(globalMetricName(SEGMENT_READ_BYTES), reply.getData().array().length); dynamicLogger.incCounterValue(nameFromSegment(SEGMENT_READ_BYTES, segment), reply.getData().array().length); }) .exceptionally(e -> {
assertTrue(result.isAtTail()); assertFalse(result.isEndOfSegment()); actual.put(result.getData()); if (actual.position() < actual.capacity()) {
@Test(timeout = 10000) public void testWrongOffsetReturned() throws ConnectionFailedException { Segment segment = new Segment("scope", "testWrongOffsetReturned", 0); byte[] good = new byte[] { 0, 1, 2, 3, 4 }; byte[] bad = new byte[] { 9, 8, 7, 6 }; PravegaNodeUri endpoint = new PravegaNodeUri("localhost", SERVICE_PORT); MockConnectionFactoryImpl connectionFactory = new MockConnectionFactoryImpl(); MockController controller = new MockController(endpoint.getEndpoint(), endpoint.getPort(), connectionFactory); @Cleanup AsyncSegmentInputStreamImpl in = new AsyncSegmentInputStreamImpl(controller, connectionFactory, segment, ""); ClientConnection c = mock(ClientConnection.class); connectionFactory.provideConnection(endpoint, c); CompletableFuture<SegmentRead> readFuture = in.read(1234, 5678); AssertExtensions.assertBlocks(() -> readFuture.get(), () -> { ReplyProcessor processor = connectionFactory.getProcessor(endpoint); processor.segmentRead(new WireCommands.SegmentRead(segment.getScopedName(), 1235, false, false, ByteBuffer.wrap(bad))); processor.segmentRead(new WireCommands.SegmentRead(segment.getScopedName(), 1234, false, false, ByteBuffer.wrap(good))); }); verify(c).sendAsync(Mockito.eq(new WireCommands.ReadSegment(segment.getScopedName(), 1234, 5678, "")), Mockito.any(ClientConnection.CompletedCallback.class)); assertTrue(Futures.isSuccessful(readFuture)); assertEquals(ByteBuffer.wrap(good), readFuture.join().getData()); verifyNoMoreInteractions(c); }