Details
-
Improvement
-
Resolution: Fixed
-
Major
-
None
-
None
-
None
-
0
Description
BaseRequest.cancel() is executed synchronously when requests expire - when many requests expire the timer thread cannot expire them fast enough.
a) AmbiguousTimeoutException and UnambiguousTimeoutException have stacktraces that are expensive to generate, and not useful - they just show the timer thread. The improvement is to construct them without the stacktrace ( writableStacktrace=false )
b) request.completeExceptionally(exception) creates a new CompletionException(exception) from the exception if it is not a CompletionException. This results in the Throwable constructor being called, which calls cause.toString() which in turn calls getMessage() which is very expensive for CouchbaseExceptions that have an error context. The improvement is to construct the CompletionException with new CompletionException( "timeout", cause), which avoids calling cause.toString() and also cause.getMessage().
public Throwable(Throwable cause) { |
fillInStackTrace();
|
detailMessage = (cause==null ? null : cause.toString()); |
this.cause = cause; |
}
|
public final String getMessage() { |
final String output = super.getMessage(); |
return ctx != null ? output + " " + ctx.exportAsString(Context.ExportFormat.JSON) : output; |
}
|
c) CompletionException is constructed with a stacktrace which is expensive to generate and not useful as it just shows the timer thread. However, there is no constructor for CompletionException that allows constructing it without the stacktrace. So no improvement is possible. Furthermore, if a static, pre-generated CompletionException was used, it could not show the ErrorContext.
Improvement to BaseRequest.cancel()
@Override |
public void cancel(final CancellationReason reason, Function<Throwable, Throwable> exceptionTranslator) { |
if (STATE_UPDATER.compareAndSet(this, State.INCOMPLETE, State.CANCELLED)) { |
cancelTimeoutRegistration();
|
|
cancellationReason = reason;
|
final Throwable exception; |
|
final String msg = this.getClass().getSimpleName() + ", Reason: " + reason; |
final CancellationErrorContext ctx = new CancellationErrorContext(context()); |
if (reason == CancellationReason.TIMEOUT) { |
exception = new CompletionException(msg, idempotent() ? new UnambiguousTimeoutException(msg, ctx) : new AmbiguousTimeoutException(msg, ctx)); |
} else { |
exception = new CompletionException(msg, new RequestCanceledException(msg, reason, ctx)); |
}
|
response.completeExceptionally(exceptionTranslator.apply(exception));
|
}
|
}
|
Improvement to UnambiguousTimeoutException/AmbiguousTimeoutException. Method needs to be propagated to TimeoutException and CouchbaseException .
public UnambiguousTimeoutException(final String message, final CancellationErrorContext ctx) { |
//super(message, ctx); |
super(message, null /* cause */, true /* enableSuppression */, false /*writableStackTrace */, ctx); |
}
|
Attachments
For Gerrit Dashboard: JVMCBC-1428 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
200681,1 | JVMCBC-1428 GetLoadTest | master | transactions-fit-performer | Status: NEW | 0 | +1 |
200682,1 | JVMCBC-1428 Timeout Lag | master | couchbase-jvm-clients | Status: NEW | 0 | -1 |
200283,6 | JVMCBC-1428 - Improvements for Timeouts | master | couchbase-jvm-clients | Status: MERGED | +2 | +1 |
201325,3 | Partial revert "JVMCBC-1428 - Improvements for Timeouts" | master | couchbase-jvm-clients | Status: MERGED | +2 | +1 |