1 /* 2 * Copyright 2015 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc; 18 19 import io.grpc.Context.CheckReturnValue; 20 import io.grpc.PersistentHashArrayMappedTrie.Node; 21 import java.io.Closeable; 22 import java.util.ArrayList; 23 import java.util.concurrent.Callable; 24 import java.util.concurrent.Executor; 25 import java.util.concurrent.ScheduledExecutorService; 26 import java.util.concurrent.ScheduledFuture; 27 import java.util.concurrent.TimeUnit; 28 import java.util.concurrent.TimeoutException; 29 import java.util.concurrent.atomic.AtomicReference; 30 import java.util.logging.Level; 31 import java.util.logging.Logger; 32 33 /** 34 * A context propagation mechanism which can carry scoped-values across API boundaries and between 35 * threads. Examples of state propagated via context include: 36 * <ul> 37 * <li>Security principals and credentials.</li> 38 * <li>Local and distributed tracing information.</li> 39 * </ul> 40 * 41 * <p>A Context object can be {@link #attach attached} to the {@link Storage}, which effectively 42 * forms a <b>scope</b> for the context. The scope is bound to the current thread. Within a scope, 43 * its Context is accessible even across API boundaries, through {@link #current}. The scope is 44 * later exited by {@link #detach detaching} the Context. 45 * 46 * <p>Context objects are immutable and inherit state from their parent. To add or overwrite the 47 * current state a new context object must be created and then attached, replacing the previously 48 * bound context. For example: 49 * 50 * <pre> 51 * Context withCredential = Context.current().withValue(CRED_KEY, cred); 52 * withCredential.run(new Runnable() { 53 * public void run() { 54 * readUserRecords(userId, CRED_KEY.get()); 55 * } 56 * }); 57 * </pre> 58 * 59 * <p>Contexts are also used to represent a scoped unit of work. When the unit of work is done the 60 * context must be cancelled. This cancellation will cascade to all descendant contexts. You can 61 * add a {@link CancellationListener} to a context to be notified when it or one of its ancestors 62 * has been cancelled. Cancellation does not release the state stored by a context and it's 63 * perfectly valid to {@link #attach()} an already cancelled context to make it current. To cancel a 64 * context (and its descendants) you first create a {@link CancellableContext} and when you need to 65 * signal cancellation call {@link CancellableContext#cancel} or {@link 66 * CancellableContext#detachAndCancel}. 67 * 68 * <p>Contexts can also be created with a timeout relative to the system nano clock which will 69 * cause it to automatically cancel at the desired time. 70 * 71 * 72 * <p>Notes and cautions on use: 73 * <ul> 74 * <li>Every {@code attach()} should have a {@code detach()} in the same method. And every 75 * CancellableContext should be cancelled at some point. Breaking these rules may lead to memory 76 * leaks. 77 * <li>While Context objects are immutable they do not place such a restriction on the state 78 * they store.</li> 79 * <li>Context is not intended for passing optional parameters to an API and developers should 80 * take care to avoid excessive dependence on context when designing an API.</li> 81 * <li>Do not mock this class. Use {@link #ROOT} for a non-null instance. 82 * </ul> 83 */ 84 /* @DoNotMock("Use ROOT for a non-null Context") // commented out to avoid dependencies */ 85 @CheckReturnValue 86 public class Context { 87 88 static final Logger log = Logger.getLogger(Context.class.getName()); 89 90 // Long chains of contexts are suspicious and usually indicate a misuse of Context. 91 // The threshold is arbitrarily chosen. 92 // VisibleForTesting 93 static final int CONTEXT_DEPTH_WARN_THRESH = 1000; 94 95 /** 96 * The logical root context which is the ultimate ancestor of all contexts. This context 97 * is not cancellable and so will not cascade cancellation or retain listeners. 98 * 99 * <p>Never assume this is the default context for new threads, because {@link Storage} may define 100 * a default context that is different from ROOT. 101 */ 102 public static final Context ROOT = new Context(); 103 104 // Visible For testing storage()105 static Storage storage() { 106 return LazyStorage.storage; 107 } 108 109 // Lazy-loaded storage. Delaying storage initialization until after class initialization makes it 110 // much easier to avoid circular loading since there can still be references to Context as long as 111 // they don't depend on storage, like key() and currentContextExecutor(). It also makes it easier 112 // to handle exceptions. 113 private static final class LazyStorage { 114 static final Storage storage; 115 116 static { 117 AtomicReference<Throwable> deferredStorageFailure = new AtomicReference<>(); 118 storage = createStorage(deferredStorageFailure); 119 Throwable failure = deferredStorageFailure.get(); 120 // Logging must happen after storage has been set, as loggers may use Context. 121 if (failure != null) { log.log(Level.FINE, "Storage override doesn't exist. Using default", failure)122 log.log(Level.FINE, "Storage override doesn't exist. Using default", failure); 123 } 124 } 125 createStorage( AtomicReference<? super ClassNotFoundException> deferredStorageFailure)126 private static Storage createStorage( 127 AtomicReference<? super ClassNotFoundException> deferredStorageFailure) { 128 try { 129 Class<?> clazz = Class.forName("io.grpc.override.ContextStorageOverride"); 130 // The override's constructor is prohibited from triggering any code that can loop back to 131 // Context 132 return clazz.asSubclass(Storage.class).getConstructor().newInstance(); 133 } catch (ClassNotFoundException e) { 134 deferredStorageFailure.set(e); 135 return new ThreadLocalContextStorage(); 136 } catch (Exception e) { 137 throw new RuntimeException("Storage override failed to initialize", e); 138 } 139 } 140 } 141 142 /** 143 * Create a {@link Key} with the given debug name. 144 * 145 * @param debugString a name intended for debugging purposes and does not impact behavior. 146 * Multiple different keys may have the same debugString. 147 * The value should be not null. 148 */ key(String debugString)149 public static <T> Key<T> key(String debugString) { 150 return new Key<>(debugString); 151 } 152 153 /** 154 * Create a {@link Key} with the given debug name and default value. 155 * 156 * @param debugString a name intended for debugging purposes and does not impact behavior. 157 * Multiple different keys may have the same debugString. 158 * The value should be not null. 159 */ keyWithDefault(String debugString, T defaultValue)160 public static <T> Key<T> keyWithDefault(String debugString, T defaultValue) { 161 return new Key<>(debugString, defaultValue); 162 } 163 164 /** 165 * Return the context associated with the current scope, will never return {@code null}. 166 * 167 * <p>Will never return {@link CancellableContext} even if one is attached, instead a 168 * {@link Context} is returned with the same properties and lifetime. This is to avoid 169 * code stealing the ability to cancel arbitrarily. 170 */ current()171 public static Context current() { 172 Context current = storage().current(); 173 if (current == null) { 174 return ROOT; 175 } 176 return current; 177 } 178 179 final CancellableContext cancellableAncestor; 180 final Node<Key<?>, Object> keyValueEntries; 181 // The number parents between this context and the root context. 182 final int generation; 183 184 /** 185 * Construct a context that cannot be cancelled and will not cascade cancellation from its parent. 186 */ Context(Node<Key<?>, Object> keyValueEntries, int generation)187 private Context(Node<Key<?>, Object> keyValueEntries, int generation) { 188 this.cancellableAncestor = null; 189 this.keyValueEntries = keyValueEntries; 190 this.generation = generation; 191 validateGeneration(generation); 192 } 193 194 /** 195 * Construct a context that cannot be cancelled but will cascade cancellation from its parent if 196 * it is cancellable. 197 */ Context(Context parent, Node<Key<?>, Object> keyValueEntries)198 private Context(Context parent, Node<Key<?>, Object> keyValueEntries) { 199 this.cancellableAncestor = cancellableAncestor(parent); 200 this.keyValueEntries = keyValueEntries; 201 this.generation = parent.generation + 1; 202 validateGeneration(generation); 203 } 204 205 /** 206 * Construct for {@link #ROOT}. 207 */ Context()208 private Context() { 209 this.cancellableAncestor = null; 210 this.keyValueEntries = null; 211 this.generation = 0; 212 validateGeneration(generation); 213 } 214 215 /** 216 * Create a new context which is independently cancellable and also cascades cancellation from 217 * its parent. Callers <em>must</em> ensure that either {@link 218 * CancellableContext#cancel(Throwable)} or {@link CancellableContext#detachAndCancel(Context, 219 * Throwable)} are called at a later point, in order to allow this context to be garbage 220 * collected. 221 * 222 * <p>Sample usage: 223 * <pre> 224 * Context.CancellableContext withCancellation = Context.current().withCancellation(); 225 * try { 226 * withCancellation.run(new Runnable() { 227 * public void run() { 228 * Context current = Context.current(); 229 * while (!current.isCancelled()) { 230 * keepWorking(); 231 * } 232 * } 233 * }); 234 * } finally { 235 * withCancellation.cancel(null); 236 * } 237 * </pre> 238 */ withCancellation()239 public CancellableContext withCancellation() { 240 return new CancellableContext(this); 241 } 242 243 /** 244 * Create a new context which will cancel itself after the given {@code duration} from now. 245 * The returned context will cascade cancellation of its parent. Callers may explicitly cancel 246 * the returned context prior to the deadline just as for {@link #withCancellation()}. If the unit 247 * of work completes before the deadline, the context should be explicitly cancelled to allow 248 * it to be garbage collected. 249 * 250 * <p>Sample usage: 251 * <pre> 252 * Context.CancellableContext withDeadline = Context.current() 253 * .withDeadlineAfter(5, TimeUnit.SECONDS, scheduler); 254 * try { 255 * withDeadline.run(new Runnable() { 256 * public void run() { 257 * Context current = Context.current(); 258 * while (!current.isCancelled()) { 259 * keepWorking(); 260 * } 261 * } 262 * }); 263 * } finally { 264 * withDeadline.cancel(null); 265 * } 266 * </pre> 267 */ withDeadlineAfter(long duration, TimeUnit unit, ScheduledExecutorService scheduler)268 public CancellableContext withDeadlineAfter(long duration, TimeUnit unit, 269 ScheduledExecutorService scheduler) { 270 return withDeadline(Deadline.after(duration, unit), scheduler); 271 } 272 273 /** 274 * Create a new context which will cancel itself at the given {@link Deadline}. 275 * The returned context will cascade cancellation of its parent. Callers may explicitly cancel 276 * the returned context prior to the deadline just as for {@link #withCancellation()}. If the unit 277 * of work completes before the deadline, the context should be explicitly cancelled to allow 278 * it to be garbage collected. 279 * 280 * <p>Sample usage: 281 * <pre> 282 * Context.CancellableContext withDeadline = Context.current() 283 * .withDeadline(someReceivedDeadline, scheduler); 284 * try { 285 * withDeadline.run(new Runnable() { 286 * public void run() { 287 * Context current = Context.current(); 288 * while (!current.isCancelled() && moreWorkToDo()) { 289 * keepWorking(); 290 * } 291 * } 292 * }); 293 * } finally { 294 * withDeadline.cancel(null); 295 * } 296 * </pre> 297 */ withDeadline(Deadline newDeadline, ScheduledExecutorService scheduler)298 public CancellableContext withDeadline(Deadline newDeadline, ScheduledExecutorService scheduler) { 299 checkNotNull(newDeadline, "deadline"); 300 checkNotNull(scheduler, "scheduler"); 301 Deadline existingDeadline = getDeadline(); 302 boolean scheduleDeadlineCancellation = true; 303 if (existingDeadline != null && existingDeadline.compareTo(newDeadline) <= 0) { 304 // The new deadline won't have an effect, so ignore it 305 newDeadline = existingDeadline; 306 scheduleDeadlineCancellation = false; 307 } 308 CancellableContext newCtx = new CancellableContext(this, newDeadline); 309 if (scheduleDeadlineCancellation) { 310 newCtx.setUpDeadlineCancellation(newDeadline, scheduler); 311 } 312 return newCtx; 313 } 314 315 /** 316 * Create a new context with the given key value set. The new context will cascade cancellation 317 * from its parent. 318 * 319 <pre> 320 * Context withCredential = Context.current().withValue(CRED_KEY, cred); 321 * withCredential.run(new Runnable() { 322 * public void run() { 323 * readUserRecords(userId, CRED_KEY.get()); 324 * } 325 * }); 326 * </pre> 327 * 328 * <p>Note that multiple calls to {@link #withValue} can be chained together. 329 * That is, 330 * 331 * <pre> 332 * context.withValues(K1, V1, K2, V2); 333 * // is the same as 334 * context.withValue(K1, V1).withValue(K2, V2); 335 * </pre> 336 * 337 * <p>Nonetheless, {@link Context} should not be treated like a general purpose 338 * map with a large number of keys and values — combine multiple related items 339 * together into a single key instead of separating them. But if the items 340 * are unrelated, have separate keys for them. 341 */ withValue(Key<V> k1, V v1)342 public <V> Context withValue(Key<V> k1, V v1) { 343 Node<Key<?>, Object> newKeyValueEntries = 344 PersistentHashArrayMappedTrie.put(keyValueEntries, k1, v1); 345 return new Context(this, newKeyValueEntries); 346 } 347 348 /** 349 * Create a new context with the given key value set. The new context will cascade cancellation 350 * from its parent. 351 */ withValues(Key<V1> k1, V1 v1, Key<V2> k2, V2 v2)352 public <V1, V2> Context withValues(Key<V1> k1, V1 v1, Key<V2> k2, V2 v2) { 353 Node<Key<?>, Object> newKeyValueEntries = 354 PersistentHashArrayMappedTrie.put(keyValueEntries, k1, v1); 355 newKeyValueEntries = PersistentHashArrayMappedTrie.put(newKeyValueEntries, k2, v2); 356 return new Context(this, newKeyValueEntries); 357 } 358 359 /** 360 * Create a new context with the given key value set. The new context will cascade cancellation 361 * from its parent. 362 */ withValues(Key<V1> k1, V1 v1, Key<V2> k2, V2 v2, Key<V3> k3, V3 v3)363 public <V1, V2, V3> Context withValues(Key<V1> k1, V1 v1, Key<V2> k2, V2 v2, Key<V3> k3, V3 v3) { 364 Node<Key<?>, Object> newKeyValueEntries = 365 PersistentHashArrayMappedTrie.put(keyValueEntries, k1, v1); 366 newKeyValueEntries = PersistentHashArrayMappedTrie.put(newKeyValueEntries, k2, v2); 367 newKeyValueEntries = PersistentHashArrayMappedTrie.put(newKeyValueEntries, k3, v3); 368 return new Context(this, newKeyValueEntries); 369 } 370 371 /** 372 * Create a new context with the given key value set. The new context will cascade cancellation 373 * from its parent. 374 * 375 * <p>For more than 4 key-value pairs, note that multiple calls to 376 * {@link #withValue} can be chained together. That is, 377 * 378 * <pre> 379 * context.withValues(K1, V1, K2, V2); 380 * // is the same as 381 * context.withValue(K1, V1).withValue(K2, V2); 382 * </pre> 383 * 384 * <p>Nonetheless, {@link Context} should not be treated like a general purpose 385 * map with a large number of keys and values — combine multiple related items 386 * together into a single key instead of separating them. But if the items 387 * are unrelated, have separate keys for them. 388 */ withValues(Key<V1> k1, V1 v1, Key<V2> k2, V2 v2, Key<V3> k3, V3 v3, Key<V4> k4, V4 v4)389 public <V1, V2, V3, V4> Context withValues(Key<V1> k1, V1 v1, Key<V2> k2, V2 v2, 390 Key<V3> k3, V3 v3, Key<V4> k4, V4 v4) { 391 Node<Key<?>, Object> newKeyValueEntries = 392 PersistentHashArrayMappedTrie.put(keyValueEntries, k1, v1); 393 newKeyValueEntries = PersistentHashArrayMappedTrie.put(newKeyValueEntries, k2, v2); 394 newKeyValueEntries = PersistentHashArrayMappedTrie.put(newKeyValueEntries, k3, v3); 395 newKeyValueEntries = PersistentHashArrayMappedTrie.put(newKeyValueEntries, k4, v4); 396 return new Context(this, newKeyValueEntries); 397 } 398 399 /** 400 * Create a new context which propagates the values of this context but does not cascade its 401 * cancellation. 402 */ fork()403 public Context fork() { 404 return new Context(keyValueEntries, generation + 1); 405 } 406 407 /** 408 * Attach this context, thus enter a new scope within which this context is {@link #current}. The 409 * previously current context is returned. It is allowed to attach contexts where {@link 410 * #isCancelled()} is {@code true}. 411 * 412 * <p>Instead of using {@code attach()} and {@link #detach(Context)} most use-cases are better 413 * served by using the {@link #run(Runnable)} or {@link #call(java.util.concurrent.Callable)} to 414 * execute work immediately within a context's scope. If work needs to be done in other threads it 415 * is recommended to use the 'wrap' methods or to use a propagating executor. 416 * 417 * <p>All calls to {@code attach()} should have a corresponding {@link #detach(Context)} within 418 * the same method: 419 * <pre>{@code Context previous = someContext.attach(); 420 * try { 421 * // Do work 422 * } finally { 423 * someContext.detach(previous); 424 * }}</pre> 425 */ attach()426 public Context attach() { 427 Context prev = storage().doAttach(this); 428 if (prev == null) { 429 return ROOT; 430 } 431 return prev; 432 } 433 434 /** 435 * Reverse an {@code attach()}, restoring the previous context and exiting the current scope. 436 * 437 * <p>This context should be the same context that was previously {@link #attach attached}. The 438 * provided replacement should be what was returned by the same {@link #attach attach()} call. If 439 * an {@code attach()} and a {@code detach()} meet above requirements, they match. 440 * 441 * <p>It is expected that between any pair of matching {@code attach()} and {@code detach()}, all 442 * {@code attach()}es and {@code detach()}es are called in matching pairs. If this method finds 443 * that this context is not {@link #current current}, either you or some code in-between are not 444 * detaching correctly, and a SEVERE message will be logged but the context to attach will still 445 * be bound. <strong>Never</strong> use {@code Context.current().detach()}, as this will 446 * compromise this error-detecting mechanism. 447 */ detach(Context toAttach)448 public void detach(Context toAttach) { 449 checkNotNull(toAttach, "toAttach"); 450 storage().detach(this, toAttach); 451 } 452 453 // Visible for testing isCurrent()454 boolean isCurrent() { 455 return current() == this; 456 } 457 458 /** 459 * Is this context cancelled. 460 */ isCancelled()461 public boolean isCancelled() { 462 if (cancellableAncestor == null) { 463 return false; 464 } else { 465 return cancellableAncestor.isCancelled(); 466 } 467 } 468 469 /** 470 * If a context {@link #isCancelled()} then return the cause of the cancellation or 471 * {@code null} if context was cancelled without a cause. If the context is not yet cancelled 472 * will always return {@code null}. 473 * 474 * <p>The cancellation cause is provided for informational purposes only and implementations 475 * should generally assume that it has already been handled and logged properly. 476 */ cancellationCause()477 public Throwable cancellationCause() { 478 if (cancellableAncestor == null) { 479 return null; 480 } else { 481 return cancellableAncestor.cancellationCause(); 482 } 483 } 484 485 /** 486 * A context may have an associated {@link Deadline} at which it will be automatically cancelled. 487 * @return A {@link io.grpc.Deadline} or {@code null} if no deadline is set. 488 */ getDeadline()489 public Deadline getDeadline() { 490 if (cancellableAncestor == null) { 491 return null; 492 } 493 return cancellableAncestor.getDeadline(); 494 } 495 496 /** 497 * Add a listener that will be notified when the context becomes cancelled. 498 */ addListener(final CancellationListener cancellationListener, final Executor executor)499 public void addListener(final CancellationListener cancellationListener, 500 final Executor executor) { 501 checkNotNull(cancellationListener, "cancellationListener"); 502 checkNotNull(executor, "executor"); 503 if (cancellableAncestor == null) { 504 return; 505 } 506 cancellableAncestor.addListenerInternal( 507 new ExecutableListener(executor, cancellationListener, this)); 508 } 509 510 /** 511 * Remove a {@link CancellationListener}. 512 */ removeListener(CancellationListener cancellationListener)513 public void removeListener(CancellationListener cancellationListener) { 514 if (cancellableAncestor == null) { 515 return; 516 } 517 cancellableAncestor.removeListenerInternal(cancellationListener, this); 518 } 519 520 // Used in tests to ensure that listeners are defined and released when cancellation cascades. 521 // It's very important to ensure that we do not accidentally retain listeners. listenerCount()522 int listenerCount() { 523 if (cancellableAncestor == null) { 524 return 0; 525 } 526 return cancellableAncestor.listenerCount(); 527 } 528 529 /** 530 * Immediately run a {@link Runnable} with this context as the {@link #current} context. 531 * @param r {@link Runnable} to run. 532 */ run(Runnable r)533 public void run(Runnable r) { 534 Context previous = attach(); 535 try { 536 r.run(); 537 } finally { 538 detach(previous); 539 } 540 } 541 542 /** 543 * Immediately call a {@link Callable} with this context as the {@link #current} context. 544 * @param c {@link Callable} to call. 545 * @return result of call. 546 */ 547 @CanIgnoreReturnValue call(Callable<V> c)548 public <V> V call(Callable<V> c) throws Exception { 549 Context previous = attach(); 550 try { 551 return c.call(); 552 } finally { 553 detach(previous); 554 } 555 } 556 557 /** 558 * Wrap a {@link Runnable} so that it executes with this context as the {@link #current} context. 559 */ wrap(final Runnable r)560 public Runnable wrap(final Runnable r) { 561 return new Runnable() { 562 @Override 563 public void run() { 564 Context previous = attach(); 565 try { 566 r.run(); 567 } finally { 568 detach(previous); 569 } 570 } 571 }; 572 } 573 574 /** 575 * Wrap a {@link Callable} so that it executes with this context as the {@link #current} context. 576 */ 577 public <C> Callable<C> wrap(final Callable<C> c) { 578 return new Callable<C>() { 579 @Override 580 public C call() throws Exception { 581 Context previous = attach(); 582 try { 583 return c.call(); 584 } finally { 585 detach(previous); 586 } 587 } 588 }; 589 } 590 591 /** 592 * Wrap an {@link Executor} so that it always executes with this context as the {@link #current} 593 * context. It is generally expected that {@link #currentContextExecutor(Executor)} would be 594 * used more commonly than this method. 595 * 596 * <p>One scenario in which this executor may be useful is when a single thread is sharding work 597 * to multiple threads. 598 * 599 * @see #currentContextExecutor(Executor) 600 */ 601 public Executor fixedContextExecutor(final Executor e) { 602 final class FixedContextExecutor implements Executor { 603 @Override 604 public void execute(Runnable r) { 605 e.execute(wrap(r)); 606 } 607 } 608 609 return new FixedContextExecutor(); 610 } 611 612 /** 613 * Create an executor that propagates the {@link #current} context when {@link Executor#execute} 614 * is called as the {@link #current} context of the {@code Runnable} scheduled. <em>Note that this 615 * is a static method.</em> 616 * 617 * @see #fixedContextExecutor(Executor) 618 */ 619 public static Executor currentContextExecutor(final Executor e) { 620 final class CurrentContextExecutor implements Executor { 621 @Override 622 public void execute(Runnable r) { 623 e.execute(Context.current().wrap(r)); 624 } 625 } 626 627 return new CurrentContextExecutor(); 628 } 629 630 /** 631 * A context which inherits cancellation from its parent but which can also be independently 632 * cancelled and which will propagate cancellation to its descendants. To avoid leaking memory, 633 * every CancellableContext must have a defined lifetime, after which it is guaranteed to be 634 * cancelled. 635 * 636 * <p>This class must be cancelled by either calling {@link #close} or {@link #cancel}. 637 * {@link #close} is equivalent to calling {@code cancel(null)}. It is safe to call the methods 638 * more than once, but only the first call will have any effect. Because it's safe to call the 639 * methods multiple times, users are encouraged to always call {@link #close} at the end of 640 * the operation, and disregard whether {@link #cancel} was already called somewhere else. 641 * 642 * <p>Blocking code can use the try-with-resources idiom: 643 * <pre> 644 * try (CancellableContext c = Context.current() 645 * .withDeadlineAfter(100, TimeUnit.MILLISECONDS, executor)) { 646 * Context toRestore = c.attach(); 647 * try { 648 * // do some blocking work 649 * } finally { 650 * c.detach(toRestore); 651 * } 652 * }</pre> 653 * 654 * <p>Asynchronous code will have to manually track the end of the CancellableContext's lifetime, 655 * and cancel the context at the appropriate time. 656 */ 657 public static final class CancellableContext extends Context implements Closeable { 658 659 private final Deadline deadline; 660 private final Context uncancellableSurrogate; 661 662 private ArrayList<ExecutableListener> listeners; 663 // parentListener is initialized when listeners is initialized (only if there is a 664 // cancellable ancestor), and uninitialized when listeners is uninitialized. 665 private CancellationListener parentListener; 666 private Throwable cancellationCause; 667 private ScheduledFuture<?> pendingDeadline; 668 private boolean cancelled; 669 670 /** 671 * Create a cancellable context that does not have a deadline. 672 */ 673 private CancellableContext(Context parent) { 674 super(parent, parent.keyValueEntries); 675 deadline = parent.getDeadline(); 676 // Create a surrogate that inherits from this to attach so that you cannot retrieve a 677 // cancellable context from Context.current() 678 uncancellableSurrogate = new Context(this, keyValueEntries); 679 } 680 681 /** 682 * Create a cancellable context that has a deadline. 683 */ 684 private CancellableContext(Context parent, Deadline deadline) { 685 super(parent, parent.keyValueEntries); 686 this.deadline = deadline; 687 this.uncancellableSurrogate = new Context(this, keyValueEntries); 688 } 689 690 private void setUpDeadlineCancellation(Deadline deadline, ScheduledExecutorService scheduler) { 691 if (!deadline.isExpired()) { 692 final class CancelOnExpiration implements Runnable { 693 @Override 694 public void run() { 695 try { 696 cancel(new TimeoutException("context timed out")); 697 } catch (Throwable t) { 698 log.log(Level.SEVERE, "Cancel threw an exception, which should not happen", t); 699 } 700 } 701 } 702 703 synchronized (this) { 704 pendingDeadline = deadline.runOnExpiration(new CancelOnExpiration(), scheduler); 705 } 706 } else { 707 // Cancel immediately if the deadline is already expired. 708 cancel(new TimeoutException("context timed out")); 709 } 710 } 711 712 @Override 713 public Context attach() { 714 return uncancellableSurrogate.attach(); 715 } 716 717 @Override 718 public void detach(Context toAttach) { 719 uncancellableSurrogate.detach(toAttach); 720 } 721 722 @Override 723 public void addListener( 724 final CancellationListener cancellationListener, final Executor executor) { 725 checkNotNull(cancellationListener, "cancellationListener"); 726 checkNotNull(executor, "executor"); 727 addListenerInternal(new ExecutableListener(executor, cancellationListener, this)); 728 } 729 730 private void addListenerInternal(ExecutableListener executableListener) { 731 synchronized (this) { 732 if (isCancelled()) { 733 executableListener.deliver(); 734 } else { 735 if (listeners == null) { 736 // Now that we have a listener we need to listen to our parent so 737 // we can cascade listener notification. 738 listeners = new ArrayList<>(); 739 listeners.add(executableListener); 740 if (cancellableAncestor != null) { 741 parentListener = 742 new CancellationListener() { 743 @Override 744 public void cancelled(Context context) { 745 CancellableContext.this.cancel(context.cancellationCause()); 746 } 747 }; 748 cancellableAncestor.addListenerInternal( 749 new ExecutableListener(DirectExecutor.INSTANCE, parentListener, this)); 750 } 751 } else { 752 listeners.add(executableListener); 753 } 754 } 755 } 756 } 757 758 @Override 759 public void removeListener(CancellationListener cancellationListener) { 760 removeListenerInternal(cancellationListener, this); 761 } 762 763 private void removeListenerInternal(CancellationListener cancellationListener, 764 Context context) { 765 synchronized (this) { 766 if (listeners != null) { 767 for (int i = listeners.size() - 1; i >= 0; i--) { 768 ExecutableListener executableListener = listeners.get(i); 769 if (executableListener.listener == cancellationListener 770 && executableListener.context == context) { 771 listeners.remove(i); 772 // Just remove the first matching listener, given that we allow duplicate 773 // adds we should allow for duplicates after remove. 774 break; 775 } 776 } 777 // We have no listeners so no need to listen to our parent 778 if (listeners.isEmpty()) { 779 if (cancellableAncestor != null) { 780 cancellableAncestor.removeListener(parentListener); 781 } 782 parentListener = null; 783 listeners = null; 784 } 785 } 786 } 787 } 788 789 /** 790 * Returns true if the Context is the current context. 791 * 792 * @deprecated This method violates some GRPC class encapsulation and should not be used. 793 * If you must know whether a Context is the current context, check whether it is the same 794 * object returned by {@link Context#current()}. 795 */ 796 //TODO(spencerfang): The superclass's method is package-private, so this should really match. 797 @Override 798 @Deprecated 799 public boolean isCurrent() { 800 return uncancellableSurrogate.isCurrent(); 801 } 802 803 /** 804 * Cancel this context and optionally provide a cause (can be {@code null}) for the 805 * cancellation. This will trigger notification of listeners. It is safe to call this method 806 * multiple times. Only the first call will have any effect. 807 * 808 * <p>Calling {@code cancel(null)} is the same as calling {@link #close}. 809 * 810 * @return {@code true} if this context cancelled the context and notified listeners, 811 * {@code false} if the context was already cancelled. 812 */ 813 @CanIgnoreReturnValue 814 public boolean cancel(Throwable cause) { 815 boolean triggeredCancel = false; 816 ScheduledFuture<?> localPendingDeadline = null; 817 synchronized (this) { 818 if (!cancelled) { 819 cancelled = true; 820 if (pendingDeadline != null) { 821 // If we have a scheduled cancellation pending attempt to cancel it. 822 localPendingDeadline = pendingDeadline; 823 pendingDeadline = null; 824 } 825 this.cancellationCause = cause; 826 triggeredCancel = true; 827 } 828 } 829 if (localPendingDeadline != null) { 830 localPendingDeadline.cancel(false); 831 } 832 if (triggeredCancel) { 833 notifyAndClearListeners(); 834 } 835 return triggeredCancel; 836 } 837 838 /** 839 * Notify all listeners that this context has been cancelled and immediately release 840 * any reference to them so that they may be garbage collected. 841 */ 842 private void notifyAndClearListeners() { 843 ArrayList<ExecutableListener> tmpListeners; 844 CancellationListener tmpParentListener; 845 synchronized (this) { 846 if (listeners == null) { 847 return; 848 } 849 tmpParentListener = parentListener; 850 parentListener = null; 851 tmpListeners = listeners; 852 listeners = null; 853 } 854 // Deliver events to this context listeners before we notify child contexts. We do this 855 // to cancel higher level units of work before child units. This allows for a better error 856 // handling paradigm where the higher level unit of work knows it is cancelled and so can 857 // ignore errors that bubble up as a result of cancellation of lower level units. 858 for (ExecutableListener tmpListener : tmpListeners) { 859 if (tmpListener.context == this) { 860 tmpListener.deliver(); 861 } 862 } 863 for (ExecutableListener tmpListener : tmpListeners) { 864 if (!(tmpListener.context == this)) { 865 tmpListener.deliver(); 866 } 867 } 868 if (cancellableAncestor != null) { 869 cancellableAncestor.removeListener(tmpParentListener); 870 } 871 } 872 873 @Override 874 int listenerCount() { 875 synchronized (this) { 876 return listeners == null ? 0 : listeners.size(); 877 } 878 } 879 880 /** 881 * Cancel this context and detach it as the current context. 882 * 883 * @param toAttach context to make current. 884 * @param cause of cancellation, can be {@code null}. 885 */ 886 public void detachAndCancel(Context toAttach, Throwable cause) { 887 try { 888 detach(toAttach); 889 } finally { 890 cancel(cause); 891 } 892 } 893 894 @Override 895 public boolean isCancelled() { 896 synchronized (this) { 897 if (cancelled) { 898 return true; 899 } 900 } 901 // Detect cancellation of parent in the case where we have no listeners and 902 // record it. 903 if (super.isCancelled()) { 904 cancel(super.cancellationCause()); 905 return true; 906 } 907 return false; 908 } 909 910 @Override 911 public Throwable cancellationCause() { 912 if (isCancelled()) { 913 return cancellationCause; 914 } 915 return null; 916 } 917 918 @Override 919 public Deadline getDeadline() { 920 return deadline; 921 } 922 923 /** 924 * Cleans up this object by calling {@code cancel(null)}. 925 */ 926 @Override 927 public void close() { 928 cancel(null); 929 } 930 } 931 932 /** 933 * A listener notified on context cancellation. 934 */ 935 public interface CancellationListener { 936 /** 937 * Notifies that a context was cancelled. 938 * 939 * @param context the newly cancelled context. 940 */ 941 void cancelled(Context context); 942 } 943 944 /** 945 * Key for indexing values stored in a context. Keys use reference equality and Context does not 946 * provide a mechanism to loop over Keys. This means there is no way to access a Key's value from 947 * a Context without having access to the Key instance itself. This allows strong control over 948 * what code can get/set a key in the Context. For example, you might manage access to Key similar 949 * to a ThreadLocal using Java visibility (private/protected). Generally Keys are stored in static 950 * fields. 951 */ 952 public static final class Key<T> { 953 private final String name; 954 private final T defaultValue; 955 956 Key(String name) { 957 this(name, null); 958 } 959 960 Key(String name, T defaultValue) { 961 this.name = checkNotNull(name, "name"); 962 this.defaultValue = defaultValue; 963 } 964 965 /** 966 * Get the value from the {@link #current()} context for this key. 967 */ 968 public T get() { 969 return get(Context.current()); 970 } 971 972 /** 973 * Get the value from the specified context for this key. 974 */ 975 @SuppressWarnings("unchecked") 976 public T get(Context context) { 977 T value = (T) PersistentHashArrayMappedTrie.get(context.keyValueEntries, this); 978 return value == null ? defaultValue : value; 979 } 980 981 @Override 982 public String toString() { 983 return name; 984 } 985 } 986 987 /** 988 * Defines the mechanisms for attaching and detaching the "current" context. The constructor for 989 * extending classes <em>must not</em> trigger any activity that can use Context, which includes 990 * logging, otherwise it can trigger an infinite initialization loop. Extending classes must not 991 * assume that only one instance will be created; Context guarantees it will only use one 992 * instance, but it may create multiple and then throw away all but one. 993 * 994 * <p>The default implementation will put the current context in a {@link ThreadLocal}. If an 995 * alternative implementation named {@code io.grpc.override.ContextStorageOverride} exists in the 996 * classpath, it will be used instead of the default implementation. 997 * 998 * <p>This API is <a href="https://github.com/grpc/grpc-java/issues/2462">experimental</a> and 999 * subject to change. 1000 */ 1001 public abstract static class Storage { 1002 /** 1003 * Unused. 1004 * 1005 * @deprecated This is an old API that is no longer used. 1006 */ 1007 @Deprecated 1008 public void attach(Context toAttach) { 1009 throw new UnsupportedOperationException("Deprecated. Do not call."); 1010 } 1011 1012 /** 1013 * Implements {@link io.grpc.Context#attach}. 1014 * 1015 * <p>Caution: {@link Context#attach()} interprets a return value of {@code null} to mean 1016 * the same thing as {@link Context#ROOT}. 1017 * 1018 * <p>See also: {@link #current()}. 1019 1020 * @param toAttach the context to be attached 1021 * @return A {@link Context} that should be passed back into {@link #detach(Context, Context)} 1022 * as the {@code toRestore} parameter. {@code null} is a valid return value, but see 1023 * caution note. 1024 */ 1025 public Context doAttach(Context toAttach) { 1026 // This is a default implementation to help migrate existing Storage implementations that 1027 // have an attach() method but no doAttach() method. 1028 Context current = current(); 1029 attach(toAttach); 1030 return current; 1031 } 1032 1033 /** 1034 * Implements {@link io.grpc.Context#detach}. 1035 * 1036 * @param toDetach the context to be detached. Should be, or be equivalent to, the current 1037 * context of the current scope 1038 * @param toRestore the context to be the current. Should be, or be equivalent to, the context 1039 * of the outer scope 1040 */ 1041 public abstract void detach(Context toDetach, Context toRestore); 1042 1043 /** 1044 * Implements {@link io.grpc.Context#current}. 1045 * 1046 * <p>Caution: {@link Context} interprets a return value of {@code null} to mean the same 1047 * thing as {@link Context#ROOT}. 1048 * 1049 * <p>See also {@link #doAttach(Context)}. 1050 * 1051 * @return The context of the current scope. {@code null} is a valid return value, but see 1052 * caution note. 1053 */ 1054 public abstract Context current(); 1055 } 1056 1057 /** 1058 * Stores listener and executor pair. 1059 */ 1060 private static final class ExecutableListener implements Runnable { 1061 private final Executor executor; 1062 final CancellationListener listener; 1063 private final Context context; 1064 1065 ExecutableListener(Executor executor, CancellationListener listener, Context context) { 1066 this.executor = executor; 1067 this.listener = listener; 1068 this.context = context; 1069 } 1070 1071 void deliver() { 1072 try { 1073 executor.execute(this); 1074 } catch (Throwable t) { 1075 log.log(Level.INFO, "Exception notifying context listener", t); 1076 } 1077 } 1078 1079 @Override 1080 public void run() { 1081 listener.cancelled(context); 1082 } 1083 } 1084 1085 @CanIgnoreReturnValue 1086 static <T> T checkNotNull(T reference, Object errorMessage) { 1087 if (reference == null) { 1088 throw new NullPointerException(String.valueOf(errorMessage)); 1089 } 1090 return reference; 1091 } 1092 1093 private enum DirectExecutor implements Executor { 1094 INSTANCE; 1095 1096 @Override 1097 public void execute(Runnable command) { 1098 command.run(); 1099 } 1100 1101 @Override 1102 public String toString() { 1103 return "Context.DirectExecutor"; 1104 } 1105 } 1106 1107 /** 1108 * Returns {@code parent} if it is a {@link CancellableContext}, otherwise returns the parent's 1109 * {@link #cancellableAncestor}. 1110 */ 1111 static CancellableContext cancellableAncestor(Context parent) { 1112 if (parent instanceof CancellableContext) { 1113 return (CancellableContext) parent; 1114 } 1115 // The parent simply cascades cancellations. 1116 // Bypass the parent and reference the ancestor directly (may be null). 1117 return parent.cancellableAncestor; 1118 } 1119 1120 /** 1121 * If the ancestry chain length is unreasonably long, then print an error to the log and record 1122 * the stack trace. 1123 */ 1124 private static void validateGeneration(int generation) { 1125 if (generation == CONTEXT_DEPTH_WARN_THRESH) { 1126 log.log( 1127 Level.SEVERE, 1128 "Context ancestry chain length is abnormally long. " 1129 + "This suggests an error in application code. " 1130 + "Length exceeded: " + CONTEXT_DEPTH_WARN_THRESH, 1131 new Exception()); 1132 } 1133 } 1134 1135 // Not using the standard com.google.errorprone.annotations.CheckReturnValue because that will 1136 // introduce dependencies that some io.grpc.Context API consumers may not want. 1137 @interface CheckReturnValue {} 1138 1139 @interface CanIgnoreReturnValue {} 1140 } 1141