OperationStatsBean.java

/*******************************************************************************
 * Copyright (c) 2021 Eclipse RDF4J contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *******************************************************************************/

package org.eclipse.rdf4j.spring.operationlog.log.jmx;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import org.eclipse.rdf4j.spring.operationlog.log.OperationExecutionStats;
import org.eclipse.rdf4j.spring.operationlog.log.OperationExecutionStatsConsumer;

/**
 * @author Florian Kleedorfer
 * @since 4.0.0
 */
public class OperationStatsBean implements OperationStatsMXBean, OperationExecutionStatsConsumer {

	private Map<String, AggregatedOperationStats> stats = new HashMap<>();

	private final ExecutorService executorService = Executors.newSingleThreadExecutor();

	@Override
	public List<AggregatedOperationStats> getAggregatedOperationStats() {
		return stats.values()
				.stream()
				.sorted(
						(l, r) -> {
							int cmp = r.getCount() - l.getCount();
							if (cmp != 0) {
								return cmp;
							}
							return (int) (r.getCumulativeTime() - l.getCumulativeTime());
						})
				.collect(Collectors.toList());
	}

	@Override
	public int getDistinctOperationCount() {
		return stats.size();
	}

	@Override
	public int getDistinctOperationExecutionCount() {
		return stats.values()
				.stream()
				.mapToInt(AggregatedOperationStats::getUniqueBindingsCount)
				.sum();
	}

	@Override
	public int getTotalOperationExecutionCount() {
		return stats.values().stream().mapToInt(AggregatedOperationStats::getCount).sum();
	}

	@Override
	public long getTotalOperationExecutionTime() {
		return stats.values().stream().mapToLong(AggregatedOperationStats::getCumulativeTime).sum();
	}

	@Override
	public int getTotalFailedOperationExecutionCount() {
		return stats.values().stream().mapToInt(AggregatedOperationStats::getFailed).sum();
	}

	@Override
	public void reset() {
		executorService.execute(
				() -> {
					Map<String, AggregatedOperationStats> old = stats;
					stats = new HashMap<>();
					old.clear();
				});
	}

	@Override
	public void consumeOperationExecutionStats(OperationExecutionStats operationExecutionStats) {
		executorService.execute(
				() -> {
					Map<String, AggregatedOperationStats> newStats = new HashMap<>(stats);
					AggregatedOperationStats aggregated = stats.get(operationExecutionStats.getOperation());
					if (aggregated == null) {
						aggregated = AggregatedOperationStats.build(operationExecutionStats);
					} else {
						aggregated = aggregated.buildNext(operationExecutionStats);
					}
					newStats.put(operationExecutionStats.getOperation(), aggregated);
					stats = newStats;
				});
	}
}