/** * 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.Calendar; import java.util.Collections; import java.util.Date; import java.util.GregorianCalendar; import java.util.LinkedList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; 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.exception.QueryException; /** * * @author tflobbe * */ @StressTestScope public class FullQueryStatistic implements QueryStatistic { /** * Stores the execution time as key, and the sumation of strings times on the same instant. */ private SortedMap<Long, Integer> queryTimeByDate; /** * This list will not always be sorted. If some method need it to be sorted, it has so sort it first. * The idea of always sorting the same collection is tha it's faster to sort a "pretty much sorted" * collection than a completly unsorted one. */ private List<Integer> sortedQueryTimes; private Date lastErrorDate; private int totalQTime; @Inject public FullQueryStatistic() { lastErrorDate = null; queryTimeByDate = Collections.synchronizedSortedMap(new TreeMap<Long, Integer>()); sortedQueryTimes = Collections.synchronizedList(new LinkedList<Integer>()); totalQTime = 0; } @Override public void onExecutedQuery(QueryResponse response, long clientTime) { sortedQueryTimes.add(response.getQTime()); totalQTime+=response.getQTime(); long mapKey = new Date().getTime(); Integer actualValue = queryTimeByDate.get(mapKey); Integer newValue; if(actualValue == null) { newValue = response.getQTime(); }else { newValue = actualValue + response.getQTime(); } queryTimeByDate.put(mapKey, newValue); } @Override public void onFinishedTest() { } @Override public void onQueryError(QueryException exception) { lastErrorDate = exception.getDate(); } public Double getMedian() { if(sortedQueryTimes.isEmpty()) { return new Double(0); } synchronized (sortedQueryTimes) { Collections.sort(sortedQueryTimes); if((sortedQueryTimes.size()&1) ==0) { int firstIndex = sortedQueryTimes.size()/2 - 1; int secondIndex = sortedQueryTimes.size()/2 ; return new Double(((double)sortedQueryTimes.get(firstIndex) + (double)sortedQueryTimes.get(secondIndex))/ 2); }else { return new Double(sortedQueryTimes.get(sortedQueryTimes.size()/2)); } } } public Integer getMode() { int actualValue = -1; int actualValueCount = 0; int maxValueCount = -1; int actualMode = -1; synchronized (sortedQueryTimes) { Collections.sort(sortedQueryTimes); for(Integer integer:sortedQueryTimes) { if(integer == actualValue) { actualValueCount++; }else { if(actualValueCount > maxValueCount) { maxValueCount = actualValueCount; actualMode = actualValue; } actualValue = integer; actualValueCount = 1; } } } if(actualValueCount > maxValueCount) { maxValueCount = actualValueCount; actualMode = actualValue; } return actualMode; } public Double getVariance() { if(sortedQueryTimes.size() == 0) { return new Double(0); } double average = (double)totalQTime/sortedQueryTimes.size(); double sumation = 0; synchronized (sortedQueryTimes) { for(Integer value:sortedQueryTimes) { sumation+= Math.pow((double)(value - average), 2.0); } return sumation / sortedQueryTimes.size(); } } public Double getStandardDeviation() { return Math.sqrt(getVariance()); } public Integer getTotaAverage() { if(sortedQueryTimes.size() == 0) { return -1; } return totalQTime/sortedQueryTimes.size(); } public Integer getLastMinuteAverage() { Calendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, -1); return getAverageSince(calendar.getTime()); } public Integer getLastTenMinutesAverage() { Calendar calendar = new GregorianCalendar(); calendar.add(Calendar.MINUTE, -10); return getAverageSince(calendar.getTime()); } public Integer getAverageSince(Date sinceDate) { int sumation = 0; int cantItems = 0; long minDate = sinceDate.getTime(); synchronized (queryTimeByDate) { for(Long value:queryTimeByDate.keySet()) { if(value >= minDate) { sumation+=queryTimeByDate.get(value); cantItems++; } } } if(cantItems != 0) { return sumation/cantItems; }else { return -1; } } public Date getLastErrorTime() { return lastErrorDate; } }