/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/
package org.opensearch.tasks;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
* Thread resource usage information for particular resource stats type.
*
* It captures the resource usage information like memory, CPU about a particular execution of thread
* for a specific stats type.
*
* @opensearch.internal
*/
public class ResourceUsageInfo {
private static final Logger logger = LogManager.getLogger(ResourceUsageInfo.class);
private final EnumMap statsInfo = new EnumMap<>(ResourceStats.class);
public ResourceUsageInfo(ResourceUsageMetric... resourceUsageMetrics) {
for (ResourceUsageMetric resourceUsageMetric : resourceUsageMetrics) {
this.statsInfo.put(resourceUsageMetric.getStats(), new ResourceStatsInfo(resourceUsageMetric.getValue()));
}
}
public void recordResourceUsageMetrics(ResourceUsageMetric... resourceUsageMetrics) {
for (ResourceUsageMetric resourceUsageMetric : resourceUsageMetrics) {
final ResourceStatsInfo resourceStatsInfo = statsInfo.get(resourceUsageMetric.getStats());
if (resourceStatsInfo != null) {
updateResourceUsageInfo(resourceStatsInfo, resourceUsageMetric);
} else {
throw new IllegalStateException(
"cannot update ["
+ resourceUsageMetric.getStats().toString()
+ "] entry as its not present current_stats_info:"
+ statsInfo
);
}
}
}
private void updateResourceUsageInfo(ResourceStatsInfo resourceStatsInfo, ResourceUsageMetric resourceUsageMetric) {
long currentEndValue;
long newEndValue;
do {
currentEndValue = resourceStatsInfo.endValue.get();
newEndValue = resourceUsageMetric.getValue();
if (currentEndValue > newEndValue) {
logger.debug(
"dropping resource usage update as the new value is lower than current value ["
+ "resource_stats=[{}], "
+ "current_end_value={}, "
+ "new_end_value={}]",
resourceUsageMetric.getStats(),
currentEndValue,
newEndValue
);
return;
}
} while (!resourceStatsInfo.endValue.compareAndSet(currentEndValue, newEndValue));
logger.debug(
"updated resource usage info [resource_stats=[{}], " + "old_end_value={}, new_end_value={}]",
resourceUsageMetric.getStats(),
currentEndValue,
newEndValue
);
}
public Map getStatsInfo() {
return Collections.unmodifiableMap(statsInfo);
}
@Override
public String toString() {
return statsInfo.toString();
}
/**
* Defines resource stats information.
*/
static class ResourceStatsInfo {
private final long startValue;
private final AtomicLong endValue;
private ResourceStatsInfo(long startValue) {
this.startValue = startValue;
this.endValue = new AtomicLong(startValue);
}
public long getTotalValue() {
return endValue.get() - startValue;
}
@Override
public String toString() {
return String.valueOf(getTotalValue());
}
}
}