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