Author: toad
Date: 2008-04-11 17:40:12 +0000 (Fri, 11 Apr 2008)
New Revision: 19191

Added:
   trunk/freenet/src/freenet/node/UptimeEstimator.java
Modified:
   trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java
   trunk/freenet/src/freenet/node/Node.java
Log:
UptimeEstimator: calculate what percentage of the last 48 hours we were online 
during.
Creates two files to which time-since-epoch-in-5-minute-increments is written.

Modified: trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java       
2008-04-11 17:36:47 UTC (rev 19190)
+++ trunk/freenet/src/freenet/clients/http/StatisticsToadlet.java       
2008-04-11 17:40:12 UTC (rev 19191)
@@ -951,6 +951,7 @@
                overviewList.addChild("li", "backedOffPercent:\u00a0" + 
fix3p1pct.format(backedOffPercent));
                overviewList.addChild("li", "pInstantReject:\u00a0" + 
fix3p1pct.format(stats.pRejectIncomingInstantly()));
                overviewList.addChild("li", "unclaimedFIFOSize:\u00a0" + 
node.getUnclaimedFIFOSize());
+               overviewList.addChild("li", "uptimeAverage:\u00a0" + 
fix3p1pct.format(node.uptime.getUptime()));

        }


Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2008-04-11 17:36:47 UTC (rev 
19190)
+++ trunk/freenet/src/freenet/node/Node.java    2008-04-11 17:40:12 UTC (rev 
19191)
@@ -392,6 +392,7 @@
        public final PacketSender ps;
        final DNSRequester dnsr;
        final NodeDispatcher dispatcher;
+       public final UptimeEstimator uptime;
        static final int MAX_MEMORY_CACHED_PUBKEYS = 1000;
        final LRUHashtable cachedPubKeys;
        final boolean testnetEnabled;
@@ -682,7 +683,7 @@
                        String msg = "Could not find or create datastore 
directory";
                        throw new 
NodeInitException(NodeInitException.EXIT_BAD_NODE_DIR, msg);
                }
-
+               
                // Boot ID
                bootID = random.nextLong();
                // Fixed length file containing boot ID. Accessed with random 
access file. So hopefully it will always be
@@ -1006,6 +1007,8 @@
                peers.writePeers();
                peers.updatePMUserAlert();

+               uptime = new UptimeEstimator(nodeDir, ps, 
darknetCrypto.identityHash);
+               
                // ULPRs

                failureTable = new FailureTable(this);

Added: trunk/freenet/src/freenet/node/UptimeEstimator.java
===================================================================
--- trunk/freenet/src/freenet/node/UptimeEstimator.java                         
(rev 0)
+++ trunk/freenet/src/freenet/node/UptimeEstimator.java 2008-04-11 17:40:12 UTC 
(rev 19191)
@@ -0,0 +1,138 @@
+/* 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.node;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import freenet.support.Fields;
+import freenet.support.Logger;
+import freenet.support.io.Closer;
+
+/**
+ * A class to estimate the node's average uptime. Every 5 minutes (with a 
fixed offset), we write
+ * an integer (the number of minutes since the epoch) to the end of a file. We 
rotate it when it
+ * gets huge. We read it to figure out how many of the 5 minute slots in the 
last X period are occupied.
+ * @author toad
+ */
+public class UptimeEstimator implements Runnable {
+       
+       Ticker ticker;
+       
+       /** For each 5 minute slot in the last 48 hours, were we online? */
+       private boolean[] wasOnline = new boolean[48*24*12];
+       
+       /** Which slot are we up to? We rotate around the array. Slots before 
us are before us,
+        * slots after us are also before us (it wraps around). */
+       private int slot;
+       
+       /** The file we are writing to */
+       private File logFile;
+       
+       /** The previous file. We have read this. When logFile reaches 48 
hours, we dump the prevFile,
+        * move the logFile over it, and write to a new logFile.
+        */
+       private File prevFile;
+       
+       /** We write to disk every 5 minutes. The offset is derived from the 
node's identity. */
+       private long timeOffset;
+
+       public UptimeEstimator(File nodeDir, Ticker ticker, byte[] bs) {
+               this.ticker = ticker;
+               logFile = new File(nodeDir, "uptime.dat");
+               prevFile = new File(nodeDir, "uptime.old.dat");
+               timeOffset = (int)
+                       ((((double)(Math.abs(Fields.hashCode(bs, bs.length / 2, 
bs.length - bs.length / 2)))) /  Integer.MAX_VALUE)
+                       * (5*60*1000));
+       }
+
+       public void start() {
+               long now = System.currentTimeMillis();
+               int fiveMinutesSinceEpoch = (int)(now / 5*60*1000);
+               int base = fiveMinutesSinceEpoch - wasOnline.length;
+               // Read both files.
+               readData(prevFile, base);
+               readData(logFile, base);
+               schedule(System.currentTimeMillis());
+               System.err.println("Created uptime estimator, time offset is 
"+timeOffset+" uptime at startup is "+getUptime());
+       }
+       
+       private void readData(File file, int base) {
+               FileInputStream fis = null;
+               try {
+                       fis = new FileInputStream(file);
+                       DataInputStream dis = new DataInputStream(fis);
+                       try {
+                               while(true) {
+                                       int offset = dis.readInt();
+                                       if(offset < base) continue;
+                                       int slotNo = offset - base;
+                                       if(slotNo > wasOnline.length) {
+                                               Logger.error(this, "Corrupt 
data read from uptime file "+file+": 5-minutes-from-epoch is now 
"+(base+wasOnline.length)+" but read "+slotNo);
+                                               break;
+                                       }
+                                       wasOnline[slotNo] = true;
+                               }
+                       } catch (EOFException e) {
+                               // Finished
+                       }
+               } catch (IOException e) {
+                       Logger.error(this, "Unable to read old uptime file: 
"+file+" - we will assume we weren't online during that period");
+               } finally {
+                       Closer.close(fis);
+               }
+       }
+
+       public void run() {
+               synchronized(this) {
+                       wasOnline[slot] = true;
+                       slot++;
+                       if(slot == wasOnline.length) slot = 0;
+               }
+               long now = System.currentTimeMillis();
+               if(logFile.length() > wasOnline.length*4) {
+                       prevFile.delete();
+                       logFile.renameTo(prevFile);
+               }
+               FileOutputStream fos = null;
+               DataOutputStream dos = null;
+               int fiveMinutesSinceEpoch = (int)(now / 5*60*1000);
+               try {
+                       fos = new FileOutputStream(logFile, true);
+                       dos = new DataOutputStream(fos);
+                       dos.writeInt(fiveMinutesSinceEpoch);
+               } catch (FileNotFoundException e) {
+                       Logger.error(this, "Unable to create or access 
"+logFile+" : "+e, e);
+               } catch (IOException e) {
+                       Logger.error(this, "Unable to write to uptime estimator 
log file: "+logFile);
+               } finally {
+                       Closer.close(fos);
+                       // Schedule next time
+                       schedule(now);
+               }
+       }
+
+       private void schedule(long now) {
+               long nextTime = (((now / 5*60*1000) + 1) * (5*60*1000)) + 
timeOffset;
+               ticker.queueTimedJob(this, System.currentTimeMillis() - 
nextTime);
+       }
+       
+       /**
+        * Get the node's uptime fraction over the last 48 hours.
+        */
+       public synchronized double getUptime() {
+               int upCount = 0;
+               for(int i=0;i<wasOnline.length;i++) {
+                       if(wasOnline[i]) upCount++;
+               }
+               return ((double) upCount) / ((double) wasOnline.length);
+       }
+       
+}


Reply via email to