Skip to content

Instantly share code, notes, and snippets.

@clebertsuconic
Created December 16, 2021 15:42
Show Gist options
  • Save clebertsuconic/87aac5eeba0a45b342de86e2512179af to your computer and use it in GitHub Desktop.
Save clebertsuconic/87aac5eeba0a45b342de86e2512179af to your computer and use it in GitHub Desktop.
/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.apache.activemq.artemis.utils;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.function.IntConsumer;
import org.jboss.logging.Logger;
public class SizeAwareMetric {
private static final Logger logger = Logger.getLogger(SizeAwareMetric.class);
private static final AtomicLongFieldUpdater<SizeAwareMetric> elementsUpdater = AtomicLongFieldUpdater.newUpdater(SizeAwareMetric.class, "elements");
private volatile long elements;
private static final AtomicLongFieldUpdater<SizeAwareMetric> sizeUpdater = AtomicLongFieldUpdater.newUpdater(SizeAwareMetric.class, "elements");
private volatile long size;
private static final AtomicIntegerFieldUpdater<SizeAwareMetric> overFlagUpdater = AtomicIntegerFieldUpdater.newUpdater(SizeAwareMetric.class, "overFlag");
private volatile int overFlag;
public boolean isOver() {
return overFlag != 0;
}
private final long maxSize;
private final long lowerMark;
private IntConsumer[] onSizeSlots;
private Runnable[] overSlots;
private Runnable[] underSlots;
public SizeAwareMetric(long maxSize, long lowerMark, IntConsumer[] onSizeSlots, Runnable[] overSlots, Runnable[] underSlots) {
this.maxSize = maxSize;
this.lowerMark = lowerMark;
this.onSizeSlots = onSizeSlots;
this.overSlots = overSlots;
this.underSlots = underSlots;
}
protected void over() {
if (overSlots != null) {
for (Runnable over: overSlots) {
if (over != null) {
try {
over.run();
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
}
}
}
}
protected void under() {
if (underSlots != null) {
for (Runnable under: underSlots) {
if (under != null) {
try {
under.run();
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
}
}
}
}
private boolean changeOverFlag(int expected, int newValue) {
return overFlagUpdater.compareAndSet(this, expected, newValue);
}
public long addSize(int delta) {
if (delta == 0) {
throw new IllegalStateException("Size must be > 0");
}
if (onSizeSlots != null) {
for (IntConsumer theFunction : onSizeSlots) {
theFunction.accept(delta);
}
}
long currentSize = sizeUpdater.addAndGet(this, delta);
if (delta > 0) {
elementsUpdater.incrementAndGet(this);
if (currentSize >= maxSize && changeOverFlag(0, 1)) {
over();
}
} else if (delta < 0) {
elementsUpdater.decrementAndGet(this);
if (currentSize <= lowerMark && changeOverFlag(1, 0)) {
under();
}
}
return currentSize;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment