Update of /cvsroot/freenet/freenet/src/freenet/node
In directory sc8-pr-cvs1:/tmp/cvs-serv20832/freenet/src/freenet/node

Modified Files:
        LoadStats.java Main.java Node.java 
Log Message:
Make queriesPerHour a time weighted decaying average.
Set lsHalfLifeHours=0 for previous behavior.

Print the local port number together with peer IP
in order to correlate with netstat output, both
in logs and on "Open Connections" servlet.

Version.java 
(Version) buildNumber = 6216

tcpConnection.java   Add import freenet.node.Node;
(tcpConnection.toString)
  Compare sock.getLocalPort to Node.listenport.
  Add import freenet.node.Node;
  If not equal, prepend localPort+">" to IP number of peer.
  If equal, append ">local" to IP number of peer.

Node.java Add new configuration option, lsHalfLifeHours
(Node.static) add description strings, default value 0.5
(Node) static public double lsHalfLifeHours;
(Node.init) lsHalfLifeHours = params.getDouble("lsHalfLifeHours");

Main.java
(Main.main) Pass Node.lsHalfLifeHours to new LoadStats()

LoadStats.java
(LoadStats) new field queriesPerHour
(LoadStats.LoadStats) accept lsHalfLifeHours parameter,
  queriesPerHour = new DecayingTimeWeightedAverage()
  specifying time unit of one hour and half life
  from the parameter.
(receivedQuery) move call to System.currentTimeMillis()
  out of synchronized(timesLock).  Once every times.length
  calls, call localQueryTraffic() to compute average.
(localQueryTraffic) Note current time upon entry.
  Always make an estimate, even when fewer than
  lsAcceptRatioSamples queries have been received.
  Return the decaying time weighted average of
  events per hour, instead of the instanteous value.
(DecayingTimeWeightedAverage) New private class,
  with method average(now, start, events)
  calculates average events per unit time, decaying
  with half-life specified in constructor.  
  If value was A events/hour, and subsequent
  calls submit B events/hour, after one half-life,
  the average will be (A+B)/2, and after two,
  the average will be (A+3B)/2.  Exponential decay.
  Probably should be moved into utilities...

Announcing.java  fixed typo in a comment.

OpenConnectionManager.java
  Change "Connections transferring (Receiving/Transmitting)"
  to "(Transmitting/Receiving)"
  Fix some comments.  Indentation.
  Append ch.getLocalPort() to the inbound/outbound 
  sending/receiving/both indicator.  Should add a new column.


ConnectionHandler.java
(getLocalPort) new method returns conn.getSocket().getLocalPort()
  or zero if any returned null.



Index: LoadStats.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/node/LoadStats.java,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- LoadStats.java      30 Sep 2003 08:02:49 -0000      1.29
+++ LoadStats.java      3 Oct 2003 08:35:20 -0000       1.30
@@ -46,20 +46,22 @@
     private long[] times;
     private int timesPos;
     private int ratio;
