Author: toad
Date: 2007-04-13 19:23:53 +0000 (Fri, 13 Apr 2007)
New Revision: 12653
Added:
trunk/freenet/src/freenet/support/StringCounter.java
Modified:
trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java
trunk/freenet/src/freenet/node/NodeStats.java
Log:
Show reasons for rejecting requests and count of occurrences for each reason on
the stats page
Modified: trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java
2007-04-13 19:08:12 UTC (rev 12652)
+++ trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java
2007-04-13 19:23:53 UTC (rev 12653)
@@ -279,13 +279,24 @@
HTMLNode nodeCircleInfobox =
nextTableCell.addChild("div", "class", "infobox");
nodeCircleInfobox.addChild("div", "class",
"infobox-header", "Node\u00a0Location\u00a0Distribution (w/Swap\u00a0Age)");
HTMLNode nodeCircleTable =
nodeCircleInfobox.addChild("table");
- addNodeCircle(nodeCircleTable);
+ addNodeCircle(nodeCircleTable);
+
+ // rejection reasons box
+ HTMLNode rejectReasonsInfobox =
nextTableCell.addChild("div", "class", "infobox");
+ drawRejectReasonsBox(rejectReasonsInfobox);
+
}
}
this.writeReply(ctx, 200, "text/html", "OK",
pageNode.generate());
}
+ private void drawRejectReasonsBox(HTMLNode rejectReasonsInfobox) {
+ rejectReasonsInfobox.addChild("div", "class", "infobox-header",
"Preemptive Rejection Reasons");
+ HTMLNode table = rejectReasonsInfobox.addChild("table");
+ node.nodeStats.getRejectReasonsTable(table);
+ }
+
private void drawNodeVersionBox(HTMLNode versionInfobox) {
versionInfobox.addChild("div", "class", "infobox-header", "Node
Version Information");
Modified: trunk/freenet/src/freenet/node/NodeStats.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeStats.java 2007-04-13 19:08:12 UTC
(rev 12652)
+++ trunk/freenet/src/freenet/node/NodeStats.java 2007-04-13 19:23:53 UTC
(rev 12653)
@@ -11,9 +11,11 @@
import freenet.io.comm.DMT;
import freenet.io.comm.IOStatisticCollector;
import freenet.node.Node.NodeInitException;
+import freenet.support.HTMLNode;
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
import freenet.support.SizeUtil;
+import freenet.support.StringCounter;
import freenet.support.TimeUtil;
import freenet.support.TokenBucket;
import freenet.support.api.BooleanCallback;
@@ -102,7 +104,7 @@
final TimeDecayingRunningAverage successfulSskFetchBytesReceivedAverage;
final TimeDecayingRunningAverage
successfulChkInsertBytesReceivedAverage;
final TimeDecayingRunningAverage
successfulSskInsertBytesReceivedAverage;
-
+
File persistTarget;
File persistTemp;
private long previous_input_stat;
@@ -136,6 +138,8 @@
private int freeHeapPercentThreshold;
final NodePinger nodePinger;
+
+ final StringCounter preemptiveRejectReasons;
// Enable this if you run into hard to debug OOMs.
// Disabled to prevent long pauses every 30 seconds.
@@ -152,6 +156,7 @@
this.node = node;
this.peers = node.peers;
this.hardRandom = node.random;
+ preemptiveRejectReasons = new StringCounter();
pInstantRejectIncoming = new TimeDecayingRunningAverage(0,
60000, 0.0, 1.0);
ThreadGroup tg = Thread.currentThread().getThreadGroup();
while(tg.getParent() != null) tg = tg.getParent();
@@ -306,8 +311,10 @@
if(logMINOR) dumpByteCostAverages();
int threadCount = getActiveThreadCount();
- if(threadLimit < threadCount)
+ if(threadLimit < threadCount) {
+ preemptiveRejectReasons.inc(">threadLimit");
return ">threadLimit ("+threadCount+'/'+threadLimit+')';
+ }
double bwlimitDelayTime =
throttledPacketSendAverage.currentValue();
@@ -342,12 +349,14 @@
if(logMINOR) Logger.minor(this,
"Accepting request anyway (take one every 10 secs to keep bwlimitDelayTime
updated)");
} else {
pInstantRejectIncoming.report(1.0);
+
preemptiveRejectReasons.inc(">MAX_PING_TIME");
return ">MAX_PING_TIME
("+TimeUtil.formatTime((long)pingTime, 2, true)+ ')';
}
} else if(pingTime > SUB_MAX_PING_TIME) {
double x = ((double)(pingTime -
SUB_MAX_PING_TIME)) / (MAX_PING_TIME - SUB_MAX_PING_TIME);
if(hardRandom.nextDouble() < x) {
pInstantRejectIncoming.report(1.0);
+
preemptiveRejectReasons.inc(">SUB_MAX_PING_TIME");
return ">SUB_MAX_PING_TIME
("+TimeUtil.formatTime((long)pingTime, 2, true)+ ')';
}
}
@@ -358,12 +367,14 @@
if(logMINOR) Logger.minor(this,
"Accepting request anyway (take one every 10 secs to keep bwlimitDelayTime
updated)");
} else {
pInstantRejectIncoming.report(1.0);
+
preemptiveRejectReasons.inc(">MAX_THROTTLE_DELAY");
return ">MAX_THROTTLE_DELAY
("+TimeUtil.formatTime((long)bwlimitDelayTime, 2, true)+ ')';
}
} else if(bwlimitDelayTime > SUB_MAX_THROTTLE_DELAY) {
double x = ((double)(bwlimitDelayTime -
SUB_MAX_THROTTLE_DELAY)) / (MAX_THROTTLE_DELAY - SUB_MAX_THROTTLE_DELAY);
if(hardRandom.nextDouble() < x) {
pInstantRejectIncoming.report(1.0);
+
preemptiveRejectReasons.inc(">SUB_MAX_THROTTLE_DELAY");
return ">SUB_MAX_THROTTLE_DELAY
("+TimeUtil.formatTime((long)bwlimitDelayTime, 2, true)+ ')';
}
}
@@ -381,8 +392,10 @@
bandwidthLiabilityOutput += getSuccessfulBytes(isSSK, isInsert,
false).currentValue();
double bandwidthAvailableOutput =
node.getOutputBandwidthLimit() * 90; // 90 seconds at
full power; we have to leave some time for the search as well
- if(bandwidthLiabilityOutput > bandwidthAvailableOutput)
+ if(bandwidthLiabilityOutput > bandwidthAvailableOutput) {
+ preemptiveRejectReasons.inc("Output bandwidth
liability");
return "Output bandwidth liability";
+ }
double bandwidthLiabilityInput =
successfulChkFetchBytesReceivedAverage.currentValue() *
node.getNumCHKRequests() +
@@ -392,8 +405,10 @@
bandwidthLiabilityInput += getSuccessfulBytes(isSSK, isInsert,
true).currentValue();
double bandwidthAvailableInput =
node.getInputBandwidthLimit() * 90; // 90 seconds at
full power
- if(bandwidthLiabilityInput > bandwidthAvailableInput)
+ if(bandwidthLiabilityInput > bandwidthAvailableInput) {
+ preemptiveRejectReasons.inc("Input bandwidth
liability");
return "Input bandwidth liability";
+ }
// Do we have the bandwidth?
@@ -403,6 +418,7 @@
int expectedSent = (int)Math.max(expected, 0);
if(!requestOutputThrottle.instantGrab(expectedSent)) {
pInstantRejectIncoming.report(1.0);
+ preemptiveRejectReasons.inc("Insufficient output
bandwidth");
return "Insufficient output bandwidth";
}
expected =
@@ -412,6 +428,7 @@
if(!requestInputThrottle.instantGrab(expectedReceived)) {
requestOutputThrottle.recycle(expectedSent);
pInstantRejectIncoming.report(1.0);
+ preemptiveRejectReasons.inc("Insufficient input
bandwidth");
return "Insufficient input bandwidth";
}
@@ -424,6 +441,7 @@
}
if(freeHeapMemory < freeHeapBytesThreshold) {
pInstantRejectIncoming.report(1.0);
+ preemptiveRejectReasons.inc("<freeHeapBytesThreshold");
return "<freeHeapBytesThreshold
("+SizeUtil.formatSize(freeHeapMemory, false)+" of
"+SizeUtil.formatSize(maxHeapMemory, false)+')';
}
double percentFreeHeapMemoryOfMax = ((double) freeHeapMemory) /
((double) maxHeapMemory);
@@ -431,6 +449,7 @@
if(percentFreeHeapMemoryOfMax < freeHeapPercentThresholdDouble)
{
pInstantRejectIncoming.report(1.0);
DecimalFormat fix3p1pct = new DecimalFormat("##0.0%");
+
preemptiveRejectReasons.inc("<freeHeapPercentThreshold");
return "<freeHeapPercentThreshold
("+SizeUtil.formatSize(freeHeapMemory, false)+" of
"+SizeUtil.formatSize(maxHeapMemory, false)+"
("+fix3p1pct.format(percentFreeHeapMemoryOfMax)+"))";
}
@@ -844,6 +863,9 @@
public boolean isTestnetEnabled() {
return node.isTestnetEnabled();
}
-
+ public void getRejectReasonsTable(HTMLNode table) {
+ preemptiveRejectReasons.toTableRows(table);
+ }
+
}
Added: trunk/freenet/src/freenet/support/StringCounter.java
===================================================================
--- trunk/freenet/src/freenet/support/StringCounter.java
(rev 0)
+++ trunk/freenet/src/freenet/support/StringCounter.java 2007-04-13
19:23:53 UTC (rev 12653)
@@ -0,0 +1,90 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.support;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+
+/**
+ * A set of strings each with a counter associated with each.
+ * @author toad
+ */
+public class StringCounter {
+
+ private HashMap map;
+
+ private class Item {
+ public Item(String string2) {
+ this.string = string2;
+ }
+ final String string;
+ int counter;
+ }
+
+ public StringCounter() {
+ map = new HashMap();
+ }
+
+ public synchronized void inc(String string) {
+ Item item = (Item) map.get(string);
+ if(item == null) {
+ item = new Item(string);
+ item.counter = 1;
+ map.put(string, item);
+ } else
+ item.counter++;
+ }
+
+ public int get(String string) {
+ Item item = (Item) map.get(string);
+ if(item == null) return 0;
+ return item.counter;
+ }
+
+ private synchronized Item[] items() {
+ return (Item[]) map.values().toArray(new Item[map.size()]);
+ }
+
+ private synchronized Item[] sortedItems(final boolean ascending) {
+ Item[] items = items();
+ Arrays.sort(items, new Comparator() {
+ public int compare(Object arg0, Object arg1) {
+ Item it0 = (Item)arg0;
+ Item it1 = (Item)arg1;
+ int ret;
+ if(it0.counter > it1.counter) ret = 1;
+ else if(it0.counter < it1.counter) ret = -1;
+ else ret = it0.string.compareTo(it1.string);
+ if(!ascending) ret = -ret;
+ return ret;
+ }
+ });
+ return items;
+ }
+
+ public String toLongString() {
+ Item[] items = sortedItems(false);
+ StringBuffer sb = new StringBuffer();
+ for(int i=0;i<items.length;i++) {
+ if(i!=0) sb.append('\n');
+ Item it = items[i];
+ sb.append(it.string);
+ sb.append('\t');
+ sb.append(it.counter);
+ }
+ return sb.toString();
+ }
+
+ public void toTableRows(HTMLNode table) {
+ Item[] items = sortedItems(false);
+ for(int i=0;i<items.length;i++) {
+ Item it = items[i];
+ HTMLNode row = table.addChild("tr");
+ row.addChild("td", it.string);
+ row.addChild("td", Integer.toString(it.counter));
+ }
+ }
+
+}