/*
 * Licensed to Metamarkets Group Inc. (Metamarkets) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. Metamarkets licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package io.druid.server.lookup.namespace.cache;

import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

final class UpdateCounter
{
  private final Phaser phaser = new Phaser(1);

  void update()
  {
    phaser.arrive();
  }

  void awaitTotalUpdates(int totalUpdates) throws InterruptedException
  {
    int currentUpdates = phaser.getPhase();
    while (totalUpdates - currentUpdates > 0) { // overflow-aware
      currentUpdates = phaser.awaitAdvanceInterruptibly(currentUpdates);
    }
  }

  void awaitNextUpdates(int nextUpdates) throws InterruptedException
  {
    awaitTotalUpdates(phaser.getPhase() + nextUpdates);
  }

  boolean awaitFirstUpdate(long timeout, TimeUnit unit) throws InterruptedException
  {
    try {
      phaser.awaitAdvanceInterruptibly(0, timeout, unit);
      return true;
    }
    catch (TimeoutException e) {
      return false;
    }
  }
}

@@ -998,16 +998,170 @@
 unter%0A%7B%0A
+  /**%0A   * Max %7B@link Phaser%7D's phase, specified in it's javadoc. Then it wraps to zero.%0A   */%0A  private static final int MAX_PHASE = Integer.MAX_VALUE;%0A%0A
   privat
@@ -1317,24 +1317,55 @@
 ception%0A  %7B%0A
+    totalUpdates &= MAX_PHASE;%0A
     int curr
@@ -1404,14 +1404,68 @@
     
-while 
+checkNotTerminated(currentUpdates);%0A    while (comparePhases
 (tot
@@ -1477,10 +1477,9 @@
 ates
- -
+,
  cur
@@ -1493,33 +1493,16 @@
 ates
+)
  %3E 0) %7B
- // overflow-aware
 %0A   
@@ -1579,87 +1579,767 @@
     
-%7D%0A  %7D%0A%0A  void awaitNextUpdates(int nextUpdates) throws InterruptedException%0A  %7B
+  checkNotTerminated(currentUpdates);%0A    %7D%0A  %7D%0A%0A  private static int comparePhases(int phase1, int phase2)%0A  %7B%0A    int diff = (phase1 - phase2) & MAX_PHASE;%0A    if (diff == 0) %7B%0A      return 0;%0A    %7D%0A    return diff %3C MAX_PHASE / 2 ? 1 : -1;%0A  %7D%0A%0A  private void checkNotTerminated(int phase)%0A  %7B%0A    if (phase %3C 0) %7B%0A      throw new IllegalStateException(%22Phaser%5B%22 + phaser + %22%5D unexpectedly terminated.%22);%0A    %7D%0A  %7D%0A%0A  void awaitNextUpdates(int nextUpdates) throws InterruptedException%0A  %7B%0A    if (nextUpdates %3C= 0) %7B%0A      throw new IllegalArgumentException(%22nextUpdates is not positive: %22 + nextUpdates);%0A    %7D%0A    if (nextUpdates %3E MAX_PHASE / 4) %7B%0A      throw new UnsupportedOperationException(%22Couldn't wait for so many updates: %22 + nextUpdates);%0A    %7D
 %0A   

Make UpdateCounter proof to update count overflow (#4138)