-    // The traffic numbers (queries/hour) are calculated from the
-    // time it took for the last ratioSamples queries to arrive.
-    // Also, the acceptedQ/totalQ ratio is calculated from
-    // this number of samples.
-    private final int ratioSamples; // was 100.
-    
+
+    // acceptRatio, the acceptedQ/totalQ ratio, is calculated from
+    // ratioSamples samples.
+    private final int ratioSamples;
+    private DecayingTimeWeightedAverage queriesPerHour;
+
     /**
      * Create a new loadstats object.
      * @param table         The DataStoreObject providing load entries.
-     * @param lsMaxTableSize The maximum number of peers to use for calculating
-     *                      global queries/hour. 
+     * @param lsMaxTableSize The maximum number of peers to use for 
+     *                      calculating global queries/hour. 
      * @param lsAcceptRatioSamples 
-     *                      Number of query fates saved for acceptRatio, and
-     *                      number of query arrival times for queries/hour calc.
+     *                      Number of query fates saved for acceptRatio.
+     * @param lsHalfLifeHours The half life in hours of the time
+     *                      weighted decaying average used to
+     *                      calculate queries/hour.
      * @param diag          The node's diagnostics object. A category named
      *                      "Network Load" will be added with the following
      *                      fields:
@@ -75,6 +77,7 @@
     public LoadStats(DataObjectStore table, 
                     int lsMaxTableSize, 
                     int lsAcceptRatioSamples,
+                    double lsHalfLifeHours,
                      Diagnostics diag,
                      DiagnosticsCategory parent, 
                     double defaultResetProbability) throws IOException {
@@ -86,7 +89,12 @@
 
         this.times = new long[ratioSamples];
         this.timesPos = 0;
-        this.ratio = ratioSamples;
+        this.ratio = ratioSamples; // acceptRatio starts at 1.0.
+
+       // Average queries per hour with a half life as specified.
+       // 3600 * 1000 is an hour in milliseconds.
+       this.queriesPerHour = 
+           new DecayingTimeWeightedAverage(lsHalfLifeHours, 3600 * 1000);
 
         for (Enumeration e = table.keys(true) ; e.hasMoreElements(); ) {
             LoadEntry le = getLoadEntry((FileNumber) e.nextElement());
@@ -129,18 +137,24 @@
      * @boolean  Whether the query was initially accepted by the node.
      **/
     public final void receivedQuery(boolean accepted) {
+       long time = System.currentTimeMillis() * (accepted ? 1 : -1);
+       boolean averageIt = false;
         diag.occurrenceBinomial("localQueryTraffic", 1,  accepted ? 1 : 0);
 
         synchronized(timesLock) {
             if (times[timesPos] >= 0) // note =, since we start with 1
                 ratio--;
 
-            times[timesPos] = System.currentTimeMillis() * (accepted ? 1 : -1);
+            times[timesPos] = time;
             timesPos = (timesPos + 1) % times.length;
+           averageIt = timesPos == 0;
 
             if (accepted)
                 ratio++;
         }
+       if (averageIt) {
+           localQueryTraffic();
+       }
     }
 
 
@@ -187,7 +201,7 @@
         }
     }
     
