use of io.pravega.shared.protocol.netty.WireCommands.SegmentIsTruncated in project pravega by pravega.
the class SegmentMetadataClientTest method testTruncateWithSegmentTruncationException.
@Test(timeout = 10000)
public void testTruncateWithSegmentTruncationException() throws ConnectionFailedException {
Segment segment = new Segment("scope", "testTruncate", 4);
PravegaNodeUri endpoint = new PravegaNodeUri("localhost", 0);
@Cleanup MockConnectionFactoryImpl cf = new MockConnectionFactoryImpl();
@Cleanup MockController controller = new MockController(endpoint.getEndpoint(), endpoint.getPort(), cf, true);
@Cleanup ClientConnection connection = mock(ClientConnection.class);
cf.provideConnection(endpoint, connection);
@Cleanup SegmentMetadataClientImpl client = new SegmentMetadataClientImpl(segment, controller, cf, "");
client.getConnection();
ReplyProcessor processor = cf.getProcessor(endpoint);
AtomicLong requestId = new AtomicLong();
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
WireCommands.TruncateSegment truncateSegment = invocation.getArgument(0);
processor.process(new SegmentIsTruncated(truncateSegment.getRequestId(), segment.getScopedName(), 124L, "", 124L));
requestId.set(truncateSegment.getRequestId());
return null;
}
}).when(connection).send(any(WireCommands.TruncateSegment.class));
client.truncateSegment(123L).join();
Mockito.verify(connection).send(Mockito.eq(new WireCommands.TruncateSegment(requestId.get(), segment.getScopedName(), 123L, "")));
}
use of io.pravega.shared.protocol.netty.WireCommands.SegmentIsTruncated in project pravega by pravega.
the class PravegaRequestProcessor method handleException.
private Void handleException(long requestId, String segment, long offset, String operation, Throwable u) {
if (u == null) {
IllegalStateException exception = new IllegalStateException("No exception to handle.");
log.error(requestId, "Error (Segment = '{}', Operation = '{}')", segment, operation, exception);
throw exception;
}
u = Exceptions.unwrap(u);
String clientReplyStackTrace = replyWithStackTraceOnError ? Throwables.getStackTraceAsString(u) : EMPTY_STACK_TRACE;
final Consumer<Throwable> failureHandler = t -> {
log.error(requestId, "Error (Segment = '{}', Operation = '{}')", segment, "handling result of " + operation, t);
connection.close();
};
if (u instanceof StreamSegmentExistsException) {
log.info(requestId, "Segment '{}' already exists and cannot perform operation '{}'.", segment, operation);
invokeSafely(connection::send, new SegmentAlreadyExists(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (u instanceof StreamSegmentNotExistsException) {
log.warn(requestId, "Segment '{}' does not exist and cannot perform operation '{}'.", segment, operation);
invokeSafely(connection::send, new NoSuchSegment(requestId, segment, clientReplyStackTrace, offset), failureHandler);
} else if (u instanceof StreamSegmentSealedException) {
log.info(requestId, "Segment '{}' is sealed and cannot perform operation '{}'.", segment, operation);
invokeSafely(connection::send, new SegmentIsSealed(requestId, segment, clientReplyStackTrace, offset), failureHandler);
} else if (u instanceof ContainerNotFoundException) {
int containerId = ((ContainerNotFoundException) u).getContainerId();
log.warn(requestId, "Wrong host. Segment = '{}' (Container {}) is not owned. Operation = '{}').", segment, containerId, operation);
invokeSafely(connection::send, new WrongHost(requestId, segment, "", clientReplyStackTrace), failureHandler);
} else if (u instanceof ReadCancellationException) {
log.info(requestId, "Sending empty response on connection {} while reading segment {} due to CancellationException.", connection, segment);
invokeSafely(connection::send, new SegmentRead(segment, offset, true, false, EMPTY_BUFFER, requestId), failureHandler);
} else if (u instanceof CancellationException) {
log.info(requestId, "Closing connection {} while performing {} due to {}.", connection, operation, u.toString());
connection.close();
} else if (u instanceof TokenExpiredException) {
log.warn(requestId, "Expired token during operation {}", operation);
invokeSafely(connection::send, new AuthTokenCheckFailed(requestId, clientReplyStackTrace, AuthTokenCheckFailed.ErrorCode.TOKEN_EXPIRED), failureHandler);
} else if (u instanceof TokenException) {
log.warn(requestId, "Token exception encountered during operation {}.", operation, u);
invokeSafely(connection::send, new AuthTokenCheckFailed(requestId, clientReplyStackTrace, AuthTokenCheckFailed.ErrorCode.TOKEN_CHECK_FAILED), failureHandler);
} else if (u instanceof UnsupportedOperationException) {
log.warn(requestId, "Unsupported Operation '{}'.", operation, u);
invokeSafely(connection::send, new OperationUnsupported(requestId, operation, clientReplyStackTrace), failureHandler);
} else if (u instanceof BadOffsetException) {
BadOffsetException badOffset = (BadOffsetException) u;
log.info(requestId, "Segment '{}' is truncated and cannot perform operation '{}' at offset '{}'", segment, operation, offset);
invokeSafely(connection::send, new SegmentIsTruncated(requestId, segment, badOffset.getExpectedOffset(), clientReplyStackTrace, offset), failureHandler);
} else if (u instanceof TableSegmentNotEmptyException) {
log.warn(requestId, "Table segment '{}' is not empty to perform '{}'.", segment, operation);
invokeSafely(connection::send, new TableSegmentNotEmpty(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (u instanceof KeyNotExistsException) {
log.warn(requestId, "Conditional update on Table segment '{}' failed as the key does not exist.", segment);
invokeSafely(connection::send, new WireCommands.TableKeyDoesNotExist(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (u instanceof BadKeyVersionException) {
log.warn(requestId, "Conditional update on Table segment '{}' failed due to bad key version.", segment);
invokeSafely(connection::send, new WireCommands.TableKeyBadVersion(requestId, segment, clientReplyStackTrace), failureHandler);
} else if (errorCodeExists(u)) {
log.warn(requestId, "Operation on segment '{}' failed due to a {}.", segment, u.getClass());
invokeSafely(connection::send, new WireCommands.ErrorMessage(requestId, segment, u.getMessage(), WireCommands.ErrorMessage.ErrorCode.valueOf(u.getClass())), failureHandler);
} else {
logError(requestId, segment, operation, u);
// Closing connection should reinitialize things, and hopefully fix the problem
connection.close();
throw new IllegalStateException("Unknown exception.", u);
}
return null;
}
use of io.pravega.shared.protocol.netty.WireCommands.SegmentIsTruncated in project pravega by pravega.
the class PravegaRequestProcessor method handleReadResult.
/**
* Handles a readResult.
* If there are cached entries that can be returned without blocking only these are returned.
* Otherwise the call will request the data and setup a callback to return the data when it is available.
* If no data is available but it was detected that the Segment had been truncated beyond the current offset,
* an appropriate message is sent back over the connection.
*/
private void handleReadResult(ReadSegment request, ReadResult result) {
String segment = request.getSegment();
ArrayList<BufferView> cachedEntries = new ArrayList<>();
ReadResultEntry nonCachedEntry = collectCachedEntries(request.getOffset(), result, cachedEntries);
final String operation = "readSegment";
boolean truncated = nonCachedEntry != null && nonCachedEntry.getType() == Truncated;
boolean endOfSegment = nonCachedEntry != null && nonCachedEntry.getType() == EndOfStreamSegment;
boolean atTail = nonCachedEntry != null && nonCachedEntry.getType() == Future;
if (!cachedEntries.isEmpty() || endOfSegment) {
// We managed to collect some data. Send it.
ByteBuf data = toByteBuf(cachedEntries);
SegmentRead reply = new SegmentRead(segment, request.getOffset(), atTail, endOfSegment, data, request.getRequestId());
connection.send(reply);
this.statsRecorder.read(segment, reply.getData().readableBytes());
} else if (truncated) {
// We didn't collect any data, instead we determined that the current read offset was truncated.
// Determine the current Start Offset and send that back.
segmentStore.getStreamSegmentInfo(segment, TIMEOUT).thenAccept(info -> connection.send(new SegmentIsTruncated(request.getRequestId(), segment, info.getStartOffset(), EMPTY_STACK_TRACE, nonCachedEntry.getStreamSegmentOffset()))).exceptionally(e -> handleException(request.getRequestId(), segment, nonCachedEntry.getStreamSegmentOffset(), operation, wrapCancellationException(e)));
} else {
Preconditions.checkState(nonCachedEntry != null, "No ReadResultEntries returned from read!?");
nonCachedEntry.requestContent(TIMEOUT);
nonCachedEntry.getContent().thenAccept(contents -> {
ByteBuf data = toByteBuf(Collections.singletonList(contents));
SegmentRead reply = new SegmentRead(segment, nonCachedEntry.getStreamSegmentOffset(), atTail, endOfSegment, data, request.getRequestId());
connection.send(reply);
this.statsRecorder.read(segment, reply.getData().readableBytes());
}).exceptionally(exception -> {
Throwable e = Exceptions.unwrap(exception);
if (e instanceof StreamSegmentTruncatedException) {
// The Segment may have been truncated in Storage after we got this entry but before we managed
// to make a read. In that case, send the appropriate error back.
final String clientReplyStackTrace = replyWithStackTraceOnError ? e.getMessage() : EMPTY_STACK_TRACE;
connection.send(new SegmentIsTruncated(request.getRequestId(), segment, ((StreamSegmentTruncatedException) e).getStartOffset(), clientReplyStackTrace, nonCachedEntry.getStreamSegmentOffset()));
} else {
handleException(request.getRequestId(), segment, nonCachedEntry.getStreamSegmentOffset(), operation, wrapCancellationException(e));
}
return null;
}).exceptionally(e -> handleException(request.getRequestId(), segment, nonCachedEntry.getStreamSegmentOffset(), operation, wrapCancellationException(e)));
}
}
Aggregations