  전체 자바 파일 6444 개 · src/grpc 아래 249 개

# GrpcAdmissionController 의 계수기 선언과 세 메서드
  :17  private final AtomicInteger inFlight = new AtomicInteger();
  :18  private final AtomicInteger queued = new AtomicInteger();
  :19  private final AtomicInteger rejected = new AtomicInteger();
  :51  public Decision tryAdmit() {
  :75  public void promoteFromQueue() {
  :83  public void release() {

  tryAdmit (:51~:72)
    :51   public Decision tryAdmit() {
    :52     int running = inFlight.get();
    :53     if (running < maxConcurrentCalls) {
    :54       inFlight.incrementAndGet();
    :55       return new Decision(true, inFlight.get(), queued.get(), "within the concurrency bound");
    :56     }
    :57     int waiting = queued.get();
    :58     if (waiting < maxQueuedCalls) {
    :59       queued.incrementAndGet();
    :60       return new Decision(true, running, queued.get(), "queued within the admission bound");
    :61     }
    :62     rejected.incrementAndGet();
    :63     return new Decision(
    :64         false,
    :65         running,
    :66         waiting,
    :67         "at capacity: "
    :68             + running
    :69             + " in flight and "
    :70             + waiting
    :71             + " queued. Refusing is better than accepting work whose caller will have given up.");
    :72   }

  promoteFromQueue (:75~:80)
    :75   public void promoteFromQueue() {
    :76     if (queued.get() > 0) {
    :77       queued.decrementAndGet();
    :78       inFlight.incrementAndGet();
    :79     }
    :80   }

  release (:83~:87)
    :83   public void release() {
    :84     if (inFlight.get() > 0) {
    :85       inFlight.decrementAndGet();
    :86     }
    :87   }

# 그 세 메서드 안에서 계수기를 읽는 자리와 쓰는 자리
  tryAdmit          :52 inFlight.get :54 inFlight.incrementAndGet :55 inFlight.get :57 queued.get :59 queued.incrementAndGet :60 queued.get :62 rejected.incrementAndGet
  promoteFromQueue  :76 queued.get :77 queued.decrementAndGet :78 inFlight.incrementAndGet
  release           :84 inFlight.get :85 inFlight.decrementAndGet
  이 파일의 compareAndSet : 0 개

# 저장소 전역에서 두 이름의 계수기를 바꾸는 자리 (Atomic 변경 연산 전부)
  inFlight :
    adapter/inbound/web · main · BlockingBridgeBudget.java:59      int current = inFlight.incrementAndGet();
    adapter/inbound/web · main · BlockingBridgeBudget.java:65      inFlight.decrementAndGet();
    grpc/grpc-server · main · GrpcAdmissionController.java:54        inFlight.incrementAndGet();
    grpc/grpc-server · main · GrpcAdmissionController.java:78        inFlight.incrementAndGet();
    grpc/grpc-server · main · GrpcAdmissionController.java:85        inFlight.decrementAndGet();
    messaging/messaging-transport-spi · main · GracefulShutdownCoordinator.java:54      inFlight.incrementAndGet();
    messaging/messaging-transport-spi · main · GracefulShutdownCoordinator.java:56        inFlight.decrementAndGet();
    messaging/messaging-transport-spi · main · GracefulShutdownCoordinator.java:70      inFlight.updateAndGet(current -> current > 0 ? current - 1 : current);
  queued :
    adapter/inbound/web · main · SemaphoreAdmissionController.java:74      int queueDepth = gate.queued().incrementAndGet();
    adapter/inbound/web · main · SemaphoreAdmissionController.java:90        gate.queued().decrementAndGet();
    grpc/grpc-server · main · GrpcAdmissionController.java:59        queued.incrementAndGet();
    grpc/grpc-server · main · GrpcAdmissionController.java:77        queued.decrementAndGet();

# 같은 저장소가 큐 계수기를 되돌리는 다른 자리
  SemaphoreAdmissionController.java:84           ? AdmissionDecision.admitted(permitFor(gate), waited)
  SemaphoreAdmissionController.java:85           : AdmissionDecision.refused(retryAfterFor(gate), waited);
  SemaphoreAdmissionController.java:86     } catch (InterruptedException interrupted) {
  SemaphoreAdmissionController.java:87       Thread.currentThread().interrupt();
  SemaphoreAdmissionController.java:88       return AdmissionDecision.refused(retryAfterFor(gate), Duration.ZERO);
  SemaphoreAdmissionController.java:89     } finally {
  SemaphoreAdmissionController.java:90       gate.queued().decrementAndGet();
  SemaphoreAdmissionController.java:91     }
  SemaphoreAdmissionController.java:92   }

  GracefulShutdownCoordinator.java:62   /**
  GracefulShutdownCoordinator.java:63    * Records that one unit of work finished.
  GracefulShutdownCoordinator.java:64    *
  GracefulShutdownCoordinator.java:65    * <p>Clamped at zero. A double release used to drive the count negative, and a negative in-flight
  GracefulShutdownCoordinator.java:66    * count reports the drain as complete while work is still running — which is exactly when the
  GracefulShutdownCoordinator.java:67    * process shuts down underneath it.
  GracefulShutdownCoordinator.java:68    */
  GracefulShutdownCoordinator.java:69   public void endWork() {
  GracefulShutdownCoordinator.java:70     inFlight.updateAndGet(current -> current > 0 ? current - 1 : current);
  GracefulShutdownCoordinator.java:71   }

# 같은 형태의 GrpcStreamAdmission 은 해제에서 두 계수기를 모두 줄인다
  GrpcStreamAdmission.java:55   /** Releases a stream's slot. */
  GrpcStreamAdmission.java:56   public void release(String callerFingerprint) {
  GrpcStreamAdmission.java:57     AtomicInteger callerCount = perCaller.get(callerFingerprint);
  GrpcStreamAdmission.java:58     if (callerCount != null && callerCount.get() > 0) {
  GrpcStreamAdmission.java:59       callerCount.decrementAndGet();
  GrpcStreamAdmission.java:60     }
  GrpcStreamAdmission.java:61     if (openStreams.get() > 0) {
  GrpcStreamAdmission.java:62       openStreams.decrementAndGet();
  GrpcStreamAdmission.java:63     }
  GrpcStreamAdmission.java:64   }

# 세 메서드를 부르는 자리
  test · GrpcServerProfileTest.java:107     assertThat(controller.tryAdmit().admitted()).isTrue();
  test · GrpcServerProfileTest.java:108     assertThat(controller.tryAdmit().admitted()).isTrue();
  test · GrpcServerProfileTest.java:109     assertThat(controller.tryAdmit().admitted()).isTrue();
  test · GrpcServerProfileTest.java:110     GrpcAdmissionController.Decision refused = controller.tryAdmit();
  test · GrpcServerProfileTest.java:123     controller.tryAdmit();
  test · GrpcServerProfileTest.java:124     controller.tryAdmit();
  test · GrpcServerProfileTest.java:126     controller.release();
  test · GrpcServerProfileTest.java:127     controller.promoteFromQueue();
  test · GrpcServerProfileTest.java:139     assertThat(controller.tryAdmit().admitted()).isTrue();
  main 소스 세트 : 0 / 9 줄
  타입 이름을 참조하는 main 파일 :
    GrpcDrainCoordinator.java:25
    GrpcDrainCoordinator.java:3
    GrpcDrainCoordinator.java:42
    GrpcPlatformAutoConfiguration.java:11
    GrpcPlatformAutoConfiguration.java:56
    GrpcPlatformAutoConfiguration.java:57
  [대조] GrpcExecutorProfile 을 참조하는 main 파일 수 : 3 (0 이면 검색이 헛돈 것)
  빈을 만드는 자리와 그 조건 :
    GrpcPlatformAutoConfiguration.java:16  import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
    GrpcPlatformAutoConfiguration.java:30  @ConditionalOnProperty(
    GrpcPlatformAutoConfiguration.java:56  public GrpcAdmissionController grpcAdmissionController(GrpcExecutorProfile executorProfile) {
  그 프로퍼티를 켜는 설정 파일 : 0 개

# promoteFromQueue 를 되돌림으로 쓰면 어떻게 되는가 (단일 스레드)
    probe:10  System.out.println("  P1 promoteFromQueue 를 queued 되돌림으로 쓴다 (상한 1, 큐 5)");
    probe:11  GrpcAdmissionController a = new GrpcAdmissionController(1, 5);
    probe:12  a.tryAdmit();
    probe:14  a.tryAdmit();
    probe:18  a.promoteFromQueue();
    probe:20  line("promoteFromQueue 5 회로 queued 를 0 으로", a);
    probe:25  GrpcAdmissionController b = new GrpcAdmissionController(2, 1);
    probe:26  b.tryAdmit();
    probe:27  b.tryAdmit();
    probe:28  GrpcAdmissionController.Decision q = b.tryAdmit();
    probe:31  b.release();
    probe:33  GrpcAdmissionController.Decision d = b.tryAdmit();
    probe:39  GrpcAdmissionController c = new GrpcAdmissionController(2, 3);
    probe:40  c.tryAdmit();
    probe:41  c.tryAdmit();
    probe:43  c.tryAdmit();
    probe:45  c.release();
    probe:46  c.release();
    probe:48  c.tryAdmit();
    probe:49  c.tryAdmit();
  P1 promoteFromQueue 를 queued 되돌림으로 쓴다 (상한 1, 큐 5)
    호출 1 건 + 큐 5 건                                 inFlight=1 queued=5
    promoteFromQueue 5 회로 queued 를 0 으로            inFlight=6 queued=0
    상한은 1 인데 진행 중은 6 다

  P2 큐로 들어온 호출자가 release 로 반납한다 (상한 2, 큐 1)
    세 번째 결정 : admitted=true reason=queued within the admission bound
    실호출 2 + 큐 1                                    inFlight=2 queued=1
    큐에 있던 호출자가 release 를 부른 뒤                      inFlight=1 queued=1
    네 번째 결정 : admitted=true reason=within the concurrency bound
    실제로 돌고 있는 호출 3 건, 상한 2, 계수기 2

  P3 승격 없이 끝난 대기 승인 (상한 2, 큐 3)
    실호출 2 건이 모두 끝난 뒤                               inFlight=0 queued=3
    진행 중이 상한에 닿은 뒤의 결정 : admitted=false
    reason : at capacity: 2 in flight and 3 queued. Refusing is better than accepting work whose caller will have given up.
