[or-cvs] [ernie/master 4/4] Clean up and document consensus stats writer.
karsten at torproject.org
karsten at torproject.org
Sat Feb 27 21:39:02 UTC 2010
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date: Sat, 27 Feb 2010 22:38:28 +0100
Subject: Clean up and document consensus stats writer.
Commit: 4c33c6d4d51c6952c464a26a8ce3bb40642d7933
---
src/ConsensusStatsFileHandler.java | 588 ++++++++++++++++++++++++------------
src/Main.java | 2 +-
2 files changed, 398 insertions(+), 192 deletions(-)
diff --git a/src/ConsensusStatsFileHandler.java b/src/ConsensusStatsFileHandler.java
index e86d1b8..af2b254 100644
--- a/src/ConsensusStatsFileHandler.java
+++ b/src/ConsensusStatsFileHandler.java
@@ -4,288 +4,494 @@ import java.util.*;
import java.util.logging.*;
/**
- *
+ * Generates statistics on the average number of relays and bridges per
+ * day. Accepts parse results from <code>RelayDescriptorParser</code> and
+ * <code>BridgeDescriptorParser</code> and stores them in intermediate
+ * result files <code>stats/consensus-stats-raw</code> and
+ * <code>stats/bridge-consensus-stats-raw</code>. Writes final results to
+ * <code>stats/consensus-stats</code> for all days for which at least half
+ * of the expected consensuses or statuses are known.
*/
public class ConsensusStatsFileHandler {
+
+ /**
+ * Intermediate results file holding the number of relays with Exit,
+ * Fast, Guard, Running, and Stable flags per consensus.
+ */
private File consensusStatsRawFile;
+
+ /**
+ * Number of relays in a given consensus with Exit, Fast, Guard,
+ * Running, and Stable flags set. Map keys are consensus valid-after
+ * times formatted as "yyyy-MM-dd HH:mm:ss", map values are lines as
+ * read from <code>stats/consensus-stats-raw</code>.
+ */
+ private SortedMap<String, String> relaysRaw;
+
+ /**
+ * Modification flag for <code>relaysRaw</code>. This flag is used to
+ * decide whether the contents of <code>relaysRaw</code> need to be
+ * written to disk during <code>writeFiles</code>.
+ */
+ private boolean relaysRawModified;
+
+ /**
+ * Intermediate results file holding the number of running bridges per
+ * bridge status.
+ */
private File bridgeConsensusStatsRawFile;
+
+ /**
+ * Number of running bridges in a given bridge status. Map keys are
+ * bridge status times formatted as "yyyy-MM-dd HH:mm:ss", map values
+ * are lines as read from <code>stats/bridge-consensus-stats-raw</code>.
+ */
+ private SortedMap<String, String> bridgesRaw;
+
+ /**
+ * Modification flag for <code>bridgesRaw</code>. This flag is used to
+ * decide whether the contents of <code>bridgesRaw</code> need to be
+ * written to disk during <code>writeFiles</code>.
+ */
+ private boolean bridgesRawModified;
+
+ /**
+ * Final results file holding the average number of relays with Exit,
+ * Fast, Guard, Running, and Stable flags set and the number of running
+ * bridges per day.
+ */
private File consensusStatsFile;
- private SortedMap<String, String> consensusResults;
- private SortedMap<String, String> bridgeConsensusResults;
- private SortedMap<String, String> csAggr =
- new TreeMap<String, String>();
- private SortedMap<String, String> bcsAggr =
- new TreeMap<String, String>();
- private boolean consensusResultsModified;
- private boolean bridgeConsensusResultsModified;
+
+ /**
+ * Average number of relays with Exit, Fast, Guard, Running, and Stable
+ * flags set per day. Map keys are dates formatted as "yyyy-MM-dd", map
+ * values are lines as written to <code>stats/consensus-stats</code>
+ * without the last column that contains the number of running bridges.
+ */
+ private SortedMap<String, String> relaysPerDay;
+
+ /**
+ * Average number of running bridges per day. Map keys are dates
+ * formatted as "yyyy-MM-dd", map values are the last column as written
+ * to <code>stats/consensus-stats</code>.
+ */
+ private SortedMap<String, String> bridgesPerDay;
+
+ /**
+ * Logger for this class.
+ */
private Logger logger;
+
+ /**
+ * Initializes <code>ConsensusStatsFileHandler</code>, including reading
+ * in intermediate results files <code>stats/consensus-stats-raw</code>
+ * and <code>stats/bridge-consensus-stats-raw</code> and final results
+ * file <code>stats/consensus-stats</code>.
+ */
public ConsensusStatsFileHandler() {
+
+ /* Initialize local data structures to hold intermediate and final
+ * results. */
+ this.relaysPerDay = new TreeMap<String, String>();
+ this.bridgesPerDay = new TreeMap<String, String>();
+ this.relaysRaw = new TreeMap<String, String>();
+ this.bridgesRaw = new TreeMap<String, String>();
+
+ /* Initialize file names for intermediate and final results files. */
this.consensusStatsRawFile = new File("stats/consensus-stats-raw");
this.bridgeConsensusStatsRawFile = new File(
"stats/bridge-consensus-stats-raw");
this.consensusStatsFile = new File("stats/consensus-stats");
- this.consensusResults = new TreeMap<String, String>();
- this.bridgeConsensusResults = new TreeMap<String, String>();
- this.logger =
- Logger.getLogger(ConsensusStatsFileHandler.class.getName());
+
+ /* Initialize logger. */
+ this.logger = Logger.getLogger(
+ ConsensusStatsFileHandler.class.getName());
+
+ /* Read in number of relays with flags set per consensus. */
if (this.consensusStatsRawFile.exists()) {
- this.logger.info("Reading file "
- + this.consensusStatsRawFile.getAbsolutePath() + "...");
try {
+ this.logger.info("Reading file "
+ + this.consensusStatsRawFile.getAbsolutePath() + "...");
BufferedReader br = new BufferedReader(new FileReader(
this.consensusStatsRawFile));
String line = null;
while ((line = br.readLine()) != null) {
- this.consensusResults.put(line.split(",")[0], line);
+ if (line.startsWith("#") || line.startsWith("date")) {
+ continue;
+ }
+ String[] parts = line.split(",");
+ if (parts.length != 6) {
+ this.logger.warning("Corrupt line '" + line + "' in file "
+ + this.consensusStatsRawFile.getAbsolutePath()
+ + "! Aborting to read this file!");
+ break;
+ }
+ String dateTime = parts[0];
+ this.relaysRaw.put(dateTime, line);
}
br.close();
this.logger.info("Finished reading file "
+ this.consensusStatsRawFile.getAbsolutePath() + ".");
} catch (IOException e) {
- this.logger.log(Level.WARNING, "Failed reading file "
+ this.logger.log(Level.WARNING, "Failed to read file "
+ this.consensusStatsRawFile.getAbsolutePath() + "!", e);
}
}
+
+ /* Read in number of running bridges per bridge status. */
if (this.bridgeConsensusStatsRawFile.exists()) {
- this.logger.info("Reading file "
- + this.bridgeConsensusStatsRawFile.getAbsolutePath() + "...");
try {
+ this.logger.info("Reading file "
+ + this.bridgeConsensusStatsRawFile.getAbsolutePath() + "...");
BufferedReader br = new BufferedReader(new FileReader(
this.bridgeConsensusStatsRawFile));
String line = null;
while ((line = br.readLine()) != null) {
- bridgeConsensusResults.put(line.split(",")[0], line);
+ if (line.startsWith("#") || line.startsWith("date")) {
+ continue;
+ }
+ String[] parts = line.split(",");
+ if (parts.length != 2) {
+ this.logger.warning("Corrupt line '" + line + "' in file "
+ + this.bridgeConsensusStatsRawFile.getAbsolutePath()
+ + "! Aborting to read this file!");
+ break;
+ }
+ String dateTime = parts[0];
+ this.bridgesRaw.put(dateTime, line);
}
br.close();
this.logger.info("Finished reading file "
+ this.bridgeConsensusStatsRawFile.getAbsolutePath() + ".");
} catch (IOException e) {
- this.logger.log(Level.WARNING, "Failed reading file "
+ this.logger.log(Level.WARNING, "Failed to read file "
+ this.bridgeConsensusStatsRawFile.getAbsolutePath() + "!",
e);
}
}
+
+ /* Read in previous results on average numbers of relays and running
+ * bridges per day. */
if (this.consensusStatsFile.exists()) {
- this.logger.info("Reading file "
- + this.consensusStatsFile.getAbsolutePath() + "...");
try {
+ this.logger.info("Reading file "
+ + this.consensusStatsFile.getAbsolutePath() + "...");
BufferedReader br = new BufferedReader(new FileReader(
this.consensusStatsFile));
- String line = br.readLine();
+ String line = null;
while ((line = br.readLine()) != null) {
+ if (line.startsWith("#") || line.startsWith("date")) {
+ continue;
+ }
String[] parts = line.split(",");
+ if (parts.length != 7) {
+ this.logger.warning("Corrupt line '" + line + "' in file "
+ + this.consensusStatsFile.getAbsolutePath()
+ + "! Aborting to read this file!");
+ break;
+ }
String date = parts[0];
- boolean foundOneNotNA = false;
- for (int i = 1; i < parts.length - 1; i++) {
- if (!parts[i].equals("NA")) {
- foundOneNotNA = true;
- break;
- }
+ /* Split line into relay and bridge part; the relay part ends
+ * with the last comma (excluding) and the bridge part starts at
+ * that comma (including). */
+ String relayPart = line.substring(0, line.lastIndexOf(","));
+ String bridgePart = line.substring(line.lastIndexOf(","));
+ if (!relayPart.endsWith(",NA,NA,NA,NA,NA")) {
+ this.relaysPerDay.put(date, relayPart);
}
- if (foundOneNotNA) {
- String relays = line.substring(0, line.lastIndexOf(","));
- String bridges = line.substring(line.lastIndexOf(",") + 1) + "\n";
- csAggr.put(date, relays);
- bcsAggr.put(date, bridges);
+ if (!bridgePart.equals(",NA")) {
+ this.bridgesPerDay.put(date, bridgePart);
}
}
br.close();
this.logger.info("Finished reading file "
+ this.consensusStatsFile.getAbsolutePath() + ".");
} catch (IOException e) {
- this.logger.log(Level.WARNING, "Failed reading file "
+ this.logger.log(Level.WARNING, "Failed to write file "
+ this.consensusStatsFile.getAbsolutePath() + "!", e);
}
}
+
+ /* Set modification flags to false. */
+ this.relaysRawModified = this.bridgesRawModified = false;
}
+
+ /**
+ * Adds the intermediate results of the number of relays with certain
+ * flags in a given consensus to the existing observations.
+ */
public void addConsensusResults(String validAfter, int exit, int fast,
int guard, int running, int stable) throws IOException {
- this.consensusResults.put(validAfter, validAfter + "," + exit + ","
- + fast + "," + guard + "," + running + "," + stable);
- this.consensusResultsModified = true;
+ String line = validAfter + "," + exit + "," + fast + "," + guard + ","
+ + running + "," + stable;
+ if (!this.relaysRaw.containsKey(validAfter)) {
+ this.logger.fine("Adding new relay numbers: " + line);
+ this.relaysRaw.put(validAfter, line);
+ this.relaysRawModified = true;
+ } else if (!line.equals(this.relaysRaw.get(validAfter))) {
+ this.logger.warning("The numbers of relays with Exit, Fast, "
+ + "Guard, Running, and Stable flag we were just given (" + line
+ + ") are different from what we learned before ("
+ + this.relaysRaw.get(validAfter) + ")! Overwriting!");
+ this.relaysRaw.put(validAfter, line);
+ this.relaysRawModified = true;
+ }
}
+
+ /**
+ * Adds the intermediate results of the number of running bridges in a
+ * given bridge status to the existing observations.
+ */
public void addBridgeConsensusResults(String published, int running)
throws IOException {
- bridgeConsensusResults.put(published, published + "," + running);
- this.bridgeConsensusResultsModified = true;
+ String line = published + "," + running;
+ if (!this.bridgesRaw.containsKey(published)) {
+ this.logger.fine("Adding new bridge numbers: " + line);
+ this.bridgesRaw.put(published, line);
+ this.bridgesRawModified = true;
+ } else if (!line.equals(this.bridgesRaw.get(published))) {
+ this.logger.warning("The numbers of running bridges we were just "
+ + "given (" + line + ") are different from what we learned "
+ + "before (" + this.bridgesRaw.get(published) + ")! "
+ + "Overwriting!");
+ this.bridgesRaw.put(published, line);
+ this.bridgesRawModified = true;
+ }
}
- public void writeFile() {
- boolean writeConsensusStatsRaw = false;
- boolean writeBridgeConsensusStatsRaw = false;
+
+ /**
+ * Aggregates the raw observations on relay and bridge numbers and
+ * writes both raw and aggregate observations to disk.
+ */
+ public void writeFiles() {
+
+ /* Did we learn anything new about average relay or bridge numbers in
+ * this run? */
boolean writeConsensusStats = false;
- try {
- BufferedWriter bwConsensusStatsRaw = null;
- if (!this.consensusResults.isEmpty()) {
- if (this.consensusResultsModified) {
- this.logger.info("Writing file "
- + this.consensusStatsRawFile.getAbsolutePath() + "...");
- writeConsensusStatsRaw = true;
- this.consensusStatsRawFile.getParentFile().mkdirs();
- bwConsensusStatsRaw = new BufferedWriter(
- new FileWriter(this.consensusStatsRawFile));
- }
- String tempDate = null;
- int exitDay = 0, fastDay = 0, guardDay = 0, runningDay = 0,
- stableDay = 0, consensusesDay = 0;
- Iterator<String> it = this.consensusResults.values().iterator();
- boolean haveWrittenFinalLine = false;
- while (it.hasNext() || !haveWrittenFinalLine) {
- String next = it.hasNext() ? it.next() : null;
- if (tempDate != null
- && (next == null
- || !next.substring(0, 10).equals(tempDate))) {
- if (consensusesDay > 11) {
- String line = tempDate + ","
- + (exitDay / consensusesDay) + ","
- + (fastDay / consensusesDay) + ","
- + (guardDay / consensusesDay) + ","
- + (runningDay / consensusesDay) + ","
- + (stableDay / consensusesDay);
- if (!line.equals(this.csAggr.get(tempDate))) {
- this.csAggr.put(tempDate, line);
- writeConsensusStats = true;
- }
- }
- exitDay = 0;
- fastDay = 0;
- guardDay = 0;
- runningDay = 0;
- stableDay = 0;
- consensusesDay = 0;
- if (next == null) {
- haveWrittenFinalLine = true;
- }
- }
- if (next != null) {
- if (writeConsensusStatsRaw) {
- bwConsensusStatsRaw.append(next + "\n");
+
+ /* Go through raw observations of numbers of relays in consensuses,
+ * calculate averages per day, and add these averages to final
+ * results. */
+ if (!this.relaysRaw.isEmpty()) {
+ String tempDate = null;
+ int exit = 0, fast = 0, guard = 0, running = 0, stable = 0,
+ consensuses = 0;
+ Iterator<String> it = this.relaysRaw.values().iterator();
+ boolean haveWrittenFinalLine = false;
+ while (it.hasNext() || !haveWrittenFinalLine) {
+ String next = it.hasNext() ? it.next() : null;
+ /* Finished reading a day or even all lines? */
+ if (tempDate != null && (next == null
+ || !next.substring(0, 10).equals(tempDate))) {
+ /* Only write results if we have seen at least half of all
+ * consensuses. */
+ if (consensuses >= 12) {
+ String line = tempDate + "," + (exit / consensuses) + ","
+ + (fast/ consensuses) + "," + (guard/ consensuses) + ","
+ + (running/ consensuses) + "," + (stable/ consensuses);
+ /* Are our results new? */
+ if (!this.relaysPerDay.containsKey(tempDate)) {
+ this.logger.fine("Adding new average relay numbers: "
+ + line);
+ this.relaysPerDay.put(tempDate, line);
+ writeConsensusStats = true;
+ } else if (!line.equals(this.relaysPerDay.get(tempDate))) {
+ this.logger.info("Replacing existing average relay numbers "
+ + "(" + this.relaysPerDay.get(tempDate) + " with new "
+ + "numbers: " + line);
+ this.relaysPerDay.put(tempDate, line);
+ writeConsensusStats = true;
}
- String[] parts = next.split(",");
- tempDate = next.substring(0, 10);
- consensusesDay++;
- exitDay += Integer.parseInt(parts[1]);
- fastDay += Integer.parseInt(parts[2]);
- guardDay += Integer.parseInt(parts[3]);
- runningDay += Integer.parseInt(parts[4]);
- stableDay += Integer.parseInt(parts[5]);
}
+ exit = fast = guard = running = stable = consensuses = 0;
+ haveWrittenFinalLine = (next == null);
}
- if (writeConsensusStatsRaw) {
- bwConsensusStatsRaw.close();
- this.logger.info("Finished writing file "
- + this.consensusStatsRawFile.getAbsolutePath() + ".");
+ /* Sum up number of relays with given flags. */
+ if (next != null) {
+ String[] parts = next.split(",");
+ tempDate = next.substring(0, 10);
+ consensuses++;
+ exit += Integer.parseInt(parts[1]);
+ fast += Integer.parseInt(parts[2]);
+ guard += Integer.parseInt(parts[3]);
+ running += Integer.parseInt(parts[4]);
+ stable += Integer.parseInt(parts[5]);
}
}
- } catch (IOException e) {
- this.logger.log(Level.WARNING, "Failed writing file "
- + this.consensusStatsRawFile.getAbsolutePath() + "!", e);
- return;
}
- try {
- BufferedWriter bwBridgeConsensusStatsRaw = null;
- if (!this.bridgeConsensusResults.isEmpty()) {
- if (this.bridgeConsensusResultsModified) {
- this.logger.info("Writing file "
- + this.bridgeConsensusStatsRawFile.getAbsolutePath()
- + "...");
- writeBridgeConsensusStatsRaw = true;
- this.bridgeConsensusStatsRawFile.getParentFile().mkdirs();
- bwBridgeConsensusStatsRaw = new BufferedWriter(
- new FileWriter(this.bridgeConsensusStatsRawFile));
- }
- String tempDate = null;
- int brunningDay = 0, bridgeStatusesDay = 0;
- Iterator<String> it = bridgeConsensusResults.values().iterator();
- boolean haveWrittenFinalLine = false;
- while (it.hasNext() || !haveWrittenFinalLine) {
- String next = it.hasNext() ? it.next() : null;
- if (tempDate != null
- && (next == null
- || !next.substring(0, 10).equals(tempDate))) {
- if (bridgeStatusesDay > 23) {
- String line = "" + (brunningDay / bridgeStatusesDay) + "\n";
- if (!line.equals(this.bcsAggr.get(tempDate))) {
- this.bcsAggr.put(tempDate, line);
- writeConsensusStats = true;
- }
- }
- brunningDay = 0;
- bridgeStatusesDay = 0;
- if (next == null) {
- haveWrittenFinalLine = true;
- }
- }
- if (next != null) {
- if (writeBridgeConsensusStatsRaw) {
- bwBridgeConsensusStatsRaw.append(next + "\n");
+
+ /* Go through raw observations of numbers of running bridges in bridge
+ * statuses, calculate averages per day, and add these averages to
+ * final results. */
+ if (!this.bridgesRaw.isEmpty()) {
+ String tempDate = null;
+ int brunning = 0, statuses = 0;
+ Iterator<String> it = this.bridgesRaw.values().iterator();
+ boolean haveWrittenFinalLine = false;
+ while (it.hasNext() || !haveWrittenFinalLine) {
+ String next = it.hasNext() ? it.next() : null;
+ /* Finished reading a day or even all lines? */
+ if (tempDate != null && (next == null
+ || !next.substring(0, 10).equals(tempDate))) {
+ /* Only write results if we have seen at least half of all
+ * statuses. */
+ if (statuses >= 24) {
+ String line = "," + (brunning / statuses);
+ /* Are our results new? */
+ if (!this.bridgesPerDay.containsKey(tempDate)) {
+ this.logger.fine("Adding new average bridge numbers: "
+ + tempDate + line);
+ this.bridgesPerDay.put(tempDate, line);
+ writeConsensusStats = true;
+ } else if (!line.equals(this.bridgesPerDay.get(tempDate))) {
+ this.logger.info("Replacing existing average bridge "
+ + "numbers (" + this.bridgesPerDay.get(tempDate)
+ + " with new numbers: " + line);
+ this.bridgesPerDay.put(tempDate, line);
+ writeConsensusStats = true;
}
- tempDate = next.substring(0, 10);
- bridgeStatusesDay++;
- brunningDay += Integer.parseInt(next.split(",")[1]);
}
+ brunning = statuses = 0;
+ haveWrittenFinalLine = (next == null);
}
- if (writeBridgeConsensusStatsRaw) {
- bwBridgeConsensusStatsRaw.close();
- this.logger.info("Finished writing file "
- + this.bridgeConsensusStatsRawFile.getAbsolutePath() + ".");
+ /* Sum up number of running bridges. */
+ if (next != null) {
+ tempDate = next.substring(0, 10);
+ statuses++;
+ brunning += Integer.parseInt(next.split(",")[1]);
}
}
- } catch (IOException e) {
- this.logger.log(Level.WARNING, "Failed writing file "
- + this.bridgeConsensusStatsRawFile.getAbsolutePath() + "!", e);
}
- if (writeConsensusStats &&
- !(this.csAggr.isEmpty() && this.bcsAggr.isEmpty())) {
- this.logger.info("Writing file "
- + this.consensusStatsFile.getAbsolutePath() + "...");
+
+ /* Write raw numbers of relays with flags set to disk. */
+ if (this.relaysRawModified) {
try {
- this.consensusStatsFile.getParentFile().mkdirs();
- BufferedWriter bwConsensusStats = new BufferedWriter(
- new FileWriter(this.consensusStatsFile));
- bwConsensusStats.append("date,exit,fast,guard,running,stable,"
- + "brunning\n");
- SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
- format.setTimeZone(TimeZone.getTimeZone("UTC"));
- long firstDate = 0L, lastDate = 0L;
- if (this.csAggr.isEmpty()) {
- firstDate = format.parse(this.bcsAggr.firstKey()).getTime();
- lastDate = format.parse(this.bcsAggr.lastKey()).getTime();
- } else if (this.bcsAggr.isEmpty()) {
- firstDate = format.parse(this.csAggr.firstKey()).getTime();
- lastDate = format.parse(this.csAggr.lastKey()).getTime();
- } else {
- firstDate = Math.min(
- format.parse(this.csAggr.firstKey()).getTime(),
- format.parse(this.bcsAggr.firstKey()).getTime());
- lastDate = Math.max(
- format.parse(this.csAggr.lastKey()).getTime(),
- format.parse(this.bcsAggr.lastKey()).getTime());
+ this.logger.info("Writing file "
+ + this.consensusStatsRawFile.getAbsolutePath() + "...");
+ this.consensusStatsRawFile.getParentFile().mkdirs();
+ BufferedWriter bw = new BufferedWriter(new FileWriter(
+ this.consensusStatsRawFile));
+ bw.append("# Number of relays in a given consensus with Exit, "
+ + "Fast, Guard, Running,\n# and Stable flags set. Columns "
+ + "are:\n# - datetime: Date and time when the consensus was "
+ + "published as written in\n# the valid-after line\n# - "
+ + "exit: Number of relays with the Running and the Exit "
+ + "flag\n# - fast: Number of relays with the Running and the "
+ + "Fast flag\n# - guard: Number of relays with the Running "
+ + "and the Guard flag\n# - running: Number of relays with "
+ + "the Running flag\n# - stable: Number of relays with the "
+ + "Running and the Stable flag\ndatetime,exit,fast,guard,"
+ + "running,stable\n");
+ for (String line : this.relaysRaw.values()) {
+ bw.append(line + "\n");
}
- long currentDate = firstDate;
- while (currentDate <= lastDate) {
- String date = format.format(new Date(currentDate));
- if (this.csAggr.containsKey(date)) {
- bwConsensusStats.append(this.csAggr.get(date));
+ bw.close();
+ this.logger.info("Finished writing file "
+ + this.consensusStatsRawFile.getAbsolutePath() + ".");
+ } catch (IOException e) {
+ this.logger.log(Level.WARNING, "Failed to write file "
+ + this.consensusStatsRawFile.getAbsolutePath() + "!", e);
+ }
+ } else {
+ this.logger.info("Not writing file "
+ + this.consensusStatsRawFile.getAbsolutePath() + ", because "
+ + "nothing has changed.");
+ }
+
+ /* Write raw numbers of running bridges to disk. */
+ if (this.bridgesRawModified) {
+ try {
+ this.logger.info("Writing file "
+ + this.bridgeConsensusStatsRawFile.getAbsolutePath() + "...");
+ this.bridgeConsensusStatsRawFile.getParentFile().mkdirs();
+ BufferedWriter bw = new BufferedWriter(
+ new FileWriter(this.bridgeConsensusStatsRawFile));
+ bw.append("# Number of running bridges in a given bridge status. "
+ + "Columns are:\n# - datetime: Date and time when the "
+ + "snapshot of this bridge status was\n# taken\n# - "
+ + "brunning: Number of bridges with the Running flag\n"
+ + "datetime,brunning\n");
+ for (String line : this.bridgesRaw.values()) {
+ bw.append(line + "\n");
+ }
+ bw.close();
+ this.logger.info("Finished writing file "
+ + this.bridgeConsensusStatsRawFile.getAbsolutePath() + ".");
+ } catch (IOException e) {
+ this.logger.log(Level.WARNING, "Failed to write file "
+ + this.bridgeConsensusStatsRawFile.getAbsolutePath() + "!",
+ e);
+ }
+ } else {
+ this.logger.info("Not writing file "
+ + this.bridgeConsensusStatsRawFile.getAbsolutePath()
+ + ", because nothing has changed.");
+ }
+
+ /* Write final results of relays with flags set and running bridges
+ * to disk. */
+ if (writeConsensusStats) {
+ try {
+ this.logger.info("Writing file "
+ + this.consensusStatsFile.getAbsolutePath() + "...");
+ this.consensusStatsFile.getParentFile().mkdirs();
+ BufferedWriter bw = new BufferedWriter(new FileWriter(
+ this.consensusStatsFile));
+ bw.append("# Statistics on the average number of relays and "
+ + "bridges per day as\n# extracted from relay consensuses "
+ + "and bridge statuses. Columns are:\n# - date: Date when "
+ + "the relay consensuses or bridge statuses were\n# "
+ + "published\n# - exit: Average number of relays with the "
+ + "Running and the Exit flag\n# - fast: Average number of "
+ + "relays with the Running and the Fast flag\n# - guard: "
+ + "Average number of relays with the Running and the Guard "
+ + "flag\n# - running: Average number of relays with the "
+ + "Running flag\n# - stable: Average number of relays with "
+ + "the Running and the Stable flag\n# - brunning: Average "
+ + "number of bridges with the Running flag\ndate,exit,fast,"
+ + "guard,running,stable,brunning\n");
+ /* Iterate over all days, including those for which we don't have
+ * observations for which we add NA's to all columns. */
+ SortedSet<String> allDates = new TreeSet<String>();
+ allDates.addAll(this.relaysPerDay.keySet());
+ allDates.addAll(this.bridgesPerDay.keySet());
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+ dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+ long firstDateMillis = dateFormat.parse(allDates.first()).
+ getTime();
+ long lastDateMillis = dateFormat.parse(allDates.last()).getTime();
+ long currentDateMillis = firstDateMillis;
+ while (currentDateMillis <= lastDateMillis) {
+ /* Write observations about relays, bridges, both, or none of
+ * them. */
+ String date = dateFormat.format(new Date(currentDateMillis));
+ if (this.relaysPerDay.containsKey(date)) {
+ bw.append(this.relaysPerDay.get(date));
} else {
- bwConsensusStats.append(date + ",NA,NA,NA,NA,NA");
+ bw.append(date + ",NA,NA,NA,NA,NA");
}
- if (this.bcsAggr.containsKey(date)) {
- bwConsensusStats.append("," + this.bcsAggr.get(date));
+ if (this.bridgesPerDay.containsKey(date)) {
+ bw.append(this.bridgesPerDay.get(date) + "\n");
} else {
- bwConsensusStats.append(",NA\n");
+ bw.append(",NA\n");
}
- currentDate += 86400000L;
+ /* Advance by 1 day. */
+ currentDateMillis += 24L * 60L * 60L * 1000L;
}
- bwConsensusStats.close();
+ bw.close();
this.logger.info("Finished writing file "
+ this.consensusStatsFile.getAbsolutePath() + ".");
} catch (IOException e) {
- this.logger.log(Level.WARNING, "Failed writing file "
+ this.logger.log(Level.WARNING, "Failed to write file "
+ this.consensusStatsFile.getAbsolutePath() + "!", e);
} catch (ParseException e) {
- this.logger.log(Level.WARNING, "Failed writing file "
+ this.logger.log(Level.WARNING, "Failed to write file "
+ this.consensusStatsFile.getAbsolutePath() + "!", e);
}
+ } else {
+ this.logger.info("Not writing file "
+ + this.consensusStatsFile.getAbsolutePath()
+ + ", because nothing has changed.");
}
}
}
diff --git a/src/Main.java b/src/Main.java
index 6bacca9..1902116 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -93,7 +93,7 @@ public class Main {
bsfh = null;
}
if (csfh != null) {
- csfh.writeFile();
+ csfh.writeFiles();
csfh = null;
}
--
1.6.5
More information about the tor-commits
mailing list