net.sf.ehcache.statistics.extended.ExtendedStatisticsImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache-core Show documentation
Show all versions of ehcache-core Show documentation
Internal ehcache-core module. This artifact is not meant to be used directly
/**
* Copyright Terracotta, Inc.
*
* 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 net.sf.ehcache.statistics.extended;
import net.sf.ehcache.CacheOperationOutcomes;
import net.sf.ehcache.CacheOperationOutcomes.ClusterEventOutcomes;
import net.sf.ehcache.CacheOperationOutcomes.EvictionOutcome;
import net.sf.ehcache.CacheOperationOutcomes.ExpiredOutcome;
import net.sf.ehcache.CacheOperationOutcomes.GetOutcome;
import net.sf.ehcache.CacheOperationOutcomes.NonStopOperationOutcomes;
import net.sf.ehcache.CacheOperationOutcomes.PutOutcome;
import net.sf.ehcache.CacheOperationOutcomes.RemoveOutcome;
import net.sf.ehcache.CacheOperationOutcomes.SearchOutcome;
import net.sf.ehcache.statistics.StatisticsGateway;
import net.sf.ehcache.store.StoreOperationOutcomes;
import net.sf.ehcache.transaction.xa.XaCommitOutcome;
import net.sf.ehcache.transaction.xa.XaRecoveryOutcome;
import net.sf.ehcache.transaction.xa.XaRollbackOutcome;
import net.sf.ehcache.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terracotta.context.TreeNode;
import org.terracotta.context.query.Matcher;
import org.terracotta.context.query.Matchers;
import org.terracotta.context.query.Query;
import org.terracotta.statistics.OperationStatistic;
import org.terracotta.statistics.StatisticsManager;
import org.terracotta.statistics.Time;
import org.terracotta.statistics.ValueStatistic;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.terracotta.context.query.Matchers.attributes;
import static org.terracotta.context.query.Matchers.context;
import static org.terracotta.context.query.Matchers.hasAttribute;
import static org.terracotta.context.query.Matchers.identifier;
import static org.terracotta.context.query.Matchers.subclassOf;
import static org.terracotta.context.query.QueryBuilder.queryBuilder;
/**
* The Class ExtendedStatisticsImpl.
*
* @author cschanck
*/
public class ExtendedStatisticsImpl implements ExtendedStatistics {
/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory.getLogger(ExtendedStatisticsImpl.class);
/** The standard pass throughs. */
private final ConcurrentMap> standardPassThroughs =
new ConcurrentHashMap>();
/** The standard operations. */
private final ConcurrentMap> standardOperations =
new ConcurrentHashMap>();
/** The custom operations. */
private final ConcurrentMap, CompoundOperationImpl>> customOperations =
new ConcurrentHashMap, CompoundOperationImpl>>();
/** custom pass thru stats*/
private final ConcurrentHashMap, Set>> customPassthrus =
new ConcurrentHashMap, Set>>();
/** The manager. */
private final StatisticsManager manager;
/** The executor. */
private final ScheduledExecutorService executor;
/** The disable task. */
private final Runnable disableTask = new Runnable() {
@Override
public void run() {
long expireThreshold = Time.absoluteTime() - timeToDisableUnit.toMillis(timeToDisable);
for (Operation> o : standardOperations.values()) {
if (o instanceof CompoundOperationImpl>) {
((CompoundOperationImpl>) o).expire(expireThreshold);
}
}
for (Iterator> it = customOperations.values().iterator(); it.hasNext();) {
if (it.next().expire(expireThreshold)) {
it.remove();
}
}
}
};
/** The time to disable. */
private long timeToDisable;
/** The time to disable unit. */
private TimeUnit timeToDisableUnit;
/** The disable status. */
private ScheduledFuture disableStatus;
/** The all cache get. */
private final Result allCacheGet;
/** The all cache miss. */
private final Result allCacheMiss;
/** The all cache put. */
private final Result allCachePut;
/** The all heap put. */
private final Result allHeapPut;
/** The all off heap put. */
private final Result allOffHeapPut;
/** The all disk put. */
private final Result allDiskPut;
/** The cache hit ratio. */
private Statistic cacheHitRatio;
/** on stop timeout ratio */
private Statistic nonStopTimeoutRatio;
private final int defaultHistorySize;
private final long defaultIntervalSeconds;
private final long defaultSearchIntervalSeconds;
/**
* Instantiates a new extended statistics impl.
*
* @param manager the manager
* @param executor the executor
* @param timeToDisable the time to disable
* @param unit the unit
*/
public ExtendedStatisticsImpl(StatisticsManager manager, ScheduledExecutorService executor, long timeToDisable, TimeUnit unit,
int defaultHistorySize, long defaultIntervalSeconds, long defaultSearchIntervalSeconds) {
this.manager = manager;
this.executor = executor;
this.timeToDisable = timeToDisable;
this.timeToDisableUnit = unit;
this.defaultHistorySize = defaultHistorySize;
this.defaultIntervalSeconds = defaultIntervalSeconds;
this.defaultSearchIntervalSeconds = defaultSearchIntervalSeconds;
this.disableStatus = this.executor.scheduleAtFixedRate(disableTask, timeToDisable, timeToDisable, unit);
findStandardPassThruStatistics();
findStandardOperationStatistics();
// well known compound results.
this.allCacheGet = get().compound(ALL_CACHE_GET_OUTCOMES);
this.allCacheMiss = get().compound(ALL_CACHE_MISS_OUTCOMES);
this.allCachePut = put().compound(ALL_CACHE_PUT_OUTCOMES);
this.allHeapPut = heapPut().compound(ALL_STORE_PUT_OUTCOMES);
this.allOffHeapPut = offheapPut().compound(ALL_STORE_PUT_OUTCOMES);
this.allDiskPut = diskPut().compound(ALL_STORE_PUT_OUTCOMES);
this.cacheHitRatio = get().ratioOf(EnumSet.of(CacheOperationOutcomes.GetOutcome.HIT),
EnumSet.allOf(CacheOperationOutcomes.GetOutcome.class));
this.nonStopTimeoutRatio = nonstop().ratioOf(
EnumSet.of(CacheOperationOutcomes.NonStopOperationOutcomes.REJOIN_TIMEOUT,
CacheOperationOutcomes.NonStopOperationOutcomes.TIMEOUT),
EnumSet.allOf(CacheOperationOutcomes.NonStopOperationOutcomes.class));
}
/**
* Find standard operation statistics.
*/
private void findStandardOperationStatistics() {
for (final StandardOperationStatistic t : StandardOperationStatistic.values()) {
OperationStatistic statistic = findOperationStatistic(manager, t);
if (statistic == null) {
if (t.required()) {
throw new IllegalStateException("Required statistic " + t + " not found");
} else {
LOGGER.debug("Mocking Operation Statistic: {}", t);
standardOperations.put(t, NullCompoundOperation.instance(t.type()));
}
} else {
standardOperations.put(t, new CompoundOperationImpl(statistic, t.type(), StatisticsGateway.DEFAULT_WINDOW_SIZE_SECS,
SECONDS, executor, defaultHistorySize, t.isSearch() ? defaultSearchIntervalSeconds : defaultIntervalSeconds,
SECONDS));
}
}
}
/**
* Find standard pass thru statistics.
*/
private void findStandardPassThruStatistics() {
for (final StandardPassThroughStatistic t : StandardPassThroughStatistic.values()) {
ValueStatistic statistic = findPassThroughStatistic(manager, t);
if (statistic == null) {
LOGGER.debug("Mocking Pass-Through Statistic: {}", t);
standardPassThroughs.put(t, NullStatistic.instance(t.absentValue()));
} else {
standardPassThroughs.put(t,
new SemiExpiringStatistic(statistic, executor, defaultHistorySize, SECONDS.toNanos(defaultIntervalSeconds)));
}
}
}
@Override
public Set> passthru(String name, Set tags) {
ArrayList key = new ArrayList(tags.size() + 1);
key.addAll(tags);
Collections.sort(key);
key.add(name);
if (customPassthrus.containsKey(key)) {
return customPassthrus.get(key);
}
// lets make sure we don't get it twice.
synchronized (customPassthrus) {
if (customPassthrus.containsKey(key)) {
return customPassthrus.get(key);
}
Set> interim = findPassThroughStatistic(manager,
EhcacheQueryBuilder.cache().descendants(),
name,
tags);
if (interim.isEmpty()) {
return Collections.EMPTY_SET;
}
Set> ret = new HashSet>(interim.size());
for (ValueStatistic> vs : interim) {
SemiExpiringStatistic stat = new SemiExpiringStatistic(vs, executor, defaultHistorySize, SECONDS.toNanos(defaultIntervalSeconds));
ret.add(stat);
}
customPassthrus.put(key, ret);
return ret;
}
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#setTimeToDisable(long, java.util.concurrent.TimeUnit)
*/
@Override
public synchronized void setTimeToDisable(long time, TimeUnit unit) {
timeToDisable = time;
timeToDisableUnit = unit;
if (disableStatus != null) {
disableStatus.cancel(false);
disableStatus = executor.scheduleAtFixedRate(disableTask, timeToDisable, timeToDisable, timeToDisableUnit);
}
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#setAlwaysOn(boolean)
*/
@Override
public synchronized void setAlwaysOn(boolean enabled) {
if (enabled) {
if (disableStatus != null) {
disableStatus.cancel(false);
disableStatus = null;
}
for (Operation> o : standardOperations.values()) {
o.setAlwaysOn(true);
}
} else {
if (disableStatus == null) {
disableStatus = executor.scheduleAtFixedRate(disableTask, 0, timeToDisable, timeToDisableUnit);
}
for (Operation> o : standardOperations.values()) {
o.setAlwaysOn(false);
}
}
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#get()
*/
@Override
public Operation get() {
return (Operation) getStandardOperation(StandardOperationStatistic.CACHE_GET);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#put()
*/
@Override
public Operation put() {
return (Operation) getStandardOperation(StandardOperationStatistic.CACHE_PUT);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#remove()
*/
@Override
public Operation remove() {
return (Operation) getStandardOperation(StandardOperationStatistic.CACHE_REMOVE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#replaceOneArg()
*/
@Override
public Operation replaceOneArg() {
return (Operation) getStandardOperation(StandardOperationStatistic.CACHE_ONE_ARG_REPLACE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#replaceTwoArg()
*/
@Override
public Operation replaceTwoArg() {
return (Operation) getStandardOperation(StandardOperationStatistic.CACHE_TWO_ARG_REPLACE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#putIfAbsent()
*/
@Override
public Operation putIfAbsent() {
return (Operation) getStandardOperation(StandardOperationStatistic.CACHE_PUT_IF_ABSENT);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#removeElement()
*/
@Override
public Operation removeElement() {
return (Operation) getStandardOperation(StandardOperationStatistic.CACHE_REMOVE_ELEMENT);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#search()
*/
@Override
public Operation search() {
return (Operation) getStandardOperation(StandardOperationStatistic.SEARCH);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#heapGet()
*/
@Override
public Operation heapGet() {
return (Operation) getStandardOperation(StandardOperationStatistic.HEAP_GET);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#heapPut()
*/
@Override
public Operation heapPut() {
return (Operation) getStandardOperation(StandardOperationStatistic.HEAP_PUT);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#heapRemove()
*/
@Override
public Operation heapRemove() {
return (Operation) getStandardOperation(StandardOperationStatistic.HEAP_REMOVE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#offheapGet()
*/
@Override
public Operation offheapGet() {
return (Operation) getStandardOperation(StandardOperationStatistic.OFFHEAP_GET);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#offheapPut()
*/
@Override
public Operation offheapPut() {
return (Operation) getStandardOperation(StandardOperationStatistic.OFFHEAP_PUT);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#offheapRemove()
*/
@Override
public Operation offheapRemove() {
return (Operation) getStandardOperation(StandardOperationStatistic.OFFHEAP_REMOVE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#diskGet()
*/
@Override
public Operation diskGet() {
return (Operation) getStandardOperation(StandardOperationStatistic.DISK_GET);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#diskPut()
*/
@Override
public Operation diskPut() {
return (Operation) getStandardOperation(StandardOperationStatistic.DISK_PUT);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#diskRemove()
*/
@Override
public Operation diskRemove() {
return (Operation) getStandardOperation(StandardOperationStatistic.DISK_REMOVE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#xaCommit()
*/
@Override
public Operation xaCommit() {
return (Operation) getStandardOperation(StandardOperationStatistic.XA_COMMIT);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#xaRollback()
*/
@Override
public Operation xaRollback() {
return (Operation) getStandardOperation(StandardOperationStatistic.XA_ROLLBACK);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#xaRecovery()
*/
@Override
public Operation xaRecovery() {
return (Operation) getStandardOperation(StandardOperationStatistic.XA_RECOVERY);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#eviction()
*/
@Override
public Operation eviction() {
return (Operation) getStandardOperation(StandardOperationStatistic.EVICTION);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#expiry()
*/
@Override
public Operation expiry() {
return (Operation) getStandardOperation(StandardOperationStatistic.EXPIRY);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getCacheHitRatio()
*/
@Override
public Statistic cacheHitRatio() {
return cacheHitRatio;
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#allGet()
*/
@Override
public Result allGet() {
return allCacheGet;
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#allMiss()
*/
@Override
public Result allMiss() {
return allCacheMiss;
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#allPut()
*/
@Override
public Result allPut() {
return allCachePut;
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#heapAllPut()
*/
@Override
public Result heapAllPut() {
return allHeapPut;
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#offHeapAllPut()
*/
@Override
public Result offHeapAllPut() {
return allOffHeapPut;
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#diskAllPut()
*/
@Override
public Result diskAllPut() {
return allDiskPut;
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#operations(java.lang.Class, java.lang.String, java.lang.String[])
*/
@Override
public > Set> operations(Class outcome, String name, String... tags) {
Set> sources = findOperationStatistic(manager, queryBuilder().descendants().build(), outcome, name,
new HashSet(Arrays.asList(tags)));
if (sources.isEmpty()) {
return Collections.emptySet();
} else {
Set> operations = new HashSet();
for (OperationStatistic source : sources) {
CompoundOperationImpl operation = (CompoundOperationImpl) customOperations.get(source);
if (operation == null) {
operation = new CompoundOperationImpl(source, source.type(), 1, SECONDS, executor, 0, 1, SECONDS);
CompoundOperationImpl racer = (CompoundOperationImpl) customOperations.putIfAbsent(source, operation);
if (racer != null) {
operation = racer;
}
}
operations.add(operation);
}
return operations;
}
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getLocalHeapSize()
*/
@Override
public Statistic localHeapSize() {
return getStandardPassThrough(StandardPassThroughStatistic.LOCAL_HEAP_SIZE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getLocalHeapSizeInBytes()
*/
@Override
public Statistic localHeapSizeInBytes() {
return getStandardPassThrough(StandardPassThroughStatistic.LOCAL_HEAP_SIZE_BYTES);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getLocalOffHeapSize()
*/
@Override
public Statistic localOffHeapSize() {
return getStandardPassThrough(StandardPassThroughStatistic.LOCAL_OFFHEAP_SIZE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getLocalOffHeapSizeInBytes()
*/
@Override
public Statistic localOffHeapSizeInBytes() {
return getStandardPassThrough(StandardPassThroughStatistic.LOCAL_OFFHEAP_SIZE_BYTES);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getLocalDiskSize()
*/
@Override
public Statistic localDiskSize() {
return getStandardPassThrough(StandardPassThroughStatistic.LOCAL_DISK_SIZE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getLocalDiskSizeInBytes()
*/
@Override
public Statistic localDiskSizeInBytes() {
return getStandardPassThrough(StandardPassThroughStatistic.LOCAL_DISK_SIZE_BYTES);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getRemoteSize()
*/
@Override
public Statistic remoteSize() {
return getStandardPassThrough(StandardPassThroughStatistic.REMOTE_SIZE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getSize()
*/
@Override
public Statistic size() {
return getStandardPassThrough(StandardPassThroughStatistic.CACHE_SIZE);
}
/*
* (non-Javadoc)
*
* @see net.sf.ehcache.statistics.extended.ExtendedStatistics#getWriterQueueLength()
*/
@Override
public Statistic writerQueueLength() {
return getStandardPassThrough(StandardPassThroughStatistic.WRITER_QUEUE_LENGTH);
}
/**
* Gets the standard operation.
*
* @param statistic the statistic
* @return the standard operation
*/
private Operation> getStandardOperation(StandardOperationStatistic statistic) {
Operation> operation = standardOperations.get(statistic);
if (operation instanceof NullCompoundOperation>) {
OperationStatistic> discovered = findOperationStatistic(manager, statistic);
if (discovered == null) {
return operation;
} else {
Operation> newOperation = new CompoundOperationImpl(discovered, statistic.type(),
StatisticsGateway.DEFAULT_WINDOW_SIZE_SECS, SECONDS, executor, defaultHistorySize,
statistic.isSearch() ? defaultSearchIntervalSeconds : defaultIntervalSeconds, SECONDS);
if (standardOperations.replace(statistic, operation, newOperation)) {
return newOperation;
} else {
return standardOperations.get(statistic);
}
}
} else {
return operation;
}
}
/**
* Gets the standard pass through.
*
* @param statistic the statistic
* @return the standard pass through
*/
private Statistic getStandardPassThrough(StandardPassThroughStatistic statistic) {
Statistic passThrough = standardPassThroughs.get(statistic);
if (passThrough instanceof NullStatistic>) {
ValueStatistic discovered = findPassThroughStatistic(manager, statistic);
if (discovered == null) {
return passThrough;
} else {
Statistic newPassThrough = new SemiExpiringStatistic(discovered, executor, defaultHistorySize,
SECONDS.toNanos(defaultIntervalSeconds));
if (standardPassThroughs.replace(statistic, passThrough, newPassThrough)) {
return newPassThrough;
} else {
return standardPassThroughs.get(statistic);
}
}
} else {
return passThrough;
}
}
/**
* Find operation statistic.
*
* @param manager the manager
* @param statistic the statistic
* @return the operation statistic
*/
private static OperationStatistic findOperationStatistic(StatisticsManager manager, StandardOperationStatistic statistic) {
Set> results = findOperationStatistic(manager,
statistic.context(),
statistic.type(),
statistic.operationName(),
statistic.tags());
switch (results.size()) {
case 0:
return null;
case 1:
return results.iterator().next();
default:
throw new IllegalStateException("Duplicate statistics found for " + statistic);
}
}
/**
* Find pass through statistic.
*
* @param manager the manager
* @param statistic the statistic
* @return the value statistic
*/
private static ValueStatistic findPassThroughStatistic(StatisticsManager manager, StandardPassThroughStatistic statistic) {
Set> results = findPassThroughStatistic(manager, statistic.context(), statistic.statisticName(), statistic.tags());
switch (results.size()) {
case 0:
return null;
case 1:
return results.iterator().next();
default:
throw new IllegalStateException("Duplicate statistics found for " + statistic);
}
}
/**
* Find operation statistic.
*
* @param the generic type
* @param manager the manager
* @param contextQuery the context query
* @param type the type
* @param name the name
* @param tags the tags
* @return the sets the
*/
private static > Set> findOperationStatistic(StatisticsManager manager, Query contextQuery,
Class type, String name, final Set tags) {
Set operationStatisticNodes = manager.query(queryBuilder().chain(contextQuery).children()
.filter(context(identifier(subclassOf(OperationStatistic.class)))).build());
Set result = queryBuilder()
.filter(context(attributes(Matchers.