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));
+               }
+       }
+
+}


Reply via email to