All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.axoniq.console.framework.application.SlidingTimeWindowReservoir Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2024. AxonIQ B.V.
 *
 * Licensed 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.axoniq.console.framework.application;

import io.micrometer.core.instrument.Clock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * NOTE: This class has been taken from the Axon Framework.
 * 

* A reservoir of measurements constrained by a sliding window that stores only the measurements made * in the last {@code N} seconds (or other time unit). *

* Adapted from com.codahale.metrics.SlidingTimeWindowReservoir from io.dropwizard.metrics:metrics-core:3.1.2 * * @author Volker Fritzsch * @author Coda Hale * @author ceetav * @author Marijn van Zelst * @since 4.1 */ public class SlidingTimeWindowReservoir { // allow for this many duplicate ticks before overwriting measurements private static final int COLLISION_BUFFER = 256; // only trim on updating once every N private static final int TRIM_THRESHOLD = 256; private final Clock clock; private final ConcurrentSkipListMap measurements; private final long window; private final AtomicLong lastTick; private final AtomicLong count; /** * Creates a new {@link SlidingTimeWindowReservoir} with the given clock and window of time. * * @param window the window of time * @param windowUnit the unit of {@code window} * @param clock the {@link Clock} to use */ public SlidingTimeWindowReservoir(long window, TimeUnit windowUnit, Clock clock) { this.clock = clock; this.measurements = new ConcurrentSkipListMap<>(); this.window = windowUnit.toNanos(window) * COLLISION_BUFFER; this.lastTick = new AtomicLong(clock.monotonicTime() * COLLISION_BUFFER); this.count = new AtomicLong(); } /** * Add new measurement value * * @param value the measurement value */ public void update(long value) { if (count.incrementAndGet() % TRIM_THRESHOLD == 0) { trim(); } measurements.put(getTick(), value); } /** * Retrieve the measurements * * @return the measurements */ public List getMeasurements() { trim(); return new ArrayList<>(measurements.values()); } private long getTick() { for (; ; ) { final long oldTick = lastTick.get(); final long tick = clock.monotonicTime() * COLLISION_BUFFER; // ensure the tick is strictly incrementing even if there are duplicate ticks final long newTick = tick - oldTick > 0 ? tick : oldTick + 1; if (lastTick.compareAndSet(oldTick, newTick)) { return newTick; } } } private void trim() { measurements.headMap(getTick() - window).clear(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy