/** * Copyright Plugtree LLC * * 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 com.plugtree.solrmeter.model.statistic; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.apache.solr.client.solrj.response.QueryResponse; import com.google.inject.Inject; import com.plugtree.stressTestScope.StressTestScope; import com.plugtree.solrmeter.model.QueryStatistic; import com.plugtree.solrmeter.model.SolrMeterConfiguration; import com.plugtree.solrmeter.model.exception.QueryException; /** * * Statistic to divide QTimes in time intervals. * @author tflobbe * */ @StressTestScope public class TimeRangeStatistic implements QueryStatistic { private Map<TimeRange, Integer> counter; private int totalQueries; @Inject public TimeRangeStatistic() { counter = Collections.synchronizedMap(new HashMap<TimeRange, Integer>()); this.addConfiguredRanges(); } public TimeRangeStatistic(boolean useDefault) { this(); if(useDefault) { addNewRange(0, 500); addNewRange(501, 1000); addNewRange(1001, 2000); addNewRange(2001, Integer.MAX_VALUE); } } private void addConfiguredRanges() { List<String> keys = SolrMeterConfiguration.getKeys(Pattern.compile("statistic\\.timeRange\\.range\\d*_\\d*")); for(String key:keys) { int min = getMinValue(key); int max = getMaxValue(key); addNewRange(min, max); } if(this.overlap()) { Logger.getLogger(this.getClass()).warn("Warning! the time range statistic ranges overlap"); } } private int getMaxValue(String property) { return Integer.valueOf(property.replaceAll("statistic\\.timeRange\\.range\\d*_", "")); } private int getMinValue(String property) { return Integer.valueOf(property.replaceAll("statistic\\.timeRange\\.range", "").replaceAll("_\\d*", "")); } @Override public void onExecutedQuery(QueryResponse response, long clientTime) { synchronized (counter) { for(TimeRange range:counter.keySet()) { if(range.isIncluded(response.getQTime())) { counter.put(range, counter.get(range) + 1); } } } totalQueries++; } @Override public void onFinishedTest() { //does nothing } /** * * @return Returns all the configured timeRanges and the percentage of strings on * each one of them. */ public Map<TimeRange, Integer> getActualPercentage() { Map<TimeRange, Integer> map = new HashMap<TimeRange, Integer>(); if(totalQueries == 0) { return map; } synchronized (counter) { for(TimeRange range:counter.keySet()) { map.put(range, (counter.get(range) * 100) / totalQueries); } } return map; } @Override public void onQueryError(QueryException exception) { } /** * Sets all counters to 0. */ public void restartCounter() { synchronized (counter) { for(TimeRange range:counter.keySet()) { counter.put(range, 0); } } totalQueries = 0; } public void addNewRange(int init, int end) { counter.put(new TimeRange(init, end), 0); SolrMeterConfiguration.setProperty(getPropertyKey(init, end), "true"); } private String getPropertyKey(int init, int end) { return "statistic.timeRange.range" + init + "_" + end; } public void removeRange(int init, int end) { if(counter.remove(new TimeRange(init, end)) == null) { throw new RuntimeException(); } SolrMeterConfiguration.removeProperty(getPropertyKey(init, end)); } public boolean overlap() { LinkedList<TimeRange> ranges = new LinkedList<TimeRange>(counter.keySet()); Collections.sort(ranges, new Comparator<TimeRange>() { @Override public int compare(TimeRange arg0, TimeRange arg1) { if(arg0.getMinTime() > arg1.getMinTime()) { return 1; } if(arg0.getMinTime() < arg1.getMinTime()) { return -1; } return 0; } }); for(int i = 0; i < (ranges.size() - 1); i++) { if(ranges.get(i).getMaxTime() >= ranges.get(i + 1).getMinTime()) { return true; } } return false; } public int getCounterCount() { return counter.size(); } public Collection<TimeRange> getActualRanges() { return counter.keySet(); } public void removeAllRanges() { List<TimeRange> ranges = new LinkedList<TimeRange>(getActualRanges()); for(TimeRange range:ranges) { this.removeRange(range.getMinTime(), range.getMaxTime()); } } }