/*
* Copyright (c) 2001-2007 Sun Micro//Systems, Inc. All rights reserved.
*
* The Sun Project JXTA(TM) Software License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by Sun Microsystems, Inc. for JXTA(TM) technology."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
* not be used to endorse or promote products derived from this software
* without prior written permission. For written permission, please contact
* Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA", nor may
* "JXTA" appear in their name, without prior written permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
* MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JXTA is a registered trademark of Sun Microsystems, Inc. in the United
* States and other countries.
*
* Please see the license information page at :
* <http://www.jxta.org/project/www/license.html> for instructions on use of
* the license in source files.
*
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of Project JXTA. For more information on Project JXTA, please see
* http://www.jxta.org.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*/
package net.jxta.impl.resolver.resolverMeter;
import java.util.Collections;
import net.jxta.endpoint.EndpointAddress;
import net.jxta.impl.meter.MetricUtilities;
import net.jxta.peer.PeerID;
import net.jxta.protocol.ResolverQueryMsg;
import net.jxta.protocol.ResolverResponseMsg;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class QueryHandlerMeter {
private static final int QUERY_CULLING_INTERVAL = 5 * 60 * 1000; // Fix-Me: Five minutes hardcoded for now...
private ResolverServiceMonitor resolverServiceMonitor;
private final String handlerName;
private QueryHandlerMetric cumulativeMetrics;
private QueryHandlerMetric deltaMetrics;
private final Map<PeerID, QueryDestinationMeter> queryDestinationMeters = new Hashtable<PeerID, QueryDestinationMeter>();
private QueryMetricsTable queryMetricsTable = null;
private class QueryMetricsTable extends Hashtable<Integer,QueryMetric> {
void deReference() {
queryMetricsTable = null;
}
@Override
public String toString() {
return handlerName;
}
}
private class QueryMetric {
int queryId;
long querySentTime = System.currentTimeMillis();
int numResponsesReceived = 0;
long lastResponseTime = 0;
QueryMetric(int queryId) {
this.queryId = queryId;
}
}
private static List<QueryMetricsTable> queryMetricsTables = new LinkedList<QueryMetricsTable>();
static {
Thread cullQueries = new Thread(new Runnable() {
public void run() {
for (;;) {
try {
Thread.sleep(QUERY_CULLING_INTERVAL);
} catch (Exception e) {}
long dormantTime = System.currentTimeMillis() - QUERY_CULLING_INTERVAL;
synchronized (queryMetricsTables) {
List<Integer> keysToRemove = new LinkedList<Integer>();
for (Iterator<QueryMetricsTable> i = queryMetricsTables.iterator(); i.hasNext();) {
QueryMetricsTable queryMetricsTable = i.next();
keysToRemove.clear();
synchronized (queryMetricsTable) {
for (Integer key : queryMetricsTable.keySet()) {
QueryMetric queryMetric = queryMetricsTable.get(key);
if (queryMetric.lastResponseTime < dormantTime) {
keysToRemove.add(key);
}
}
for (Iterator<Integer> k = keysToRemove.iterator(); k.hasNext();) {
Integer key = k.next();
queryMetricsTable.deReference();
queryMetricsTable.remove(key);
}
if (queryMetricsTable.isEmpty()) {
i.remove();
}
}
}
}
}
}
}, "Resolver Query Metrics Culling Thread");
cullQueries.setDaemon(true);
cullQueries.start();
}
public QueryHandlerMeter(String handlerName, ResolverServiceMonitor resolverServiceMonitor) {
this.handlerName = handlerName;
cumulativeMetrics = new QueryHandlerMetric(handlerName);
this.resolverServiceMonitor = resolverServiceMonitor;
}
public QueryHandlerMetric getCumulativeMetrics() {
return cumulativeMetrics;
}
public String getHandlerName() {
return handlerName;
}
public synchronized QueryHandlerMetric collectMetrics() {
QueryHandlerMetric prevDelta = deltaMetrics;
for (QueryDestinationMeter queryDestinationMeter : queryDestinationMeters.values()) {
QueryDestinationMetric queryDestinationMetric = queryDestinationMeter.collectMetrics();
if (queryDestinationMetric != null) {
/*
* Fix-me: while fixing an exception thrown by SrdiHandlerMeter, I noticed that
* a similar problem might occur here if there can be a case where a destinationMtric
* is available even though nothing has happened to create the delta.
* If that is not possible (we need to do a code review!) remove the check for
* a null delta here.
*/
if (prevDelta == null) {
createDeltaMetric();
prevDelta = deltaMetrics;
}
prevDelta.addQueryDestinationMetric(queryDestinationMetric);
}
}
deltaMetrics = null;
return prevDelta;
}
public synchronized QueryDestinationMeter getQueryDestinationMeter(EndpointAddress endpointAddress) {
PeerID peerID = MetricUtilities.getPeerIdFromEndpointAddress(endpointAddress);
return getQueryDestinationMeter(peerID);
}
public synchronized QueryDestinationMeter getQueryDestinationMeter(String peerIdString) {
PeerID peerID = MetricUtilities.getPeerIdFromString(peerIdString);
return getQueryDestinationMeter(peerID);
}
public synchronized QueryDestinationMeter getQueryDestinationMeter(PeerID peerID) {
QueryDestinationMeter queryDestinationMeter = queryDestinationMeters.get(peerID);
if (queryDestinationMeter == null) {
queryDestinationMeter = new QueryDestinationMeter(peerID);
queryDestinationMeters.put(peerID, queryDestinationMeter);
cumulativeMetrics.addQueryDestinationMetric(queryDestinationMeter.getCumulativeMetrics());
}
return queryDestinationMeter;
}
private void createDeltaMetric() {
deltaMetrics = new QueryHandlerMetric(handlerName);
}
@Override
public String toString() {
return "QueryHandlerMeter(" + handlerName + ")";
}
public void setRegistered(boolean registered) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.setRegistered(registered);
cumulativeMetrics.setRegistered(registered);
}
private QueryMetric getQueryMetric(int queryId) {
synchronized (queryMetricsTables) {
if (queryMetricsTable == null) {
queryMetricsTable = new QueryMetricsTable();
queryMetricsTables.add(queryMetricsTable);
}
QueryMetric queryMetric = queryMetricsTable.get(queryId);
if (queryMetric == null) {
queryMetric = new QueryMetric(queryId);
queryMetricsTable.put(queryId, queryMetric);
}
return queryMetric;
}
}
// Sent Queries
public void querySentInGroup(ResolverQueryMsg query) {
if (deltaMetrics == null) {
createDeltaMetric();
}
getQueryMetric(query.getQueryId()); // register the query
deltaMetrics.querySentInGroup();
cumulativeMetrics.querySentInGroup();
}
public void querySentViaWalker(ResolverQueryMsg query) {
if (deltaMetrics == null) {
createDeltaMetric();
}
getQueryMetric(query.getQueryId()); // register the query
deltaMetrics.querySentViaWalker();
cumulativeMetrics.querySentViaWalker();
}
public void querySentViaUnicast(String peer, ResolverQueryMsg query) {
if (deltaMetrics == null) {
createDeltaMetric();
}
getQueryMetric(query.getQueryId()); // register the query
deltaMetrics.querySentViaUnicast(peer);
cumulativeMetrics.querySentViaUnicast(peer);
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(peer);
destinationMeter.querySentViaUnicast();
}
public void querySendError() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.querySendError();
cumulativeMetrics.querySendError();
}
public void queryPropagateError() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.queryPropagateError();
cumulativeMetrics.queryPropagateError();
}
public void queryHopCountDropped() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.queryHopCountDropped();
cumulativeMetrics.queryHopCountDropped();
}
public void unableToPropagate() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.unableToPropagate();
cumulativeMetrics.unableToPropagate();
}
// Propagate Query
public void queryPropagatedInGroup() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.queryPropagatedInGroup();
cumulativeMetrics.queryPropagatedInGroup();
}
public void queryPropagatedViaWalker() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.queryPropagatedViaWalker();
cumulativeMetrics.queryPropagatedViaWalker();
}
public void propagationQueryDropped() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.propagationQueryDropped();
cumulativeMetrics.propagationQueryDropped();
}
// Sent Responses
public void responseSentViaUnicast(String peer, ResolverResponseMsg response) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.responseSentViaUnicast();
cumulativeMetrics.responseSentViaUnicast();
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(peer);
destinationMeter.responseSentViaUnicast();
}
public void responseSentViaWalker(ResolverResponseMsg response) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.responseSentViaWalker();
cumulativeMetrics.responseSentViaWalker();
}
public void responseSentInGroup(ResolverResponseMsg response) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.responseSentInGroup();
cumulativeMetrics.responseSentInGroup();
}
public void responseSendError() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.responseSendError();
cumulativeMetrics.responseSendError();
}
public void responsePropagateError() {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.responsePropagateError();
cumulativeMetrics.responsePropagateError();
}
// Received Responses
public void responseProcessed(ResolverResponseMsg response, long processTime, EndpointAddress srcAddr) {
if (deltaMetrics == null) {
createDeltaMetric();
}
QueryMetric queryMetric = getQueryMetric(response.getQueryId());
long now = System.currentTimeMillis();
long responseTime = now - queryMetric.querySentTime;
queryMetric.lastResponseTime = now;
queryMetric.numResponsesReceived++;
deltaMetrics.responseProcessed(responseTime, processTime);
cumulativeMetrics.responseProcessed(responseTime, processTime);
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(srcAddr);
destinationMeter.responseProcessed();
}
public void responseToUnregisteredHandler(EndpointAddress src) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.responseToUnregisteredHandler();
cumulativeMetrics.responseToUnregisteredHandler();
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(src);
destinationMeter.responseToUnregisteredHandler();
}
public void errorWhileProcessingResponse(EndpointAddress srcAddr) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.errorWhileProcessingResponse();
cumulativeMetrics.errorWhileProcessingResponse();
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(srcAddr);
destinationMeter.errorWhileProcessingResponse();
}
// Received Queries
public void queryProcessed(ResolverQueryMsg query, int result, long processTime) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.queryProcessed(result, processTime);
cumulativeMetrics.queryProcessed(result, processTime);
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(query.getSrcPeer().toString());
destinationMeter.queryProcessed();
}
public void queryToUnregisteredHandler(ResolverQueryMsg query) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.queryToUnregisteredHandler();
cumulativeMetrics.queryToUnregisteredHandler();
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(query.getSrcPeer().toString());
destinationMeter.queryToUnregisteredHandler();
}
public void errorWhileProcessingQuery(ResolverQueryMsg query) {
if (deltaMetrics == null) {
createDeltaMetric();
}
deltaMetrics.errorWhileProcessingQuery();
cumulativeMetrics.errorWhileProcessingQuery();
QueryDestinationMeter destinationMeter = getQueryDestinationMeter(query.getSrcPeer().toString());
destinationMeter.errorWhileProcessingQuery();
}
public Enumeration getQueryDestinationMeters() {
return Collections.enumeration(queryDestinationMeters.values());
}
public int getQueryDestinationCount() {
return queryDestinationMeters.size();
}
}