context: allow creating Deadline with custom Ticker. (#6031)

This makes Deadline more test-friendly. Next step is to allow
ServerBuilder to take a custom Ticker and use it for creating
incoming Deadlines. With both changes in, application logic will be
able to verify the Deadlines they set.
This commit is contained in:
Kun Zhang 2019-07-31 11:26:51 -07:00 committed by GitHub
parent e14f8de4ab
commit f9509694b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 13 deletions

View File

@ -255,7 +255,7 @@ public class CallOptionsTest {
private long time; private long time;
@Override @Override
public long read() { public long nanoTime() {
return time; return time;
} }

View File

@ -39,7 +39,20 @@ public final class Deadline implements Comparable<Deadline> {
private static final long NANOS_PER_SECOND = TimeUnit.SECONDS.toNanos(1); private static final long NANOS_PER_SECOND = TimeUnit.SECONDS.toNanos(1);
/** /**
* Create a deadline that will expire at the specified offset from the current system clock. * Returns the ticker that's based on system clock.
*
* <p>This is <strong>EXPERIMENTAL</strong> API and may subject to change. If you'd like it to be
* stabilized or have any feedback, please
* <href a="https://github.com/grpc/grpc-java/issues/6030">let us know</a>.
*/
public static Ticker getSystemTicker() {
return SYSTEM_TICKER;
}
/**
* Create a deadline that will expire at the specified offset based on the {@link #getSystemTicker
* system ticker}.
*
* @param duration A non-negative duration. * @param duration A non-negative duration.
* @param units The time unit for the duration. * @param units The time unit for the duration.
* @return A new deadline. * @return A new deadline.
@ -48,8 +61,19 @@ public final class Deadline implements Comparable<Deadline> {
return after(duration, units, SYSTEM_TICKER); return after(duration, units, SYSTEM_TICKER);
} }
// For testing /**
static Deadline after(long duration, TimeUnit units, Ticker ticker) { * Create a deadline that will expire at the specified offset based on the given {@link Ticker}.
*
* <p>This is <strong>EXPERIMENTAL</strong> API and may subject to change. If you'd like it to be
* stabilized or have any feedback, please
* <href a="https://github.com/grpc/grpc-java/issues/6030">let us know</a>.
*
* @param duration A non-negative duration.
* @param units The time unit for the duration.
* @param ticker Where this deadline refer the current time
* @return A new deadline.
*/
public static Deadline after(long duration, TimeUnit units, Ticker ticker) {
checkNotNull(units, "units"); checkNotNull(units, "units");
return new Deadline(ticker, units.toNanos(duration), true); return new Deadline(ticker, units.toNanos(duration), true);
} }
@ -59,7 +83,7 @@ public final class Deadline implements Comparable<Deadline> {
private volatile boolean expired; private volatile boolean expired;
private Deadline(Ticker ticker, long offset, boolean baseInstantAlreadyExpired) { private Deadline(Ticker ticker, long offset, boolean baseInstantAlreadyExpired) {
this(ticker, ticker.read(), offset, baseInstantAlreadyExpired); this(ticker, ticker.nanoTime(), offset, baseInstantAlreadyExpired);
} }
private Deadline(Ticker ticker, long baseInstant, long offset, private Deadline(Ticker ticker, long baseInstant, long offset,
@ -77,7 +101,7 @@ public final class Deadline implements Comparable<Deadline> {
*/ */
public boolean isExpired() { public boolean isExpired() {
if (!expired) { if (!expired) {
if (deadlineNanos - ticker.read() <= 0) { if (deadlineNanos - ticker.nanoTime() <= 0) {
expired = true; expired = true;
} else { } else {
return false; return false;
@ -124,7 +148,7 @@ public final class Deadline implements Comparable<Deadline> {
* long ago the deadline expired. * long ago the deadline expired.
*/ */
public long timeRemaining(TimeUnit unit) { public long timeRemaining(TimeUnit unit) {
final long nowNanos = ticker.read(); final long nowNanos = ticker.nanoTime();
if (!expired && deadlineNanos - nowNanos <= 0) { if (!expired && deadlineNanos - nowNanos <= 0) {
expired = true; expired = true;
} }
@ -140,7 +164,7 @@ public final class Deadline implements Comparable<Deadline> {
public ScheduledFuture<?> runOnExpiration(Runnable task, ScheduledExecutorService scheduler) { public ScheduledFuture<?> runOnExpiration(Runnable task, ScheduledExecutorService scheduler) {
checkNotNull(task, "task"); checkNotNull(task, "task");
checkNotNull(scheduler, "scheduler"); checkNotNull(scheduler, "scheduler");
return scheduler.schedule(task, deadlineNanos - ticker.read(), TimeUnit.NANOSECONDS); return scheduler.schedule(task, deadlineNanos - ticker.nanoTime(), TimeUnit.NANOSECONDS);
} }
@Override @Override
@ -173,15 +197,24 @@ public final class Deadline implements Comparable<Deadline> {
return 0; return 0;
} }
/** Time source representing nanoseconds since fixed but arbitrary point in time. */ /**
abstract static class Ticker { * Time source representing nanoseconds since fixed but arbitrary point in time.
*
* <p>This is <strong>EXPERIMENTAL</strong> API and may subject to change. If you'd like it to be
* stabilized or have any feedback, please
* <href a="https://github.com/grpc/grpc-java/issues/6030">let us know</a>.
*
* <p>In general implementations should be thread-safe, unless it's implemented and used in a
* localized environment (like unit tests) where you are sure the usages are synchronized.
*/
public abstract static class Ticker {
/** Returns the number of nanoseconds since this source's epoch. */ /** Returns the number of nanoseconds since this source's epoch. */
public abstract long read(); public abstract long nanoTime();
} }
private static class SystemTicker extends Ticker { private static class SystemTicker extends Ticker {
@Override @Override
public long read() { public long nanoTime() {
return System.nanoTime(); return System.nanoTime();
} }
} }

View File

@ -265,7 +265,7 @@ public class DeadlineTest {
private long time; private long time;
@Override @Override
public long read() { public long nanoTime() {
return time; return time;
} }