[tor-commits] [metrics-lib/master] Fast exits read/write more than MAX_INT KiB per day.

karsten at torproject.org karsten at torproject.org
Mon Jul 8 10:56:29 UTC 2013


commit 60a066a0b08bbe621ed5ce9d0184ac168435bfa4
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Mon Jul 8 12:53:53 2013 +0200

    Fast exits read/write more than MAX_INT KiB per day.
    
    For example, see "other" entry in:
    
      exit-kibibytes-read 80=505190490,182=25102395,443=61873906,
        6881=47999666,8989=8657674,17173=7910494,21762=9138992,
        45682=5154543,50500=6086469,51413=62394452,other=2282907805
---
 .../torproject/descriptor/ExtraInfoDescriptor.java |    6 +-
 .../descriptor/impl/ExtraInfoDescriptorImpl.java   |  101 +++++++++++---------
 .../torproject/descriptor/impl/ParseHelper.java    |   43 ++++++++-
 .../impl/ExtraInfoDescriptorImplTest.java          |   15 ++-
 4 files changed, 111 insertions(+), 54 deletions(-)

diff --git a/src/org/torproject/descriptor/ExtraInfoDescriptor.java b/src/org/torproject/descriptor/ExtraInfoDescriptor.java
index 1478a4a..d19c590 100644
--- a/src/org/torproject/descriptor/ExtraInfoDescriptor.java
+++ b/src/org/torproject/descriptor/ExtraInfoDescriptor.java
@@ -205,18 +205,18 @@ public interface ExtraInfoDescriptor extends Descriptor {
   /* Return statistics on KiB written by port with map keys being ports
    * (or "other") and map values being KiB rounded up to the next full
    * KiB, or null if no exit statistics are included. */
-  public SortedMap<String, Integer> getExitKibibytesWritten();
+  public SortedMap<String, Long> getExitKibibytesWritten();
 
   /* Return statistics on KiB read by port with map keys being ports (or
    * "other") and map values being KiB rounded up to the next full KiB, or
    * null if no exit statistics are included. */
-  public SortedMap<String, Integer> getExitKibibytesRead();
+  public SortedMap<String, Long> getExitKibibytesRead();
 
   /* Return statistics on opened exit streams with map keys being ports
    * (or "other") and map values being the number of opened streams,
    * rounded up to the nearest multiple of 4, or null if no exit
    * statistics are included. */
-  public SortedMap<String, Integer> getExitStreamsOpened();
+  public SortedMap<String, Long> getExitStreamsOpened();
 
   /* Return the start of the included geoip statistics, or -1 if no geoip
    * statistics are included. */
diff --git a/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java b/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
index f5bf8ed..c67a040 100644
--- a/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
+++ b/src/org/torproject/descriptor/impl/ExtraInfoDescriptorImpl.java
@@ -258,8 +258,9 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
 
   private void parseGeoipClientOriginsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.geoipClientOrigins = ParseHelper.parseCommaSeparatedKeyValueList(
-        line, partsNoOpt, 1, 2);
+    this.geoipClientOrigins =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
+        partsNoOpt, 1, 2);
   }
 
   private void parseDirreqStatsEndLine(String line, String lineNoOpt,
@@ -290,25 +291,27 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
 
   private void parseDirreqV2IpsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV2Ips = ParseHelper.parseCommaSeparatedKeyValueList(line,
-        partsNoOpt, 1, 2);
+    this.dirreqV2Ips = ParseHelper.parseCommaSeparatedKeyIntegerValueList(
+        line, partsNoOpt, 1, 2);
   }
 
   private void parseDirreqV3IpsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV3Ips = ParseHelper.parseCommaSeparatedKeyValueList(line,
-        partsNoOpt, 1, 2);
+    this.dirreqV3Ips = ParseHelper.parseCommaSeparatedKeyIntegerValueList(
+        line, partsNoOpt, 1, 2);
   }
 
   private void parseDirreqV2ReqsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV2Reqs = ParseHelper.parseCommaSeparatedKeyValueList(line,
+    this.dirreqV2Reqs =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
         partsNoOpt, 1, 2);
   }
 
   private void parseDirreqV3ReqsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV3Reqs = ParseHelper.parseCommaSeparatedKeyValueList(line,
+    this.dirreqV3Reqs =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
         partsNoOpt, 1, 2);
   }
 
