All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ehcache.impl.internal.statistics.StatsUtils Maven / Gradle / Ivy
/*
* 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 org.ehcache.impl.internal.statistics;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.ehcache.Cache;
import org.ehcache.core.statistics.StoreOperationOutcomes;
import org.terracotta.context.ContextManager;
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 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.QueryBuilder.queryBuilder;
/**
* Class allowing to query cache and tier statistics
*/
final class StatsUtils {
private StatsUtils() {}
static Matcher> hasTag(final String tag) {
return hasAttribute("tags", new Matcher>() {
@Override
protected boolean matchesSafely(Set object) {
return object.contains(tag);
}
});
}
static Matcher> hasProperty(final String key, final String value) {
return hasAttribute("properties", new Matcher>() {
@Override
protected boolean matchesSafely(Map properties) {
Object val = properties.get(key);
return val != null && value.equals(val);
}
});
}
/**
* Search for a statistic on the descendant of the context that matches the tag and statistic name.
*
* @param context the context of the query
* @param discriminator a filter on the discriminator property
* @param tag the tag we are looking for
* @param statName statistic name
* @param type of the statistic that will be returned
* @return the wanted statistic or null if no such statistic is found
* @throws RuntimeException when more than one matching statistic is found
*/
static Optional findStatisticOnDescendants(Object context, String discriminator, String tag, String statName) {
@SuppressWarnings("unchecked")
Set statResult = queryBuilder()
.descendants()
.filter(context(attributes(Matchers.allOf(
hasAttribute("name", statName),
hasProperty("discriminator", discriminator),
hasTag(tag)))))
.build().execute(Collections.singleton(ContextManager.nodeFor(context)));
if (statResult.size() > 1) {
throw new RuntimeException("One stat expected for " + statName + " but found " + statResult.size());
}
if (statResult.size() == 1) {
@SuppressWarnings("unchecked")
T result = (T) statResult.iterator().next().getContext().attributes().get("this");
return Optional.ofNullable(result);
}
// No such stat in this context
return Optional.empty();
}
/**
* Search for a statistic on the descendant of the context that matches the tag and statistic name.
*
* @param context the context of the query
* @param tag the tag we are looking for
* @param statName statistic name
* @param type of the statistic that will be returned
* @return the wanted statistic or null if no such statistic is found
* @throws RuntimeException when more than one matching statistic is found
*/
static Optional findStatisticOnDescendants(Object context, String tag, String statName) {
@SuppressWarnings("unchecked")
Set statResult = queryBuilder()
.descendants()
.filter(context(attributes(Matchers.allOf(
hasAttribute("name", statName),
hasTag(tag)))))
.build().execute(Collections.singleton(ContextManager.nodeFor(context)));
if (statResult.size() > 1) {
throw new RuntimeException("One stat expected for " + statName + " but found " + statResult.size());
}
if (statResult.size() == 1) {
@SuppressWarnings("unchecked")
T result = (T) statResult.iterator().next().getContext().attributes().get("this");
return Optional.ofNullable(result);
}
// No such stat in this context
return Optional.empty();
}
/**
* Find an operation statistic attached (as a children) to this context that matches the statistic name and type
*
* @param context the context of the query
* @param type type of the operation statistic
* @param statName statistic name
* @param type of the operation statistic content
* @return the operation statistic searched for
* @throws RuntimeException if 0 or more than 1 result is found
*/
static > OperationStatistic findOperationStatisticOnChildren(Object context, Class type, String statName) {
@SuppressWarnings("unchecked")
Query query = queryBuilder()
.children()
.filter(context(attributes(Matchers.allOf(hasAttribute("name", statName), hasAttribute("type", type)))))
.build();
Set result = query.execute(Collections.singleton(ContextManager.nodeFor(context)));
if (result.size() > 1) {
throw new RuntimeException("result must be unique");
}
if (result.isEmpty()) {
throw new RuntimeException("result must not be null");
}
@SuppressWarnings("unchecked")
OperationStatistic statistic = (OperationStatistic) result.iterator().next().getContext().attributes().get("this");
return statistic;
}
/**
* Find the list of tiers of a cache. We assume a lot of things here.
*
* The "eviction" statistic is available on the tier
* That the tiers have only one tag attribute
* That this tag contains the tier name
* That the only descendants having an "eviction" statistic are the tiers
*
*
* @param cache the context for looking for tiers
* @return an array of tier names
* @throws RuntimeException if not tiers are found or if tiers have multiple tags
*/
static String[] findTiers(Cache cache) {
// Here I'm randomly taking the eviction observer because it exists on all tiers
@SuppressWarnings("unchecked")
Query statQuery = queryBuilder()
.descendants()
.filter(context(attributes(Matchers.allOf(hasAttribute("name", "eviction"), hasAttribute("type", StoreOperationOutcomes.EvictionOutcome.class)))))
.build();
Set statResult = statQuery.execute(Collections.singleton(ContextManager.nodeFor(cache)));
if (statResult.isEmpty()) {
throw new RuntimeException("Failed to find tiers using the eviction observer, valid result Set sizes must 1 or more");
}
String[] tiers = new String[statResult.size()];
int i = 0;
for (TreeNode treeNode : statResult) {
Set tags = (Set) treeNode.getContext().attributes().get("tags");
if (tags.size() != 1) {
throw new RuntimeException("We expect tiers to have only one tag");
}
String storeType = tags.iterator().next().toString();
tiers[i++] = storeType;
}
return tiers;
}
/**
* Find the lowest tier from a list of tier. We assume a lot of things here that the tiers depth
* magically matches the alphabetical order.
*
* @param tiers all tiers
* @return the lowest tier
*/
static String findLowestTier(String[] tiers) {
//if only 1 store then you don't need to find the lowest tier
if (tiers.length == 1) {
return tiers[0];
}
//we expect at least one tier
if (tiers.length == 0) {
throw new RuntimeException("No existing tier");
}
// We rely here on the alphabetical order matching the depth order so from highest to lowest we have
// OnHeap, OffHeap, Disk, Clustered
String lowestTier = tiers[0];
for (int i = 1; i < tiers.length; i++) {
if (tiers[i].compareTo(lowestTier) < 0) {
lowestTier = tiers[i];
}
}
return lowestTier;
}
}