content: package org.apache.cassandra.stress.util;
  /*
   * 
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF 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.
   * 
   */
  
  
  import java.util.concurrent.CopyOnWriteArrayList;
  import java.util.concurrent.CountDownLatch;
  
  // TODO: do not assume normal distribution of measurements.
  public class Uncertainty
  {
  
      private int measurements;
      private double sumsquares;
      private double sum;
      private double stdev;
      private double mean;
      private double uncertainty;
  
      private CopyOnWriteArrayList<WaitForTargetUncertainty> waiting = new CopyOnWriteArrayList<>();
  
      private static final class WaitForTargetUncertainty
      {
          final double targetUncertainty;
          final int minMeasurements;
          final int maxMeasurements;
          final CountDownLatch latch = new CountDownLatch(1);
  
          private WaitForTargetUncertainty(double targetUncertainty, int minMeasurements, int maxMeasurements)
          {
              this.targetUncertainty = targetUncertainty;
              this.minMeasurements = minMeasurements;
              this.maxMeasurements = maxMeasurements;
          }
  
          void await() throws InterruptedException
          {
              latch.await();
          }
  
      }
  
      public void update(double value)
      {
          measurements++;
          sumsquares += value * value;
          sum += value;
          mean = sum / measurements;
          stdev = Math.sqrt((sumsquares / measurements) - (mean * mean));
          uncertainty = (stdev / Math.sqrt(measurements)) / mean;
  
          for (WaitForTargetUncertainty waiter : waiting)
          {
              if ((uncertainty < waiter.targetUncertainty && measurements >= waiter.minMeasurements) || (measurements >= waiter.maxMeasurements))
              {
                  waiter.latch.countDown();
                  // can safely remove as working over snapshot with COWArrayList
                  waiting.remove(waiter);
              }
          }
      }
  
      public void await(double targetUncertainty, int minMeasurements, int maxMeasurements) throws InterruptedException
      {
          final WaitForTargetUncertainty wait = new WaitForTargetUncertainty(targetUncertainty, minMeasurements, maxMeasurements);
          waiting.add(wait);
          wait.await();
      }
  
      public double getUncertainty()
      {
          return uncertainty;
      }
  
      public void wakeAll()
      {
          for (WaitForTargetUncertainty waiting : this.waiting)
          {
              waiting.latch.countDown();
              this.waiting.remove(waiting);
          }
      }
  
  }
  