blob: 3fdbfdaacc303f44ae96c190682f39588ed44114 [file] [log] [blame]
/*
* 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
*
* 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 org.apache.geode.internal.statistics;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.IntSupplier;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.apache.geode.StatisticDescriptor;
import org.apache.geode.Statistics;
import org.apache.geode.StatisticsType;
import org.apache.geode.StatisticsTypeFactory;
import org.apache.geode.internal.process.ProcessUtils;
/**
* A {@link StatisticsManager} that delegates creation to specified factories and notifies listeners
* when statistics are created or destroyed.
*/
public class StatisticsRegistry implements StatisticsManager {
private final StatisticsTypeFactory typeFactory;
private final AtomicStatisticsFactory atomicStatisticsFactory;
private final OsStatisticsFactory osStatisticsFactory;
private final IntSupplier pidSupplier;
private final String name;
private final long startTime;
private final List<Statistics> instances = new CopyOnWriteArrayList<>();
private final AtomicLong nextUniqueId = new AtomicLong(1);
private int modificationCount;
/**
* Creates an instance of OS Statistics for this registry.
*/
public interface OsStatisticsFactory {
Statistics create(StatisticsType type, String textId, long numericId, long uniqueId,
int osStatFlags, StatisticsManager manager);
}
/**
* Creates an instance of Atomic Statistics for this registry.
*/
public interface AtomicStatisticsFactory {
Statistics create(StatisticsType type, String textId, long numericId, long uniqueId,
StatisticsManager manager);
}
/**
* Creates a {@code StatisticsRegistry} that uses the default factories to create {@link
* StatisticsType}s and {@link Statistics} instances.
*
* The default factories are:
* <ol>
* <li>For {@code StatisticsType}s: the {@link StatisticsTypeFactoryImpl} singleton.</li>
* <li>For atomic {@code Statistics}s: {@link StatisticsImpl#createAtomicNoOS}.</li>
* <li>For non-atomic {@code Statistics}s: the {@link LocalStatisticsImpl} constructor.</li>
* </ol>
*
* @param name the name of the registry
* @param startTime the time at which the registry was started
*/
public StatisticsRegistry(String name, long startTime) {
this(name, startTime, StatisticsTypeFactoryImpl.singleton(),
LocalStatisticsImpl::createNonAtomic, StatisticsImpl::createAtomicNoOS,
ProcessUtils::identifyPidAsUnchecked);
}
/**
* Creates a {@code StatisticsRegistry} that uses the given factories to create {@code
* StatisticsType}s and {@code Statistics} instances.
*
* @param name the name of the registry
* @param startTime the time at which the registry was started
* @param typeFactory the factory to create {@code StatisticsType}s
* @param osStatisticsFactory the factory to create OS statistics
* @param atomicStatisticsFactory the factory to create atomic statistics
* @param pidSupplier the IntSupplier to return this pid
*/
StatisticsRegistry(String name, long startTime, StatisticsTypeFactory typeFactory,
OsStatisticsFactory osStatisticsFactory, AtomicStatisticsFactory atomicStatisticsFactory,
IntSupplier pidSupplier) {
this.name = name;
this.startTime = startTime;
this.typeFactory = typeFactory;
this.osStatisticsFactory = osStatisticsFactory;
this.atomicStatisticsFactory = atomicStatisticsFactory;
this.pidSupplier = pidSupplier;
}
@Override
public String getName() {
return name;
}
@Override
public int getPid() {
return pidSupplier.getAsInt();
}
@Override
public long getStartTime() {
return startTime;
}
@Override
public List<Statistics> getStatsList() {
return instances;
}
@Override
public int getStatListModCount() {
return modificationCount;
}
@Override
public Statistics[] getStatistics() {
return getStatsList().toArray(new Statistics[0]);
}
@Override
public int getStatisticsCount() {
return getStatsList().size();
}
@Override
public StatisticsType createType(String name, String description, StatisticDescriptor[] stats) {
return typeFactory.createType(name, description, stats);
}
@Override
public StatisticsType[] createTypesFromXml(Reader reader) throws IOException {
return typeFactory.createTypesFromXml(reader);
}
@Override
public StatisticsType findType(String name) {
return typeFactory.findType(name);
}
@Override
public Statistics createStatistics(StatisticsType type) {
return createOsStatistics(type, null, 0, 0);
}
@Override
public Statistics createAtomicStatistics(StatisticsType type) {
return createAtomicStatistics(type, null, 0);
}
@Override
public Statistics createStatistics(StatisticsType type, String textId) {
return createOsStatistics(type, textId, 0, 0);
}
@Override
public Statistics createAtomicStatistics(StatisticsType type, String textId) {
return createAtomicStatistics(type, textId, 0);
}
@Override
public Statistics createStatistics(StatisticsType type, String textId, long numericId) {
return createOsStatistics(type, textId, numericId, 0);
}
@Override
public Statistics createAtomicStatistics(StatisticsType type, String textId, long numericId) {
long uniqueId = nextUniqueId.getAndIncrement();
return newAtomicStatistics(type, uniqueId, numericId, textId);
}
@Override
public Statistics createOsStatistics(StatisticsType type, String textId, long numericId,
int osStatFlags) {
long uniqueId = nextUniqueId.getAndIncrement();
return newOsStatistics(type, uniqueId, numericId, textId, osStatFlags);
}
@Override
public void destroyStatistics(Statistics statisticsToDestroy) {
deregisterDestroyedStatistics(statisticsToDestroy);
}
@Override
public boolean statisticsExists(long uniqueId) {
return anyStatisticsInstance(withUniqueId(uniqueId))
.isPresent();
}
@Override
public Statistics findStatisticsByUniqueId(long uniqueId) {
return anyStatisticsInstance(withUniqueId(uniqueId))
.orElse(null);
}
@Override
public Statistics[] findStatisticsByNumericId(long numericId) {
return allStatisticsInstances(withNumericId(numericId))
.toArray(Statistics[]::new);
}
@Override
public Statistics[] findStatisticsByTextId(String textId) {
return allStatisticsInstances(withTextId(textId))
.toArray(Statistics[]::new);
}
@Override
public Statistics[] findStatisticsByType(StatisticsType type) {
return allStatisticsInstances(withStatisticsType(type))
.toArray(Statistics[]::new);
}
@Override
public StatisticDescriptor createIntCounter(String name, String description, String units) {
return typeFactory.createIntCounter(name, description, units);
}
@Override
public StatisticDescriptor createLongCounter(String name, String description, String units) {
return typeFactory.createLongCounter(name, description, units);
}
@Override
public StatisticDescriptor createDoubleCounter(String name, String description, String units) {
return typeFactory.createDoubleCounter(name, description, units);
}
@Override
public StatisticDescriptor createIntGauge(String name, String description, String units) {
return typeFactory.createIntGauge(name, description, units);
}
@Override
public StatisticDescriptor createLongGauge(String name, String description, String units) {
return typeFactory.createLongGauge(name, description, units);
}
@Override
public StatisticDescriptor createDoubleGauge(String name, String description, String units) {
return typeFactory.createDoubleGauge(name, description, units);
}
@Override
public StatisticDescriptor createIntCounter(String name, String description, String units,
boolean largerBetter) {
return typeFactory.createIntCounter(name, description, units, largerBetter);
}
@Override
public StatisticDescriptor createLongCounter(String name, String description, String units,
boolean largerBetter) {
return typeFactory.createLongCounter(name, description, units, largerBetter);
}
@Override
public StatisticDescriptor createDoubleCounter(String name, String description, String units,
boolean largerBetter) {
return typeFactory.createDoubleCounter(name, description, units, largerBetter);
}
@Override
public StatisticDescriptor createIntGauge(String name, String description, String units,
boolean largerBetter) {
return typeFactory.createIntGauge(name, description, units, largerBetter);
}
@Override
public StatisticDescriptor createLongGauge(String name, String description, String units,
boolean largerBetter) {
return typeFactory.createLongGauge(name, description, units, largerBetter);
}
@Override
public StatisticDescriptor createDoubleGauge(String name, String description, String units,
boolean largerBetter) {
return typeFactory.createDoubleGauge(name, description, units, largerBetter);
}
protected Statistics newAtomicStatistics(StatisticsType type, long uniqueId, long numericId,
String textId) {
Statistics statistics =
atomicStatisticsFactory.create(type, textId, numericId, uniqueId, this);
registerNewStatistics(statistics);
return statistics;
}
protected Statistics newOsStatistics(StatisticsType type, long uniqueId, long numericId,
String textId, int osStatFlags) {
Statistics statistics = osStatisticsFactory.create(type, textId, numericId, uniqueId,
osStatFlags, this);
registerNewStatistics(statistics);
return statistics;
}
private Stream<Statistics> allStatisticsInstances(Predicate<? super Statistics> predicate) {
return getStatsList().stream().filter(predicate);
}
private Optional<Statistics> anyStatisticsInstance(Predicate<? super Statistics> predicate) {
return allStatisticsInstances(predicate).findAny();
}
private static Predicate<Statistics> withNumericId(long numericId) {
return statistics -> statistics.getNumericId() == numericId;
}
private static Predicate<Statistics> withStatisticsType(StatisticsType type) {
return statistics -> statistics.getType() == type;
}
private static Predicate<Statistics> withTextId(String textId) {
return statistics -> textId.equals(statistics.getTextId());
}
private static Predicate<Statistics> withUniqueId(long uniqueId) {
return statistics -> statistics.getUniqueId() == uniqueId;
}
private void registerNewStatistics(Statistics newStatistics) {
synchronized (instances) {
instances.add(newStatistics);
modificationCount++;
}
}
private void deregisterDestroyedStatistics(Statistics destroyedStatistics) {
synchronized (instances) {
if (instances.remove(destroyedStatistics)) {
modificationCount++;
}
}
}
}