use of com.couchbase.client.core.msg.Response in project couchbase-jvm-clients by couchbase.
the class KeyValueMessageHandler method write.
@Override
@SuppressWarnings({ "unchecked" })
public void write(final ChannelHandlerContext ctx, final Object msg, final ChannelPromise promise) {
if (msg instanceof KeyValueRequest) {
KeyValueRequest<Response> request = (KeyValueRequest<Response>) msg;
int opaque = request.opaque();
writtenRequests.put(opaque, request);
try {
ctx.write(request.encode(ctx.alloc(), opaque, channelContext), promise);
writtenRequestDispatchTimings.put(opaque, (Long) System.nanoTime());
if (request.requestSpan() != null) {
RequestTracer tracer = endpointContext.environment().requestTracer();
RequestSpan dispatchSpan = tracer.requestSpan(TracingIdentifiers.SPAN_DISPATCH, request.requestSpan());
if (!isInternalTracer) {
setCommonDispatchSpanAttributes(dispatchSpan, ctx.channel().attr(ChannelAttributes.CHANNEL_ID_KEY).get(), ioContext.localHostname(), ioContext.localPort(), endpoint.remoteHostname(), endpoint.remotePort(), null);
setNumericOperationId(dispatchSpan, request.opaque());
setCommonKVSpanAttributes(dispatchSpan, request);
}
writtenRequestDispatchSpans.put(opaque, dispatchSpan);
}
} catch (Throwable err) {
writtenRequests.remove(opaque);
if (err instanceof CollectionNotFoundException) {
if (channelContext.collectionsEnabled()) {
ConfigurationProvider cp = ioContext.core().configurationProvider();
if (cp.collectionRefreshInProgress(request.collectionIdentifier())) {
RetryOrchestrator.maybeRetry(ioContext, request, RetryReason.COLLECTION_MAP_REFRESH_IN_PROGRESS);
} else if (cp.config().bucketConfig(request.bucket()) instanceof MemcachedBucketConfig) {
request.fail(FeatureNotAvailableException.collectionsForMemcached());
} else {
handleOutdatedCollection(request, RetryReason.COLLECTION_NOT_FOUND);
}
return;
}
}
request.fail(err);
}
} else {
eventBus.publish(new InvalidRequestDetectedEvent(ioContext, ServiceType.KV, msg));
ctx.channel().close().addListener(f -> eventBus.publish(new ChannelClosedProactivelyEvent(ioContext, ChannelClosedProactivelyEvent.Reason.INVALID_REQUEST_DETECTED)));
}
}
use of com.couchbase.client.core.msg.Response in project couchbase-jvm-clients by couchbase.
the class KeyValueMessageHandler method decode.
/**
* Main method to start dispatching the decode.
*
* @param ctx the channel handler context from netty.
* @param response the response to decode and handle.
*/
private void decode(final ChannelHandlerContext ctx, final ByteBuf response) {
int opaque = MemcacheProtocol.opaque(response);
KeyValueRequest<Response> request = writtenRequests.remove(opaque);
if (request == null) {
handleUnknownResponseReceived(ctx, response);
return;
}
long serverTime = MemcacheProtocol.parseServerDurationFromResponse(response);
request.context().serverLatency(serverTime);
long start = writtenRequestDispatchTimings.remove(opaque);
request.context().dispatchLatency(System.nanoTime() - start);
RequestSpan dispatchSpan = writtenRequestDispatchSpans.remove(opaque);
if (dispatchSpan != null) {
if (!isInternalTracer) {
TracingUtils.setServerDurationAttribute(dispatchSpan, serverTime);
}
dispatchSpan.end();
}
short statusCode = MemcacheProtocol.status(response);
ResponseStatus status = MemcacheProtocol.decodeStatus(statusCode);
ErrorMap.ErrorCode errorCode = status != ResponseStatus.SUCCESS ? decodeErrorCode(statusCode) : null;
if (errorCode != null) {
request.errorCode(errorCode);
}
boolean errorUnknown = false;
if (status == ResponseStatus.UNKNOWN) {
errorUnknown = true;
if (errorCode != null) {
ioContext.environment().eventBus().publish(new KeyValueErrorMapCodeHandledEvent(ioContext, errorCode));
status = handleErrorCode(ctx, errorCode);
}
ioContext.environment().eventBus().publish(new UnknownResponseStatusReceivedEvent(ioContext, statusCode));
}
if (status == ResponseStatus.NOT_MY_VBUCKET) {
handleNotMyVbucket(request, response);
} else if (status == ResponseStatus.UNKNOWN_COLLECTION) {
handleOutdatedCollection(request, RetryReason.KV_COLLECTION_OUTDATED);
} else if (errorUnknown && errorMapIndicatesRetry(errorCode)) {
RetryOrchestrator.maybeRetry(ioContext, request, RetryReason.KV_ERROR_MAP_INDICATED);
} else if (statusIndicatesInvalidChannel(status)) {
closeChannelWithReason(ioContext, ctx, ChannelClosedProactivelyEvent.Reason.KV_RESPONSE_CONTAINED_CLOSE_INDICATION);
} else {
RetryReason retryReason = statusCodeIndicatesRetry(status, request);
if (retryReason == null) {
if (!request.completed()) {
decodeAndComplete(request, response);
} else {
ioContext.environment().orphanReporter().report(request);
}
} else {
RetryOrchestrator.maybeRetry(ioContext, request, retryReason);
}
}
}
use of com.couchbase.client.core.msg.Response in project couchbase-jvm-clients by couchbase.
the class KeyValueMessageHandler method handleNotMyVbucket.
/**
* Helper method to handle a "not my vbucket" response.
*
* @param request the request to retry.
* @param response the response to extract the config from, potentially.
*/
private void handleNotMyVbucket(final KeyValueRequest<Response> request, final ByteBuf response) {
request.indicateRejectedWithNotMyVbucket();
eventBus.publish(new NotMyVbucketReceivedEvent(ioContext, request.partition()));
final String origin = request.context().lastDispatchedTo() != null ? request.context().lastDispatchedTo().hostname() : null;
RetryOrchestrator.maybeRetry(ioContext, request, RetryReason.KV_NOT_MY_VBUCKET);
body(response).map(b -> b.toString(UTF_8).trim()).filter(c -> c.startsWith("{")).ifPresent(c -> ioContext.core().configurationProvider().proposeBucketConfig(new ProposedBucketConfigContext(request.bucket(), c, origin)));
}
use of com.couchbase.client.core.msg.Response in project couchbase-jvm-clients by couchbase.
the class NodeTest method retriesIfGlobalServiceNotFound.
@Test
void retriesIfGlobalServiceNotFound() {
final Service s = mock(Service.class);
final AtomicReference<Request<?>> retried = new AtomicReference<>();
Node node = new Node(CTX, mock(NodeIdentifier.class), NO_ALTERNATE) {
@Override
protected Service createService(ServiceType serviceType, int port, Optional<String> bucket) {
when(s.state()).thenReturn(ServiceState.CONNECTED);
when(s.states()).thenReturn(DirectProcessor.create());
when(s.type()).thenReturn(serviceType);
return s;
}
@Override
protected <R extends Request<? extends Response>> void sendIntoRetry(R request) {
retried.set(request);
}
};
QueryRequest r = mock(QueryRequest.class);
when(r.serviceType()).thenReturn(ServiceType.QUERY);
node.send(r);
verify(s, never()).send(eq(r));
assertEquals(r, retried.get());
}
use of com.couchbase.client.core.msg.Response in project couchbase-jvm-clients by couchbase.
the class KeyValueMessageHandler method decodeAndComplete.
/**
* Tries to decode the response and succeed the request.
* <p>
* If decoding fails, will fail the underlying request as well.
*
* @param request the request to decode and complete.
* @param response the raw response to decode.
*/
private void decodeAndComplete(final KeyValueRequest<Response> request, final ByteBuf response) {
try {
Response decoded = request.decode(response, channelContext);
request.succeed(decoded);
} catch (Throwable t) {
request.fail(new DecodingFailureException(t));
}
}
Aggregations