private void updateCutoff()

in spectator-api/src/main/java/com/netflix/spectator/api/patterns/CardinalityLimiters.java [255:318]


    private void updateCutoff() {
      long now = clock.wallTime();
      if (now - limiterTimestamp > REFRESH_INTERVAL && values.size() > n) {
        lock.lock();
        try {
          if (now - limiterTimestamp > REFRESH_INTERVAL) {
            limiterTimestamp = clock.wallTime();
            List<Map.Entry<String, AtomicLong>> sorted = values.entrySet()
                .stream()
                .sorted(FREQUENT_ENTRY_COMPARATOR)
                .collect(Collectors.toList());

            final long maxCount = sorted.get(0).getValue().get();

            Map.Entry<String, AtomicLong> min = sorted.get(Math.min(n - 1, sorted.size() - 1));
            final String minKey = min.getKey();
            final long minCount = min.getValue().get();
            final long delta = Math.max(minCount / 2L, 1L);

            final int numCloseToMin = (int) sorted.stream()
                .map(e -> e.getValue().get())
                .filter(v -> Math.abs(v - minCount) <= delta)
                .count();


            // Check for high churn
            long previousCutoff = cutoff;
            if (numCloseToMin > n) {
              if (maxCount - minCount <= maxCount / 2L) {
                // Max is close to min indicating more likelihood for churn with all values
                cutoff = Math.max(previousCutoff, maxCount + delta);
                updatesWithHighChurn = MAX_UPDATES;
              } else {
                // Try to cutoff the noisy tail without impacting higher frequency values
                cutoff = Math.max(previousCutoff, minCount + delta);
                updatesWithHighChurn += updatesWithHighChurn >= MAX_UPDATES ? 0 : 1;
              }
              sorted.stream().skip(10L * n).forEach(e -> values.remove(e.getKey()));

              // Update the limiter and ensure highest frequency values are preserved
              Function<String, String> newLimiter = first(n);
              sorted.stream().limit(n).forEach(e -> newLimiter.apply(e.getKey()));
              limiter = newLimiter;
            } else {
              cutoff = minCount - minCount / 10L;
              values
                  .entrySet()
                  .removeIf(e -> e.getValue().get() <= minCount && e.getKey().compareTo(minKey) > 0);

              // Decay the counts so new items will have a chance to catch up
              values.values().forEach(v -> v.set(v.get() - v.get() / 10L));

              // Replace the fallback limiter instance so new values will be allowed
              updatesWithHighChurn -= updatesWithHighChurn > 0 ? 1 : 0;
              if (updatesWithHighChurn == 0) {
                limiter = first(n);
              }
            }
          }
        } finally {
          lock.unlock();
        }
      }
    }