@@ -343,38 +346,44 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
 
   private void parseDirreqV2RespLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV2Resp = ParseHelper.parseCommaSeparatedKeyValueList(line,
+    this.dirreqV2Resp =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
         partsNoOpt, 1, 0);
   }
 
   private void parseDirreqV3RespLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV3Resp = ParseHelper.parseCommaSeparatedKeyValueList(line,
+    this.dirreqV3Resp =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
         partsNoOpt, 1, 0);
   }
 
   private void parseDirreqV2DirectDlLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV2DirectDl = ParseHelper.parseCommaSeparatedKeyValueList(
-        line, partsNoOpt, 1, 0);
+    this.dirreqV2DirectDl =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
+        partsNoOpt, 1, 0);
   }
 
   private void parseDirreqV3DirectDlLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV3DirectDl = ParseHelper.parseCommaSeparatedKeyValueList(
-        line, partsNoOpt, 1, 0);
+    this.dirreqV3DirectDl =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
+        partsNoOpt, 1, 0);
   }
 
   private void parseDirreqV2TunneledDlLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV2TunneledDl = ParseHelper.parseCommaSeparatedKeyValueList(
-        line, partsNoOpt, 1, 0);
+    this.dirreqV2TunneledDl =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
+        partsNoOpt, 1, 0);
   }
 
   private void parseDirreqV3TunneledDlLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.dirreqV3TunneledDl = ParseHelper.parseCommaSeparatedKeyValueList(
-        line, partsNoOpt, 1, 0);
+    this.dirreqV3TunneledDl =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(
+        line,partsNoOpt, 1, 0);
   }
 
   private void parseDirreqReadHistoryLine(String line, String lineNoOpt,
@@ -399,8 +408,8 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
 
   private void parseEntryIpsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.entryIps = ParseHelper.parseCommaSeparatedKeyValueList(line,
-        partsNoOpt, 1, 2);
+    this.entryIps = ParseHelper.parseCommaSeparatedKeyIntegerValueList(
+        line, partsNoOpt, 1, 2);
   }
 
   private void parseCellStatsEndLine(String line, String lineNoOpt,
@@ -488,7 +497,7 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
       String lineNoOpt, String[] partsNoOpt)
       throws DescriptorParseException {
     this.exitKibibytesWritten = this.sortByPorts(ParseHelper.
-        parseCommaSeparatedKeyValueList(line, partsNoOpt, 1, 0));
+        parseCommaSeparatedKeyLongValueList(line, partsNoOpt, 1, 0));
     this.verifyPorts(line, this.exitKibibytesWritten.keySet());
     this.verifyBytesOrStreams(line, this.exitKibibytesWritten.values());
   }
@@ -496,7 +505,7 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
   private void parseExitKibibytesReadLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
     this.exitKibibytesRead = this.sortByPorts(ParseHelper.
-        parseCommaSeparatedKeyValueList(line, partsNoOpt, 1, 0));
+        parseCommaSeparatedKeyLongValueList(line, partsNoOpt, 1, 0));
     this.verifyPorts(line, this.exitKibibytesRead.keySet());
     this.verifyBytesOrStreams(line, this.exitKibibytesRead.values());
   }
@@ -504,15 +513,15 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
   private void parseExitStreamsOpenedLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
     this.exitStreamsOpened = this.sortByPorts(ParseHelper.
-        parseCommaSeparatedKeyValueList(line, partsNoOpt, 1, 0));
+        parseCommaSeparatedKeyLongValueList(line, partsNoOpt, 1, 0));
     this.verifyPorts(line, this.exitStreamsOpened.keySet());
     this.verifyBytesOrStreams(line, this.exitStreamsOpened.values());
   }
 