-    boolean insufficientData = true;
+    private boolean insufficientData = true;
     
     /**
      * @return The number of outbound requests per hour made from
@@ -195,24 +209,142 @@
      */
     public final double localQueryTraffic() {
         long time;
+       long now = System.currentTimeMillis();
+       int events = times.length;
         synchronized(timesLock) {
             time = times[timesPos];
+           if (time == 0) {
+               time = times[0];
+               events = timesPos;
+           }
         }
-        if (time == 0)
-            return 0;
         if (time < 0)
             time = time * -1;
 
-        // second millisecond  query
-        // ------ ----------- --------
-        //  hour    second    interval     query
-        // --------------------------- ==> -----
-        //         millisecond             hour
-        //         -----------
-        //          interval
-
-        return (3600.0 * 1000 * ratioSamples) / 
-            ((double) (System.currentTimeMillis() - time));
+       return queriesPerHour.average(now, time, events);
+    }
+    
+    /**
+     *  Class to maintain a decaying time weighted average of events
+     *  per unit time.  If the value was a at time t = t0, and
+     *  subsequently values of b are submitted, then the value will
+     *  decay to (a+b)/2 at time t = t0 + halfLife.  Since exp(a+b) =
+     *  exp(a)exp(b), it follows that this is true regardless of
+     *  whether a single call is made at time t0 + halfLife, or if any
+     *  number of calls are made during the interval, provided that
+     *  the events per unit time provided was always b.
+     *  @author ejhuff
+     */
+ 
+    // An example of how the sums and products collapse:
+ 
+    // In[15]:= ??da
+    // Global`da
+ 
+    // da[0] = a
+  
+    // da[n_] := da[n - 1]*Exp[coef*dt] + (1 - Exp[coef*dt])*b
+ 
+    // In[16]:= da[1]
+ 
+    //             coef dt           coef dt
+    // Out[16]= a E        + b (1 - E       )
+ 
+    // In[17]:= da[2]
+ 
+    //                  coef dt     coef dt     coef dt           coef dt
+    // Out[17]= b (1 - E       ) + E        (a E        + b (1 - E       ))
+ 
+    // In[18]:= da[2]//Simplify
+ 
+    //                 2 coef dt      2 coef dt
+    // Out[18]= b + a E          - b E
+ 
+    // In[19]:= da[3]
+ 
+    //                  coef dt     coef dt
+    // Out[19]= b (1 - E       ) + E
+  
+    //                coef dt     coef dt     coef dt           coef dt
+    // >     (b (1 - E       ) + E        (a E        + b (1 - E       )))
+ 
+    // In[20]:= da[3]//Simplify
+ 
+    //                 3 coef dt      3 coef dt
+    // Out[20]= b + a E          - b E
+ 
+ 
+    // In[22]:= da[20]//Simplify
+ 
+    //                 20 coef dt      20 coef dt
+    // Out[22]= b + a E           - b E
+ 
+    private class DecayingTimeWeightedAverage {
+       private final double unitOfTime;
+       private final double coef; // -log(2) * (half life in milliseconds)
+       private double decayingAverage = 0.0;
+       private long then = 0; // first time through, decay will be near zero.
+
+       /**
+        *  Create a new DecayingTimeWeightedAverage object.
+        *  @param halfLife     halfLife as a fraction of a time unit.
+        *  @param unitOfTime   The number of milliseconds in a time
+        *                      unit.
+        */
+
+       DecayingTimeWeightedAverage(double halfLife, long unitOfTime) {
+           this.coef = -halfLife * unitOfTime * Math.log(2.0);
+           this.unitOfTime = (double) unitOfTime; // milliseconds.
+       }
+       
+       /**
+        *  Calculate the decaying time weighted average given the
+        *  present time, the time when the last interval started, and
+        *  the number of events which occurred during that interval.
+        *  Any subsequent calls that specify current time earlier
+        *  than this call will be ignored.
+        *  @param now      A recent value of System.currentTimeMillis()
+        *  @param start    Time of start of interval, millis.
+        *  @param events   Number of events which occurred during the
+        *                  interval.
+        *  @return         Average events / unit time, decaying with
+        *                  the half-life specifed to the constructor.
+        */
+
+       synchronized double average(long now, long start, int events) {
+
+           //      millisecond  event
+           //      ----------- --------
+           //       unitTime   interval        event
+           //     ----------------------- ==> --------
+           //           millisecond           unitTime
+           //           -----------
+           //            interval
+           
+           double dt = (double)(now - start); // dt in ms / interval
+           double eventPerUnitTime = (unitOfTime * (double)events) / dt;
+
+           // Calculate a time weighted decaying average
+           // with half-life of halfLife milliseconds. 
+           // decay 0 would mean it never decays.
+           // 0 < decay < 0.5 if dt < halfLife.
+           // decay == 0.5 if dt == halfLife.
+           // 0.5 < decay < 1 if dt > halfLife.
+           // decay 1 means it decays instantly (halfLife zero).
+           if (now > then) {
+               // This is a different time interval than above.
+               // It is milliseconds since last calculation,
+               // not milliseconds in the interval during which
+               // <code> events </code> events occurred.
+               dt = (double)(now - then); // dt > 0, coef < 0
+               double decay = Math.exp(coef / dt); // 0 < decay < 1
+               decayingAverage = 
+                   (1 - decay) * decayingAverage +
+                   decay * eventPerUnitTime;
+               then = now;
+           }
+           return decayingAverage;
+       }
     }
 
     /**

Index: Main.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/node/Main.java,v
retrieving revision 1.262
retrieving revision 1.263
diff -u -r1.262 -r1.263
--- Main.java   30 Sep 2003 08:02:49 -0000      1.262
+++ Main.java   3 Oct 2003 08:35:20 -0000       1.263
@@ -840,6 +840,7 @@
            
             LoadStats loadStats = new LoadStats(lsNodes, Node.lsMaxTableSize,
                                                                                       
         Node.lsAcceptRatioSamples,
+                                                                                      
         Node.lsHalfLifeHours,
                                                                                       
         Core.diagnostics,
                                                 null, 
                                                                                       
         Node.defaultResetProbability);

Index: Node.java
===================================================================
RCS file: /cvsroot/freenet/freenet/src/freenet/node/Node.java,v
retrieving revision 1.212
retrieving revision 1.213
diff -u -r1.212 -r1.213
--- Node.java   30 Sep 2003 08:02:50 -0000      1.212
+++ Node.java   3 Oct 2003 08:35:20 -0000       1.213
@@ -223,6 +223,7 @@
        config.addOption("defaultResetProbability", 1, 0.05, 3557);
        config.addOption("lsMaxTableSize", 1, 100, 3558);
        config.addOption("lsAcceptRatioSamples", 1, 500, 3559);
+       config.addOption("lsHalfLifeHours", 1, 0.1, 3560);
 
        // Forward Error Correction (FEC) options
        config.addOption("FECTempDir", 1, "", 3600);
@@ -1201,7 +1202,13 @@
        config.setExpert ("lsAcceptRatioSamples", true);
        config.argDesc   ("lsAcceptRatioSamples", "<positive integer>");
        config.shortDesc ("lsAcceptRatioSamples", "Number of query arrival time and 
accepted/rejected status entries.");
-       config.longDesc  ("lsAcceptRatioSamples", "LoadStats: Current proportion of 
requests being accepted is calculated from the fate of this number of recent requests. 
 The local queries/hour is calculated from the time it took for this number of queries 
to arrive.");
+       config.longDesc  ("lsAcceptRatioSamples", "LoadStats: Current proportion of 
requests being accepted is calculated from the fate of this number of recent requests. 
 The local queries/hour is calculated from the time it took for this number of queries 
to arrive, averaged at least every time this number of queries is received.");
+
+       // lsHalfLifeHours
+       config.setExpert ("lsHalfLifeHours", true);
+       config.argDesc   ("lsHalfLifeHours", "<positive real>");
+       config.shortDesc ("lsHalfLifeHours", "Half life in hours of the queries per 
hour decaying average.");
+       config.longDesc  ("lsHalfLifeHours", "Half life in hours of the queries per 
hour decaying average.  Small values permit the value to change rapidly; large values 
force it to change slowly.  Use zero to get prior behavior.");
 
         // logOutboundContacts
         config.setExpert ("logOutboundContacts",true);
@@ -1759,6 +1766,7 @@
     static public double defaultResetProbability;
     static public int lsMaxTableSize;
     static public int lsAcceptRatioSamples;
+    static public double lsHalfLifeHours;
     static public boolean doOutLimitCutoff;
     static public boolean doOutLimitConnectCutoff;
     static public float outLimitCutoff;
@@ -2089,6 +2097,7 @@
        defaultResetProbability = params.getDouble("defaultResetProbability");
        lsMaxTableSize = params.getInt("lsMaxTableSize");
        lsAcceptRatioSamples = params.getInt("lsAcceptRatioSamples");
+       lsHalfLifeHours = params.getDouble("lsHalfLifeHours");
        doOutLimitCutoff = params.getBoolean("doOutLimitCutoff");
        outLimitCutoff = params.getFloat("outLimitCutoff");
        doOutLimitConnectCutoff = params.getBoolean("doOutLimitConnectCutoff");

_______________________________________________
cvs mailing list
[EMAIL PROTECTED]
http://dodo.freenetproject.org/cgi-bin/mailman/listinfo/cvs

Reply via email to