diff --git a/context/src/main/java/io/grpc/Context.java b/context/src/main/java/io/grpc/Context.java index af4417a166..3c12dba647 100644 --- a/context/src/main/java/io/grpc/Context.java +++ b/context/src/main/java/io/grpc/Context.java @@ -60,11 +60,11 @@ import java.util.logging.Logger; * *
* Context withCredential = Context.current().withValue(CRED_KEY, cred);
- * executorService.execute(withCredential.wrap(new Runnable() {
+ * withCredential.run(new Runnable() {
* public void run() {
* readUserRecords(userId, CRED_KEY.get());
* }
- * }));
+ * });
*
*
* Contexts are also used to represent a scoped unit of work. When the unit of work is done the @@ -78,7 +78,7 @@ import java.util.logging.Logger; *
* CancellableContext withCancellation = Context.current().withCancellation();
* try {
- * executorService.execute(withCancellation.wrap(new Runnable() {
+ * withCancellation.run(new Runnable() {
* public void run() {
* while (waitingForData() && !Context.current().isCancelled()) {}
* }
@@ -95,12 +95,13 @@ import java.util.logging.Logger;
*
* Notes and cautions on use:
*
Sample usage: *
* Context.CancellableContext withCancellation = Context.current().withCancellation();
* try {
- * executorService.execute(withCancellation.wrap(new Runnable() {
+ * withCancellation.run(new Runnable() {
* public void run() {
* Context current = Context.current();
* while (!current.isCancelled()) {
@@ -244,9 +246,8 @@ public class Context {
* }
* }
* });
- * doSomethingRelatedWork();
- * } catch (Throwable t) {
- * withCancellation.cancel(t);
+ * } finally {
+ * withCancellation.cancel(null);
* }
*
*/
@@ -257,20 +258,26 @@ public class Context {
/**
* Create a new context which will cancel itself after the given {@code duration} from now.
* The returned context will cascade cancellation of its parent. Callers may explicitly cancel
- * the returned context prior to the deadline just as for {@link #withCancellation()},
+ * the returned context prior to the deadline just as for {@link #withCancellation()}. If the unit
+ * of work completes before the deadline, the context should be explicitly cancelled to allow
+ * it to be garbage collected.
*
* Sample usage: *
- * Context.CancellableContext withDeadline = Context.current().withDeadlineAfter(5,
- * TimeUnit.SECONDS, scheduler);
- * executorService.execute(withDeadline.wrap(new Runnable() {
- * public void run() {
- * Context current = Context.current();
- * while (!current.isCancelled()) {
- * keepWorking();
+ * Context.CancellableContext withDeadline = Context.current()
+ * .withDeadlineAfter(5, TimeUnit.SECONDS, scheduler);
+ * try {
+ * withDeadline.run(new Runnable() {
+ * public void run() {
+ * Context current = Context.current();
+ * while (!current.isCancelled()) {
+ * keepWorking();
+ * }
* }
- * }
- * });
+ * });
+ * } finally {
+ * withDeadline.cancel(null);
+ * }
*
*/
public CancellableContext withDeadlineAfter(long duration, TimeUnit unit,
@@ -281,20 +288,26 @@ public class Context {
/**
* Create a new context which will cancel itself at the given {@link Deadline}.
* The returned context will cascade cancellation of its parent. Callers may explicitly cancel
- * the returned context prior to the deadline just as for {@link #withCancellation()},
+ * the returned context prior to the deadline just as for {@link #withCancellation()}. If the unit
+ * of work completes before the deadline, the context should be explicitly cancelled to allow
+ * it to be garbage collected.
*
* Sample usage: *
* Context.CancellableContext withDeadline = Context.current()
- * .withDeadline(someReceivedDeadline);
- * executorService.execute(withDeadline.wrap(new Runnable() {
- * public void run() {
- * Context current = Context.current();
- * while (!current.isCancelled()) {
- * keepWorking();
+ * .withDeadline(someReceivedDeadline, scheduler);
+ * try {
+ * withDeadline.run(new Runnable() {
+ * public void run() {
+ * Context current = Context.current();
+ * while (!current.isCancelled() && moreWorkToDo()) {
+ * keepWorking();
+ * }
* }
- * }
- * });
+ * });
+ * } finally {
+ * withDeadline.cancel(null);
+ * }
*
*/
public CancellableContext withDeadline(Deadline deadline,
@@ -310,11 +323,11 @@ public class Context {
*
* Context withCredential = Context.current().withValue(CRED_KEY, cred);
- * executorService.execute(withCredential.wrap(new Runnable() {
+ * withCredential.run(new Runnable() {
* public void run() {
* readUserRecords(userId, CRED_KEY.get());
* }
- * }));
+ * });
*
*
*/
@@ -366,10 +379,19 @@ public class Context {
* previously current context is returned. It is allowed to attach contexts where {@link
* #isCancelled()} is {@code true}.
*
- * Instead of using {@link #attach()} & {@link #detach(Context)} most use-cases are better + *
Instead of using {@code attach()} and {@link #detach(Context)} most use-cases are better * served by using the {@link #run(Runnable)} or {@link #call(java.util.concurrent.Callable)} to * execute work immediately within a context's scope. If work needs to be done in other threads it * is recommended to use the 'wrap' methods or to use a propagating executor. + * + *
All calls to {@code attach()} should have a corresponding {@link #detach(Context)} within + * the same method: + *
{@code Context previous = someContext.attach();
+ * try {
+ * // Do work
+ * } finally {
+ * someContext.detach(previous);
+ * }}
*/
public Context attach() {
Context previous = current();
@@ -378,8 +400,7 @@ public class Context {
}
/**
- * Detach the current context and attach the provided replacement which should be the context of
- * the outer scope, thus exit the current scope.
+ * Reverse an {@code attach()}, restoring the previous context and exiting the current scope.
*
* This context should be the same context that was previously {@link #attach attached}. The * provided replacement should be what was returned by the same {@link #attach attach()} call. If @@ -649,7 +670,9 @@ public class Context { /** * A context which inherits cancellation from its parent but which can also be independently - * cancelled and which will propagate cancellation to its descendants. + * cancelled and which will propagate cancellation to its descendants. To avoid leaking memory, + * every CancellableContext must have a defined lifetime, after which it is guaranteed to be + * cancelled. */ public static final class CancellableContext extends Context { diff --git a/context/src/main/java/io/grpc/Deadline.java b/context/src/main/java/io/grpc/Deadline.java index c3ab53e329..732088b5b3 100644 --- a/context/src/main/java/io/grpc/Deadline.java +++ b/context/src/main/java/io/grpc/Deadline.java @@ -36,7 +36,14 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; /** - * An absolute deadline in system time. + * An absolute point in time, generally for tracking when a task should be completed. A deadline is + * immutable except for the passage of time causing it to expire. + * + *
Many systems use timeouts, which are relative to the start of the operation. However, being
+ * relative causes them to be poorly suited for managing higher-level tasks where there are many
+ * components and sub-operations that may not know the time of the initial "start of the operation."
+ * However, a timeout can be converted to a {@code Deadline} at the start of the operation and then
+ * passed to the various components unambiguously.
*/
public final class Deadline implements Comparable Applications can add common cross-cutting behaviors to stubs by decorating Channel
* implementations using {@link ClientInterceptor}. It is expected that most application
* code will not use this class directly but rather work with stubs that have been bound to a
- * Channel that was decorated during application initialization,
+ * Channel that was decorated during application initialization.
*/
@ThreadSafe
public abstract class Channel {
diff --git a/core/src/main/java/io/grpc/ClientCall.java b/core/src/main/java/io/grpc/ClientCall.java
index d05def4a60..c12da4fc25 100644
--- a/core/src/main/java/io/grpc/ClientCall.java
+++ b/core/src/main/java/io/grpc/ClientCall.java
@@ -236,7 +236,8 @@ public abstract class ClientCall This implementation always returns {@code true}.
+ * This abstract class's implementation always returns {@code true}. Implementations generally
+ * override the method.
*/
public boolean isReady() {
return true;
diff --git a/core/src/main/java/io/grpc/LoadBalancer.java b/core/src/main/java/io/grpc/LoadBalancer.java
index c9c32c42c0..ff35ef6e61 100644
--- a/core/src/main/java/io/grpc/LoadBalancer.java
+++ b/core/src/main/java/io/grpc/LoadBalancer.java
@@ -198,8 +198,6 @@ public abstract class LoadBalancer {
/**
* The main balancing logic. It must be thread-safe. Typically it should only
* synchronize on its own state, and avoid synchronizing with the LoadBalancer's state.
- *
- * Note: Implementations should override exactly one {@code pickSubchannel}.
*/
@ThreadSafe
public abstract static class SubchannelPicker {
diff --git a/core/src/main/java/io/grpc/ServerBuilder.java b/core/src/main/java/io/grpc/ServerBuilder.java
index 5fe0546835..d0c5f6e188 100644
--- a/core/src/main/java/io/grpc/ServerBuilder.java
+++ b/core/src/main/java/io/grpc/ServerBuilder.java
@@ -129,7 +129,9 @@ public abstract class ServerBuilder Multiple filters maybe registered to a server, in which case the output of a filter is the
* input of the next filter. For example, what returned by {@link #transportReady} of a filter is
* passed to the same method of the next filter, and the last filter's return value is the effective
- * transport attributes. A filter should modify the passed-in attributes instead of creating one
- * from scratch.
+ * transport attributes.
*
* {@link Grpc} defines commonly used attributes.
*/
diff --git a/stub/src/main/java/io/grpc/stub/AbstractStub.java b/stub/src/main/java/io/grpc/stub/AbstractStub.java
index 8b8d33032f..a1f575b5ee 100644
--- a/stub/src/main/java/io/grpc/stub/AbstractStub.java
+++ b/stub/src/main/java/io/grpc/stub/AbstractStub.java
@@ -43,16 +43,20 @@ import io.grpc.ExperimentalApi;
import io.grpc.ManagedChannelBuilder;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
/**
- * Common base type for stub implementations.
+ * Common base type for stub implementations. Stub configuration is immutable; changing the
+ * configuration returns a new stub with updated configuration. Changing the configuration is cheap
+ * and may be done before every RPC, such as would be common when using {@link #withDeadlineAfter}.
*
- * This is the base class of the stub classes from the generated code. It allows for
- * reconfiguration, e.g., attaching interceptors to the stub.
+ * Configuration is stored in {@link CallOptions} and is passed to the {@link Channel} when
+ * performing an RPC.
*
* @since 1.0.0
* @param the concrete type of this stub.
*/
+@ThreadSafe
public abstract class AbstractStub> {
private final Channel channel;
private final CallOptions callOptions;
diff --git a/stub/src/main/java/io/grpc/stub/CallStreamObserver.java b/stub/src/main/java/io/grpc/stub/CallStreamObserver.java
index 67003181a3..e92ef278dd 100644
--- a/stub/src/main/java/io/grpc/stub/CallStreamObserver.java
+++ b/stub/src/main/java/io/grpc/stub/CallStreamObserver.java
@@ -54,8 +54,10 @@ import io.grpc.ExperimentalApi;
public abstract class CallStreamObserver