-  private SortedMap<String, Integer> sortByPorts(
-      SortedMap<String, Integer> naturalOrder) {
-    SortedMap<String, Integer> byPortNumber =
-        new TreeMap<String, Integer>(new Comparator<String>() {
+  private SortedMap<String, Long> sortByPorts(
+      SortedMap<String, Long> naturalOrder) {
+    SortedMap<String, Long> byPortNumber =
+        new TreeMap<String, Long>(new Comparator<String>() {
           public int compare(String arg0, String arg1) {
             int port0 = 0, port1 = 0;
             try {
@@ -557,11 +566,10 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
   }
 
   private void verifyBytesOrStreams(String line,
-      Collection<Integer> bytesOrStreams)
-      throws DescriptorParseException {
+      Collection<Long> bytesOrStreams) throws DescriptorParseException {
     boolean valid = true;
-    for (int s : bytesOrStreams) {
-      if (s < 0) {
+    for (long s : bytesOrStreams) {
+      if (s < 0L) {
         valid = false;
         break;
       }
@@ -582,20 +590,23 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
 
   private void parseBridgeStatsIpsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.bridgeIps = ParseHelper.parseCommaSeparatedKeyValueList(line,
+    this.bridgeIps =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
         partsNoOpt, 1, 2);
   }
 
   private void parseBridgeIpVersionsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.bridgeIpVersions = ParseHelper.parseCommaSeparatedKeyValueList(
-        line, partsNoOpt, 1, 2);
+    this.bridgeIpVersions =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
+        partsNoOpt, 1, 2);
   }
 
   private void parseBridgeIpTransportsLine(String line, String lineNoOpt,
       String[] partsNoOpt) throws DescriptorParseException {
-    this.bridgeIpTransports = ParseHelper.parseCommaSeparatedKeyValueList(
-        line, partsNoOpt, 1, 0);
+    this.bridgeIpTransports =
+        ParseHelper.parseCommaSeparatedKeyIntegerValueList(line,
+        partsNoOpt, 1, 0);
   }
 
   private void parseTransportLine(String line, String lineNoOpt,
@@ -869,22 +880,22 @@ public class ExtraInfoDescriptorImpl extends DescriptorImpl
     return this.exitStatsIntervalLength;
   }
 
-  private SortedMap<String, Integer> exitKibibytesWritten;
-  public SortedMap<String, Integer> getExitKibibytesWritten() {
+  private SortedMap<String, Long> exitKibibytesWritten;
+  public SortedMap<String, Long> getExitKibibytesWritten() {
     return this.exitKibibytesWritten == null ? null :
-        new TreeMap<String, Integer>(this.exitKibibytesWritten);
+        new TreeMap<String, Long>(this.exitKibibytesWritten);
   }
 
-  private SortedMap<String, Integer> exitKibibytesRead;
-  public SortedMap<String, Integer> getExitKibibytesRead() {
+  private SortedMap<String, Long> exitKibibytesRead;
+  public SortedMap<String, Long> getExitKibibytesRead() {
     return this.exitKibibytesRead == null ? null :
-        new TreeMap<String, Integer>(this.exitKibibytesRead);
+        new TreeMap<String, Long>(this.exitKibibytesRead);
   }
 
-  private SortedMap<String, Integer> exitStreamsOpened;
-  public SortedMap<String, Integer> getExitStreamsOpened() {
+  private SortedMap<String, Long> exitStreamsOpened;
+  public SortedMap<String, Long> getExitStreamsOpened() {
     return this.exitStreamsOpened == null ? null :
-        new TreeMap<String, Integer>(this.exitStreamsOpened);
+        new TreeMap<String, Long>(this.exitStreamsOpened);
   }
 
   private long geoipStartTimeMillis = -1L;
diff --git a/src/org/torproject/descriptor/impl/ParseHelper.java b/src/org/torproject/descriptor/impl/ParseHelper.java
index 4fd776e..ebb8bc6 100644
--- a/src/org/torproject/descriptor/impl/ParseHelper.java
+++ b/src/org/torproject/descriptor/impl/ParseHelper.java
@@ -253,8 +253,9 @@ public class ParseHelper {
   }
 
   public static SortedMap<String, Integer>
-      parseCommaSeparatedKeyValueList(String line, String[] partsNoOpt,
-      int index, int keyLength) throws DescriptorParseException {
+      parseCommaSeparatedKeyIntegerValueList(String line,
+      String[] partsNoOpt, int index, int keyLength)
+      throws DescriptorParseException {
     SortedMap<String, Integer> result = new TreeMap<String, Integer>();
     if (partsNoOpt.length < index) {
       throw new DescriptorParseException("Line '" + line + "' does not "
@@ -289,6 +290,44 @@ public class ParseHelper {
     return result;
   }
 
+  public static SortedMap<String, Long>
+      parseCommaSeparatedKeyLongValueList(String line,
+      String[] partsNoOpt, int index, int keyLength)
+      throws DescriptorParseException {
+    SortedMap<String, Long> result = new TreeMap<String, Long>();
+    if (partsNoOpt.length < index) {
+      throw new DescriptorParseException("Line '" + line + "' does not "
+          + "contain a key-value list at index " + index + ".");
+    } else if (partsNoOpt.length > index + 1 ) {
+      throw new DescriptorParseException("Line '" + line + "' contains "
+          + "unrecognized values beyond the expected key-value list at "
+          + "index " + index + ".");
+    } else if (partsNoOpt.length > index) {
+      String[] listElements = partsNoOpt[index].split(",", -1);
+      for (String listElement : listElements) {
+        String[] keyAndValue = listElement.split("=");
+        String key = null;
+        long value = -1;
+        if (keyAndValue.length == 2 && (keyLength == 0 ||
+            keyAndValue[0].length() == keyLength)) {
+          try {
+            value = Long.parseLong(keyAndValue[1]);
+            key = keyAndValue[0];
+          } catch (NumberFormatException e) {
+            /* Handle below. */
+          }
+        }
+        if (key == null) {
+          throw new DescriptorParseException("Line '" + line + "' "
+              + "contains an illegal key or value in list element '"
+              + listElement + "'.");
+        }
+        result.put(key, value);
+      }
+    }
+    return result;
+  }
+
   public static List<Integer> parseCommaSeparatedIntegerValueList(
       String line, String[] partsNoOpt, int index)
       throws DescriptorParseException {
diff --git a/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java b/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
index 11b07b2..4aa8a44 100644
--- a/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
+++ b/test/org/torproject/descriptor/impl/ExtraInfoDescriptorImplTest.java
@@ -1234,7 +1234,7 @@ public class ExtraInfoDescriptorImplTest {
     int[] writtenValues = new int[] { 74647, 31370, 20577, 23, 12, 1111,
         4, 11, 6, 3365, 2592 };
     int i = 0;
-    for (Map.Entry<String, Integer> e :
+    for (Map.Entry<String, Long> e :
         descriptor.getExitKibibytesWritten().entrySet()) {
       assertEquals(ports[i], e.getKey());
       assertEquals(writtenValues[i++], e.getValue().intValue());
@@ -1242,7 +1242,7 @@ public class ExtraInfoDescriptorImplTest {
     int[] readValues = new int[] { 35562, 1254256, 110279, 9396, 1911,
         648, 1188, 1427, 1824, 14, 3054 };
     i = 0;
-    for (Map.Entry<String, Integer> e :
+    for (Map.Entry<String, Long> e :
         descriptor.getExitKibibytesRead().entrySet()) {
       assertEquals(ports[i], e.getKey());
       assertEquals(readValues[i++], e.getValue().intValue());
@@ -1250,7 +1250,7 @@ public class ExtraInfoDescriptorImplTest {
     int[] streamsValues = new int[] { 369748, 64212, 151660, 4, 4, 4, 4,
         4, 4, 4, 1212 };
     i = 0;
-    for (Map.Entry<String, Integer> e :
+    for (Map.Entry<String, Long> e :
         descriptor.getExitStreamsOpened().entrySet()) {
       assertEquals(ports[i], e.getKey());
       assertEquals(streamsValues[i++], e.getValue().intValue());
@@ -1285,7 +1285,14 @@ public class ExtraInfoDescriptorImplTest {
         "exit-kibibytes-read 25=-35562");
   }
 
-  @Test(expected = DescriptorParseException.class)
+  @Test()
+  public void testExitStatsReadTooLarge()
+      throws DescriptorParseException {
+    ExitStatsBuilder.createWithExitKibibytesReadLine(
+        "exit-kibibytes-read other=2282907805");
+  }
+
+  @Test()
   public void testExitStatsStreamsTooLarge()
       throws DescriptorParseException {
     ExitStatsBuilder.createWithExitStreamsOpenedLine(



More information about the tor-commits mailing list