/*
* Created on 18-Jan-2005
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package com.aelitis.azureus.core.dht.transport.util;
import java.net.InetSocketAddress;
import java.util.Arrays;
import org.gudy.azureus2.core3.util.SystemTime;
import com.aelitis.azureus.core.dht.impl.DHTLog;
import com.aelitis.azureus.core.dht.transport.DHTTransportStats;
import com.aelitis.azureus.core.dht.transport.udp.impl.DHTUDPPacketHelper;
import com.aelitis.azureus.core.dht.transport.udp.impl.DHTUDPPacketRequest;
import com.aelitis.azureus.core.util.bloom.BloomFilter;
import com.aelitis.azureus.core.util.bloom.BloomFilterFactory;
/**
* @author parg
*
*/
public abstract class
DHTTransportStatsImpl
implements DHTTransportStats
{
private byte protocol_version;
private long[] pings = new long[4];
private long[] find_nodes = new long[4];
private long[] find_values = new long[4];
private long[] stores = new long[4];
private long[] stats = new long[4];
private long[] data = new long[4];
private long[] key_blocks = new long[4];
private long[] store_queries = new long[4];
private long[] aliens = new long[7];
private long incoming_requests;
private long outgoing_requests;
private long incoming_version_requests;
private long[] incoming_request_versions;
private long outgoing_version_requests;
private long[] outgoing_request_versions;
private static final int SKEW_VALUE_MAX = 256;
private final int[] skew_values = new int[SKEW_VALUE_MAX];
private int skew_pos = 0;
private long last_skew_average;
private long last_skew_average_time;
private BloomFilter skew_originator_bloom =
BloomFilterFactory.createRotating(
BloomFilterFactory.createAddOnly( SKEW_VALUE_MAX*4 ),
2 );
protected
DHTTransportStatsImpl(
byte _protocol_version )
{
protocol_version = _protocol_version;
incoming_request_versions = new long[protocol_version+1];
outgoing_request_versions = new long[protocol_version+1];
Arrays.fill( skew_values, Integer.MAX_VALUE );
}
protected byte
getProtocolVersion()
{
return( protocol_version );
}
public void
add(
DHTTransportStatsImpl other )
{
add( pings, other.pings );
add( find_nodes, other.find_nodes );
add( find_values, other.find_values );
add( stores, other.stores );
add( stats, other.stats );
add( data, other.data );
add( key_blocks, other.key_blocks );
add( store_queries, other.store_queries );
add( aliens, other.aliens );
incoming_requests += other.incoming_requests;
outgoing_requests += other.outgoing_requests;
}
protected void
add(
long[] a,
long[] b )
{
for (int i=0;i<a.length;i++){
a[i] += b[i];
}
}
protected void
snapshotSupport(
DHTTransportStatsImpl clone )
{
clone.pings = (long[])pings.clone();
clone.find_nodes = (long[])find_nodes.clone();
clone.find_values = (long[])find_values.clone();
clone.stores = (long[])stores.clone();
clone.data = (long[])data.clone();
clone.key_blocks = (long[])key_blocks.clone();
clone.store_queries = (long[])store_queries.clone();
clone.aliens = (long[])aliens.clone();
clone.incoming_requests = incoming_requests;
clone.outgoing_requests = outgoing_requests;
}
// ping
public void
pingSent(
DHTUDPPacketRequest request )
{
pings[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
pingOK()
{
pings[STAT_OK]++;
}
public void
pingFailed()
{
pings[STAT_FAILED]++;
}
public void
pingReceived()
{
pings[STAT_RECEIVED]++;
}
public long[]
getPings()
{
return( pings );
}
// key blocks
public void
keyBlockSent(
DHTUDPPacketRequest request )
{
key_blocks[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
keyBlockOK()
{
key_blocks[STAT_OK]++;
}
public void
keyBlockFailed()
{
key_blocks[STAT_FAILED]++;
}
public void
keyBlockReceived()
{
key_blocks[STAT_RECEIVED]++;
}
public long[]
getKeyBlocks()
{
return( key_blocks );
}
// store queries
public void
queryStoreSent(
DHTUDPPacketRequest request )
{
store_queries[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
queryStoreOK()
{
store_queries[STAT_OK]++;
}
public void
queryStoreFailed()
{
store_queries[STAT_FAILED]++;
}
public void
queryStoreReceived()
{
store_queries[STAT_RECEIVED]++;
}
public long[]
getQueryStores()
{
return( store_queries );
}
// find node
public void
findNodeSent(
DHTUDPPacketRequest request )
{
find_nodes[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
findNodeOK()
{
find_nodes[STAT_OK]++;
}
public void
findNodeFailed()
{
find_nodes[STAT_FAILED]++;
}
public void
findNodeReceived()
{
find_nodes[STAT_RECEIVED]++;
}
public long[]
getFindNodes()
{
return( find_nodes );
}
// find value
public void
findValueSent(
DHTUDPPacketRequest request )
{
find_values[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
findValueOK()
{
find_values[STAT_OK]++;
}
public void
findValueFailed()
{
find_values[STAT_FAILED]++;
}
public void
findValueReceived()
{
find_values[STAT_RECEIVED]++;
}
public long[]
getFindValues()
{
return( find_values );
}
// store
public void
storeSent(
DHTUDPPacketRequest request )
{
stores[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
storeOK()
{
stores[STAT_OK]++;
}
public void
storeFailed()
{
stores[STAT_FAILED]++;
}
public void
storeReceived()
{
stores[STAT_RECEIVED]++;
}
public long[]
getStores()
{
return( stores );
}
//stats
public void
statsSent(
DHTUDPPacketRequest request )
{
stats[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
statsOK()
{
stats[STAT_OK]++;
}
public void
statsFailed()
{
stats[STAT_FAILED]++;
}
public void
statsReceived()
{
stats[STAT_RECEIVED]++;
}
//data
public void
dataSent(
DHTUDPPacketRequest request )
{
data[STAT_SENT]++;
outgoingRequestSent( request );
}
public void
dataOK()
{
data[STAT_OK]++;
}
public void
dataFailed()
{
data[STAT_FAILED]++;
}
public void
dataReceived()
{
data[STAT_RECEIVED]++;
}
public long[]
getData()
{
return( data );
}
protected void
outgoingRequestSent(
DHTUDPPacketRequest request )
{
outgoing_requests++;
if ( DHTLog.TRACE_VERSIONS ){
byte protocol_version = request.getProtocolVersion();
if ( protocol_version >= 0 && protocol_version < outgoing_request_versions.length ){
outgoing_request_versions[ protocol_version ]++;
outgoing_version_requests++;
if ( outgoing_version_requests%100 == 0 ){
String str= "";
for (int i=0;i<outgoing_request_versions.length;i++){
long count = outgoing_request_versions[i];
if ( count > 0 ){
str += (str.length()==0?"":", ") + i + "=" + count + "[" +
((outgoing_request_versions[i]*100)/outgoing_version_requests) + "]";
}
}
System.out.println( "net " + request.getTransport().getNetwork() + ": Outgoing versions: tot = " + outgoing_requests +"/" + outgoing_version_requests + ": " + str );
}
if ( outgoing_version_requests%1000 == 0 ){
for (int i=0;i<outgoing_request_versions.length;i++){
outgoing_request_versions[i] = 0;
}
outgoing_version_requests = 0;
}
}
}
}
public void
incomingRequestReceived(
DHTUDPPacketRequest request,
boolean alien )
{
incoming_requests++;
if ( alien ){
// System.out.println( "Alien on net " + request.getNetwork() + " - sender=" + request.getAddress());
int type = request.getAction();
if ( type == DHTUDPPacketHelper.ACT_REQUEST_FIND_NODE ){
aliens[AT_FIND_NODE]++;
}else if ( type == DHTUDPPacketHelper.ACT_REQUEST_FIND_VALUE ){
aliens[AT_FIND_VALUE]++;
}else if ( type == DHTUDPPacketHelper.ACT_REQUEST_PING ){
aliens[AT_PING]++;
}else if ( type == DHTUDPPacketHelper.ACT_REQUEST_STATS ){
aliens[AT_STATS]++;
}else if ( type == DHTUDPPacketHelper.ACT_REQUEST_STORE ){
aliens[AT_STORE]++;
}else if ( type == DHTUDPPacketHelper.ACT_REQUEST_KEY_BLOCK ){
aliens[AT_KEY_BLOCK]++;
}else if ( type == DHTUDPPacketHelper.ACT_REQUEST_QUERY_STORE ){
aliens[AT_QUERY_STORE]++;
}
}
if ( DHTLog.TRACE_VERSIONS ){
byte protocol_version = request.getProtocolVersion();
if ( protocol_version >= 0 && protocol_version < incoming_request_versions.length ){
incoming_request_versions[ protocol_version ]++;
incoming_version_requests++;
if ( incoming_version_requests%100 == 0 ){
String str= "";
for (int i=0;i<incoming_request_versions.length;i++){
long count = incoming_request_versions[i];
if ( count > 0 ){
str += (str.length()==0?"":", ") + i + "=" + count + "[" +
((incoming_request_versions[i]*100)/incoming_version_requests) + "]";
}
}
System.out.println( "net " + request.getTransport().getNetwork() + ": Incoming versions: tot = " + incoming_requests +"/" + incoming_version_requests + ": " + str );
}
if ( incoming_version_requests%1000 == 0 ){
for (int i=0;i<incoming_request_versions.length;i++){
incoming_request_versions[i] = 0;
}
incoming_version_requests = 0;
}
}
}
}
public long[]
getAliens()
{
return( aliens );
}
public long
getIncomingRequests()
{
return( incoming_requests );
}
public void
recordSkew(
InetSocketAddress originator_address,
long skew )
{
byte[] bytes = originator_address.getAddress().getAddress();
if ( skew_originator_bloom.contains( bytes)){
//System.out.println( "skipping skew: " + originator_address );
return;
}
skew_originator_bloom.add( bytes );
//System.out.println( "adding skew: " + originator_address + "/" + skew );
int i_skew = skew<Integer.MAX_VALUE?(int)skew:(Integer.MAX_VALUE-1);
// no sync here as not important so ensure things work ok
int pos = skew_pos;
skew_values[ pos++ ] = i_skew;
if ( pos == SKEW_VALUE_MAX ){
pos = 0;
}
skew_pos = pos;
}
public long
getSkewAverage()
{
long now = SystemTime.getCurrentTime();
if ( now < last_skew_average_time ||
now - last_skew_average_time > 30000 ){
int[] values = (int[])skew_values.clone();
int pos = skew_pos;
int num_values;
if ( values[pos] == Integer.MAX_VALUE ){
num_values = pos;
}else{
num_values = SKEW_VALUE_MAX;
}
Arrays.sort( values, 0, num_values );
// remove outliers
int start = num_values/3;
int end = 2*num_values/3;
int entries = end - start;
if ( entries < 5 ){
last_skew_average = 0;
}else{
long total = 0;
for (int i=start;i<end;i++){
total += (long)values[i];
}
last_skew_average = total / entries;
}
last_skew_average_time = now;
}
return( last_skew_average );
}
public String
getString()
{
return( "ping:" + getString( pings ) + "," +
"store:" + getString( stores ) + "," +
"node:" + getString( find_nodes ) + "," +
"value:" + getString( find_values ) + "," +
"stats:" + getString( stats ) + "," +
"data:" + getString( data ) + "," +
"kb:" + getString( key_blocks ) + "," +
"incoming:" + incoming_requests +"," +
"alien:" + getString( aliens ));
}
protected String
getString(
long[] x )
{
String str = "";
for (int i=0;i<x.length;i++){
str += (i==0?"":",") + x[i];
}
return( str );
}
}