[tor-commits] [onionoo/master] Add new method to list recently stored documents.

karsten at torproject.org karsten at torproject.org
Mon Dec 8 12:22:56 UTC 2014


commit 99d9f094722b1f0f1b0ba1b51ff53e942a06a263
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Tue Oct 28 14:32:28 2014 +0100

    Add new method to list recently stored documents.
    
    This is a rather big refactoring of how document writers obtain a list of
    documents they should write.
    
    The old way was to register a "fingerprint listener" at the descriptor
    source and write documents of all relays and bridges whose fingerprints
    it they learned about.  One drawback (or even bug; cf. #12651) was that
    document writers didn't learn about relays or bridges that went offline,
    because there's no descriptor for that.
    
    The new way is for document writers to ask for a list of status files that
    have changed since the last "update status" file was written.  This can be
    implemented for documents cached in memory and for documents stored on
    disk.  Document writers can then use this list to only write the
    documents that need updating.
---
 .../org/torproject/onionoo/docs/DocumentStore.java |   85 +++++++++++++-------
 .../org/torproject/onionoo/docs/UpdateStatus.java  |   29 ++++++-
 .../org/torproject/onionoo/server/NodeIndexer.java |   12 +--
 .../onionoo/updater/DescriptorSource.java          |   77 +-----------------
 .../onionoo/updater/FingerprintListener.java       |   10 ---
 .../onionoo/writer/BandwidthDocumentWriter.java    |   36 +++------
 .../onionoo/writer/ClientsDocumentWriter.java      |   35 +++-----
 .../onionoo/writer/DetailsDocumentWriter.java      |   64 +++++++--------
 .../onionoo/writer/UptimeDocumentWriter.java       |   57 ++++---------
 .../onionoo/writer/WeightsDocumentWriter.java      |   43 +++-------
 .../torproject/onionoo/DummyDescriptorSource.java  |   47 -----------
 .../org/torproject/onionoo/DummyDocumentStore.java |   11 ++-
 .../torproject/onionoo/ResourceServletTest.java    |    3 +-
 .../onionoo/UptimeDocumentWriterTest.java          |    3 -
 14 files changed, 174 insertions(+), 338 deletions(-)

diff --git a/src/main/java/org/torproject/onionoo/docs/DocumentStore.java b/src/main/java/org/torproject/onionoo/docs/DocumentStore.java
index 23ac03f..5137fb4 100644
--- a/src/main/java/org/torproject/onionoo/docs/DocumentStore.java
+++ b/src/main/java/org/torproject/onionoo/docs/DocumentStore.java
@@ -66,22 +66,41 @@ public class DocumentStore {
   private SortedMap<String, NodeStatus> cachedNodeStatuses;
   private SortedMap<String, SummaryDocument> cachedSummaryDocuments;
 
+  /* Last-modified timestamp of cached network statuses and summary
+   * documents when reading them from disk. */
+  private long lastModifiedNodeStatuses = 0L;
+  private long lastModifiedSummaryDocuments = 0L;
+
+  /* Fingerprints of updated node statuses and summary documents that are
+   * not yet written to disk. */
+  private SortedSet<String> updatedNodeStatuses;
+  private SortedSet<String> updatedSummaryDocuments;
+
   public <T extends Document> SortedSet<String> list(
       Class<T> documentType) {
+    return this.list(documentType, 0L);
+  }
+
+  public <T extends Document> SortedSet<String> list(
+      Class<T> documentType, long updatedAfter) {
     if (documentType.equals(NodeStatus.class)) {
-      return this.listNodeStatuses();
+      return this.listNodeStatuses(updatedAfter);
     } else if (documentType.equals(SummaryDocument.class)) {
-      return this.listSummaryDocuments();
+      return this.listSummaryDocuments(updatedAfter);
     } else {
-      return this.listDocumentFiles(documentType);
+      return this.listDocumentFiles(documentType, updatedAfter);
     }
   }
 
-  private SortedSet<String> listNodeStatuses() {
+  private SortedSet<String> listNodeStatuses(long updatedAfter) {
     if (this.cachedNodeStatuses == null) {
       this.cacheNodeStatuses();
     }
-    return new TreeSet<String>(this.cachedNodeStatuses.keySet());
+    if (updatedAfter >= this.lastModifiedNodeStatuses) {
+      return new TreeSet<String>(this.updatedNodeStatuses);
+    } else {
+      return new TreeSet<String>(this.cachedNodeStatuses.keySet());
+    }
   }
 
   private void cacheNodeStatuses() {
@@ -105,6 +124,7 @@ public class DocumentStore {
             }
           }
           br.close();
+          this.lastModifiedNodeStatuses = summaryFile.lastModified();
           this.listedFiles += parsedNodeStatuses.size();
           this.listOperations++;
         } catch (IOException e) {
@@ -114,13 +134,18 @@ public class DocumentStore {
       }
     }
     this.cachedNodeStatuses = parsedNodeStatuses;
+    this.updatedNodeStatuses = new TreeSet<String>();
   }
 
-  private SortedSet<String> listSummaryDocuments() {
+  private SortedSet<String> listSummaryDocuments(long updatedAfter) {
     if (this.cachedSummaryDocuments == null) {
       this.cacheSummaryDocuments();
     }
-    return new TreeSet<String>(this.cachedSummaryDocuments.keySet());
+    if (updatedAfter >= this.lastModifiedSummaryDocuments) {
+      return new TreeSet<String>(this.updatedSummaryDocuments);
+    } else {
+      return new TreeSet<String>(this.cachedSummaryDocuments.keySet());
+    }
   }
 
   private void cacheSummaryDocuments() {
@@ -147,6 +172,7 @@ public class DocumentStore {
             }
           }
           br.close();
+          this.lastModifiedSummaryDocuments = summaryFile.lastModified();
           this.listedFiles += parsedSummaryDocuments.size();
           this.listOperations++;
         } catch (IOException e) {
@@ -159,10 +185,11 @@ public class DocumentStore {
       }
     }
     this.cachedSummaryDocuments = parsedSummaryDocuments;
+    this.updatedSummaryDocuments = new TreeSet<String>();
   }
 
   private <T extends Document> SortedSet<String> listDocumentFiles(
-      Class<T> documentType) {
+      Class<T> documentType, long updatedAfter) {
     SortedSet<String> fingerprints = new TreeSet<String>();
     File directory = null;
     String subdirectory = null;
@@ -204,8 +231,9 @@ public class DocumentStore {
         File file = files.pop();
         if (file.isDirectory()) {
           files.addAll(Arrays.asList(file.listFiles()));
-        } else if (file.getName().length() == 40) {
-            fingerprints.add(file.getName());
+        } else if (file.getName().length() == 40 &&
+            (updatedAfter == 0L || file.lastModified() > updatedAfter)) {
+          fingerprints.add(file.getName());
         }
       }
     }
@@ -235,6 +263,7 @@ public class DocumentStore {
     if (this.cachedNodeStatuses == null) {
       this.cacheNodeStatuses();
     }
+    this.updatedNodeStatuses.add(fingerprint);
     this.cachedNodeStatuses.put(fingerprint, nodeStatus);
     return true;
   }
@@ -244,6 +273,7 @@ public class DocumentStore {
     if (this.cachedSummaryDocuments == null) {
       this.cacheSummaryDocuments();
     }
+    this.updatedSummaryDocuments.add(fingerprint);
     this.cachedSummaryDocuments.put(fingerprint, summaryDocument);
     return true;
   }
@@ -289,7 +319,8 @@ public class DocumentStore {
     } else if (document instanceof BandwidthStatus ||
         document instanceof WeightsStatus ||
         document instanceof ClientsStatus ||
-        document instanceof UptimeStatus) {
+        document instanceof UptimeStatus ||
+        document instanceof UpdateStatus) {
       documentString = document.toDocumentString();
     } else {
       log.error("Serializing is not supported for type "
@@ -435,7 +466,8 @@ public class DocumentStore {
     } else if (documentType.equals(BandwidthStatus.class) ||
         documentType.equals(WeightsStatus.class) ||
         documentType.equals(ClientsStatus.class) ||
-        documentType.equals(UptimeStatus.class)) {
+        documentType.equals(UptimeStatus.class) ||
+        documentType.equals(UpdateStatus.class)) {
       return this.retrieveParsedStatusFile(documentType, documentString);
     } else if (documentType.equals(DetailsStatus.class)) {
       return this.retrieveParsedDocumentFile(documentType, "{"
@@ -523,6 +555,7 @@ public class DocumentStore {
     if (this.cachedNodeStatuses == null) {
       this.cacheNodeStatuses();
     }
+    this.updatedNodeStatuses.remove(fingerprint);
     return this.cachedNodeStatuses.remove(fingerprint) != null;
   }
 
@@ -530,6 +563,7 @@ public class DocumentStore {
     if (this.cachedSummaryDocuments == null) {
       this.cacheSummaryDocuments();
     }
+    this.updatedSummaryDocuments.remove(fingerprint);
     return this.cachedSummaryDocuments.remove(fingerprint) != null;
   }
 
@@ -550,9 +584,6 @@ public class DocumentStore {
     File documentFile = null;
     if (fingerprint == null && !documentType.equals(UpdateStatus.class) &&
         !documentType.equals(UptimeStatus.class)) {
-      // TODO Instead of using the update file workaround, add new method
-      // lastModified(Class<T> documentType) that serves a similar
-      // purpose.
       return null;
     }
     File directory = null;
@@ -631,6 +662,10 @@ public class DocumentStore {
   public void invalidateDocumentCache() {
     this.cachedNodeStatuses = null;
     this.cachedSummaryDocuments = null;
+    this.lastModifiedNodeStatuses = 0L;
+    this.lastModifiedSummaryDocuments = 0L;
+    this.updatedNodeStatuses = null;
+    this.updatedSummaryDocuments = null;
   }
 
   private void writeNodeStatuses() {
@@ -675,6 +710,8 @@ public class DocumentStore {
       BufferedWriter bw = new BufferedWriter(new FileWriter(summaryFile));
       bw.write(documentString);
       bw.close();
+      this.lastModifiedNodeStatuses = summaryFile.lastModified();
+      this.updatedNodeStatuses.clear();
       this.storedFiles++;
       this.storedBytes += documentString.length();
     } catch (IOException e) {
@@ -703,6 +740,8 @@ public class DocumentStore {
       BufferedWriter bw = new BufferedWriter(new FileWriter(summaryFile));
       bw.write(documentString);
       bw.close();
+      this.lastModifiedSummaryDocuments = summaryFile.lastModified();
+      this.updatedSummaryDocuments.clear();
       this.storedFiles++;
       this.storedBytes += documentString.length();
     } catch (IOException e) {
@@ -715,19 +754,9 @@ public class DocumentStore {
     if (this.outDir == null) {
       return;
     }
-    File updateFile = new File(this.outDir, "update");
-    String documentString = String.valueOf(this.time.currentTimeMillis());
-    try {
-      updateFile.getParentFile().mkdirs();
-      BufferedWriter bw = new BufferedWriter(new FileWriter(updateFile));
-      bw.write(documentString);
-      bw.close();
-      this.storedFiles++;
-      this.storedBytes += documentString.length();
-    } catch (IOException e) {
-      log.error("Could not write file '"
-          + updateFile.getAbsolutePath() + "'.", e);
-    }
+    UpdateStatus updateStatus = new UpdateStatus();
+    updateStatus.setUpdatedMillis(this.time.currentTimeMillis());
+    this.store(updateStatus);
   }
 
   public String getStatsString() {
diff --git a/src/main/java/org/torproject/onionoo/docs/UpdateStatus.java b/src/main/java/org/torproject/onionoo/docs/UpdateStatus.java
index 7bd710b..efdcf24 100644
--- a/src/main/java/org/torproject/onionoo/docs/UpdateStatus.java
+++ b/src/main/java/org/torproject/onionoo/docs/UpdateStatus.java
@@ -1,7 +1,34 @@
-/* Copyright 2013 The Tor Project
+/* Copyright 2013, 2014 The Tor Project
  * See LICENSE for licensing information */
 package org.torproject.onionoo.docs;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 public class UpdateStatus extends Document {
+
+  private static Logger log = LoggerFactory.getLogger(UpdateStatus.class);
+
+  private long updatedMillis;
+  public void setUpdatedMillis(long updatedMillis) {
+    this.updatedMillis = updatedMillis;
+  }
+  public long getUpdatedMillis() {
+    return this.updatedMillis;
+  }
+
+  public void setFromDocumentString(String documentString) {
+    try {
+      this.updatedMillis = Long.parseLong(documentString.trim());
+    } catch (NumberFormatException e) {
+      log.error("Could not parse timestamp '" + documentString + "'.  "
+          + "Setting to 1970-01-01 00:00:00.");
+      this.updatedMillis = 0L;
+    }
+  }
+
+  public String toDocumentString() {
+    return String.valueOf(this.updatedMillis);
+  }
 }
 
diff --git a/src/main/java/org/torproject/onionoo/server/NodeIndexer.java b/src/main/java/org/torproject/onionoo/server/NodeIndexer.java
index bafd442..f8870db 100644
--- a/src/main/java/org/torproject/onionoo/server/NodeIndexer.java
+++ b/src/main/java/org/torproject/onionoo/server/NodeIndexer.java
@@ -99,15 +99,9 @@ public class NodeIndexer implements ServletContextListener, Runnable {
     long updateStatusMillis = -1L;
     DocumentStore documentStore = DocumentStoreFactory.getDocumentStore();
     UpdateStatus updateStatus = documentStore.retrieve(UpdateStatus.class,
-        false);
-    if (updateStatus != null &&
-        updateStatus.getDocumentString() != null) {
-      String updateString = updateStatus.getDocumentString();
-      try {
-        updateStatusMillis = Long.parseLong(updateString.trim());
-      } catch (NumberFormatException e) {
-        /* Handle below. */
-      }
+        true);
+    if (updateStatus != null) {
+      updateStatusMillis = updateStatus.getUpdatedMillis();
     }
     synchronized (this) {
       if (updateStatusMillis <= this.lastIndexed) {
diff --git a/src/main/java/org/torproject/onionoo/updater/DescriptorSource.java b/src/main/java/org/torproject/onionoo/updater/DescriptorSource.java
index 30001f8..26b7b10 100644
--- a/src/main/java/org/torproject/onionoo/updater/DescriptorSource.java
+++ b/src/main/java/org/torproject/onionoo/updater/DescriptorSource.java
@@ -9,19 +9,10 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.torproject.descriptor.BridgeNetworkStatus;
-import org.torproject.descriptor.BridgePoolAssignment;
 import org.torproject.descriptor.Descriptor;
-import org.torproject.descriptor.ExitList;
-import org.torproject.descriptor.ExitListEntry;
-import org.torproject.descriptor.ExtraInfoDescriptor;
-import org.torproject.descriptor.RelayNetworkStatusConsensus;
-import org.torproject.descriptor.ServerDescriptor;
 import org.torproject.onionoo.util.FormattingUtils;
 
 public class DescriptorSource {
@@ -39,8 +30,6 @@ public class DescriptorSource {
     this.descriptorQueues = new ArrayList<DescriptorQueue>();
     this.descriptorListeners =
         new HashMap<DescriptorType, Set<DescriptorListener>>();
-    this.fingerprintListeners =
-        new HashMap<DescriptorType, Set<FingerprintListener>>();
   }
 
   private DescriptorQueue getDescriptorQueue(
@@ -59,9 +48,6 @@ public class DescriptorSource {
   private Map<DescriptorType, Set<DescriptorListener>>
       descriptorListeners;
 
-  private Map<DescriptorType, Set<FingerprintListener>>
-      fingerprintListeners;
-
   public void registerDescriptorListener(DescriptorListener listener,
       DescriptorType descriptorType) {
     if (!this.descriptorListeners.containsKey(descriptorType)) {
@@ -71,15 +57,6 @@ public class DescriptorSource {
     this.descriptorListeners.get(descriptorType).add(listener);
   }
 
-  public void registerFingerprintListener(FingerprintListener listener,
-      DescriptorType descriptorType) {
-    if (!this.fingerprintListeners.containsKey(descriptorType)) {
-      this.fingerprintListeners.put(descriptorType,
-          new HashSet<FingerprintListener>());
-    }
-    this.fingerprintListeners.get(descriptorType).add(listener);
-  }
-
   public void downloadDescriptors() {
     for (DescriptorType descriptorType : DescriptorType.values()) {
       log.info("Loading: " + descriptorType);
@@ -91,8 +68,7 @@ public class DescriptorSource {
       downloadedFiles = 0, deletedLocalFiles = 0;
 
   private void downloadDescriptors(DescriptorType descriptorType) {
-    if (!this.descriptorListeners.containsKey(descriptorType) &&
-        !this.fingerprintListeners.containsKey(descriptorType)) {
+    if (!this.descriptorListeners.containsKey(descriptorType)) {
       return;
     }
     DescriptorDownloader descriptorDownloader =
@@ -140,14 +116,11 @@ public class DescriptorSource {
 
   private void readDescriptors(DescriptorType descriptorType,
       DescriptorHistory descriptorHistory, boolean relay) {
-    if (!this.descriptorListeners.containsKey(descriptorType) &&
-        !this.fingerprintListeners.containsKey(descriptorType)) {
+    if (!this.descriptorListeners.containsKey(descriptorType)) {
       return;
     }
     Set<DescriptorListener> descriptorListeners =
         this.descriptorListeners.get(descriptorType);
-    Set<FingerprintListener> fingerprintListeners =
-        this.fingerprintListeners.get(descriptorType);
     DescriptorQueue descriptorQueue = this.getDescriptorQueue(
         descriptorType, descriptorHistory);
     Descriptor descriptor;
@@ -155,52 +128,6 @@ public class DescriptorSource {
       for (DescriptorListener descriptorListener : descriptorListeners) {
         descriptorListener.processDescriptor(descriptor, relay);
       }
-      if (fingerprintListeners == null) {
-        continue;
-      }
-      SortedSet<String> fingerprints = new TreeSet<String>();
-      if (descriptorType == DescriptorType.RELAY_CONSENSUSES &&
-          descriptor instanceof RelayNetworkStatusConsensus) {
-        fingerprints.addAll(((RelayNetworkStatusConsensus) descriptor).
-            getStatusEntries().keySet());
-      } else if (descriptorType
-          == DescriptorType.RELAY_SERVER_DESCRIPTORS &&
-          descriptor instanceof ServerDescriptor) {
-        fingerprints.add(((ServerDescriptor) descriptor).
-            getFingerprint());
-      } else if (descriptorType == DescriptorType.RELAY_EXTRA_INFOS &&
-          descriptor instanceof ExtraInfoDescriptor) {
-        fingerprints.add(((ExtraInfoDescriptor) descriptor).
-            getFingerprint());
-      } else if (descriptorType == DescriptorType.EXIT_LISTS &&
-          descriptor instanceof ExitList) {
-        for (ExitListEntry entry :
-            ((ExitList) descriptor).getExitListEntries()) {
-          fingerprints.add(entry.getFingerprint());
-        }
-      } else if (descriptorType == DescriptorType.BRIDGE_STATUSES &&
-          descriptor instanceof BridgeNetworkStatus) {
-        fingerprints.addAll(((BridgeNetworkStatus) descriptor).
-            getStatusEntries().keySet());
-      } else if (descriptorType ==
-          DescriptorType.BRIDGE_SERVER_DESCRIPTORS &&
-          descriptor instanceof ServerDescriptor) {
-        fingerprints.add(((ServerDescriptor) descriptor).
-            getFingerprint());
-      } else if (descriptorType == DescriptorType.BRIDGE_EXTRA_INFOS &&
-          descriptor instanceof ExtraInfoDescriptor) {
-        fingerprints.add(((ExtraInfoDescriptor) descriptor).
-            getFingerprint());
-      } else if (descriptorType ==
-          DescriptorType.BRIDGE_POOL_ASSIGNMENTS &&
-          descriptor instanceof BridgePoolAssignment) {
-        fingerprints.addAll(((BridgePoolAssignment) descriptor).
-            getEntries().keySet());
-      }
-      for (FingerprintListener fingerprintListener :
-          fingerprintListeners) {
-        fingerprintListener.processFingerprints(fingerprints, relay);
-      }
     }
     switch (descriptorType) {
     case RELAY_CONSENSUSES:
diff --git a/src/main/java/org/torproject/onionoo/updater/FingerprintListener.java b/src/main/java/org/torproject/onionoo/updater/FingerprintListener.java
deleted file mode 100644
index 5e16eae..0000000
--- a/src/main/java/org/torproject/onionoo/updater/FingerprintListener.java
+++ /dev/null
@@ -1,10 +0,0 @@
-/* Copyright 2013, 2014 The Tor Project
- * See LICENSE for licensing information */
-package org.torproject.onionoo.updater;
-
-import java.util.SortedSet;
-
-public interface FingerprintListener {
-  abstract void processFingerprints(SortedSet<String> fingerprints,
-      boolean relay);
-}
\ No newline at end of file
diff --git a/src/main/java/org/torproject/onionoo/writer/BandwidthDocumentWriter.java b/src/main/java/org/torproject/onionoo/writer/BandwidthDocumentWriter.java
index c5167d0..9bad965 100644
--- a/src/main/java/org/torproject/onionoo/writer/BandwidthDocumentWriter.java
+++ b/src/main/java/org/torproject/onionoo/writer/BandwidthDocumentWriter.java
@@ -3,11 +3,9 @@
 package org.torproject.onionoo.writer;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
 
@@ -19,47 +17,31 @@ import org.torproject.onionoo.docs.DateTimeHelper;
 import org.torproject.onionoo.docs.DocumentStore;
 import org.torproject.onionoo.docs.DocumentStoreFactory;
 import org.torproject.onionoo.docs.GraphHistory;
-import org.torproject.onionoo.updater.DescriptorSource;
-import org.torproject.onionoo.updater.DescriptorSourceFactory;
-import org.torproject.onionoo.updater.DescriptorType;
-import org.torproject.onionoo.updater.FingerprintListener;
+import org.torproject.onionoo.docs.UpdateStatus;
 import org.torproject.onionoo.util.TimeFactory;
 
-public class BandwidthDocumentWriter implements FingerprintListener,
-    DocumentWriter{
+public class BandwidthDocumentWriter implements DocumentWriter {
 
   private static final Logger log = LoggerFactory.getLogger(
       BandwidthDocumentWriter.class);
 
-  private DescriptorSource descriptorSource;
-
   private DocumentStore documentStore;
 
   private long now;
 
   public BandwidthDocumentWriter() {
-    this.descriptorSource = DescriptorSourceFactory.getDescriptorSource();
     this.documentStore = DocumentStoreFactory.getDocumentStore();
     this.now = TimeFactory.getTime().currentTimeMillis();
-    this.registerFingerprintListeners();
-  }
-
-  private void registerFingerprintListeners() {
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.RELAY_EXTRA_INFOS);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.BRIDGE_EXTRA_INFOS);
-  }
-
-  private Set<String> updateBandwidthDocuments = new HashSet<String>();
-
-  public void processFingerprints(SortedSet<String> fingerprints,
-      boolean relay) {
-    this.updateBandwidthDocuments.addAll(fingerprints);
   }
 
   public void writeDocuments() {
-    for (String fingerprint : this.updateBandwidthDocuments) {
+    UpdateStatus updateStatus = this.documentStore.retrieve(
+        UpdateStatus.class, true);
+    long updatedMillis = updateStatus != null ?
+        updateStatus.getUpdatedMillis() : 0L;
+    SortedSet<String> updateBandwidthDocuments = this.documentStore.list(
+        BandwidthStatus.class, updatedMillis);
+    for (String fingerprint : updateBandwidthDocuments) {
       BandwidthStatus bandwidthStatus = this.documentStore.retrieve(
           BandwidthStatus.class, true, fingerprint);
       if (bandwidthStatus == null) {
diff --git a/src/main/java/org/torproject/onionoo/writer/ClientsDocumentWriter.java b/src/main/java/org/torproject/onionoo/writer/ClientsDocumentWriter.java
index 4086bc7..885494c 100644
--- a/src/main/java/org/torproject/onionoo/writer/ClientsDocumentWriter.java
+++ b/src/main/java/org/torproject/onionoo/writer/ClientsDocumentWriter.java
@@ -9,7 +9,6 @@ import java.util.Map;
 import java.util.SortedMap;
 import java.util.SortedSet;
 import java.util.TreeMap;
-import java.util.TreeSet;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -20,10 +19,7 @@ import org.torproject.onionoo.docs.ClientsStatus;
 import org.torproject.onionoo.docs.DateTimeHelper;
 import org.torproject.onionoo.docs.DocumentStore;
 import org.torproject.onionoo.docs.DocumentStoreFactory;
-import org.torproject.onionoo.updater.DescriptorSource;
-import org.torproject.onionoo.updater.DescriptorSourceFactory;
-import org.torproject.onionoo.updater.DescriptorType;
-import org.torproject.onionoo.updater.FingerprintListener;
+import org.torproject.onionoo.docs.UpdateStatus;
 import org.torproject.onionoo.util.FormattingUtils;
 import org.torproject.onionoo.util.TimeFactory;
 
@@ -50,43 +46,30 @@ import org.torproject.onionoo.util.TimeFactory;
  *   "transports":{"obfs2":0.4581},
  *   "versions":{"v4":1.0000}}
  */
-public class ClientsDocumentWriter implements FingerprintListener,
-    DocumentWriter {
+public class ClientsDocumentWriter implements DocumentWriter {
 
   private final static Logger log = LoggerFactory.getLogger(
       ClientsDocumentWriter.class);
 
-  private DescriptorSource descriptorSource;
-
   private DocumentStore documentStore;
 
   private long now;
 
   public ClientsDocumentWriter() {
-    this.descriptorSource = DescriptorSourceFactory.getDescriptorSource();
     this.documentStore = DocumentStoreFactory.getDocumentStore();
     this.now = TimeFactory.getTime().currentTimeMillis();
-    this.registerFingerprintListeners();
-  }
-
-  private void registerFingerprintListeners() {
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.BRIDGE_EXTRA_INFOS);
-  }
-
-  private SortedSet<String> updateDocuments = new TreeSet<String>();
-
-  public void processFingerprints(SortedSet<String> fingerprints,
-      boolean relay) {
-    if (!relay) {
-      this.updateDocuments.addAll(fingerprints);
-    }
   }
 
   private int writtenDocuments = 0;
 
   public void writeDocuments() {
-    for (String hashedFingerprint : this.updateDocuments) {
+    UpdateStatus updateStatus = this.documentStore.retrieve(
+        UpdateStatus.class, true);
+    long updatedMillis = updateStatus != null ?
+        updateStatus.getUpdatedMillis() : 0L;
+    SortedSet<String> updateDocuments = this.documentStore.list(
+        ClientsStatus.class, updatedMillis);
+    for (String hashedFingerprint : updateDocuments) {
       ClientsStatus clientsStatus = this.documentStore.retrieve(
           ClientsStatus.class, true, hashedFingerprint);
       if (clientsStatus == null) {
diff --git a/src/main/java/org/torproject/onionoo/writer/DetailsDocumentWriter.java b/src/main/java/org/torproject/onionoo/writer/DetailsDocumentWriter.java
index 47b7c79..0692070 100644
--- a/src/main/java/org/torproject/onionoo/writer/DetailsDocumentWriter.java
+++ b/src/main/java/org/torproject/onionoo/writer/DetailsDocumentWriter.java
@@ -16,59 +16,55 @@ import org.torproject.onionoo.docs.DetailsStatus;
 import org.torproject.onionoo.docs.DocumentStore;
 import org.torproject.onionoo.docs.DocumentStoreFactory;
 import org.torproject.onionoo.docs.NodeStatus;
-import org.torproject.onionoo.updater.DescriptorSource;
-import org.torproject.onionoo.updater.DescriptorSourceFactory;
-import org.torproject.onionoo.updater.DescriptorType;
-import org.torproject.onionoo.updater.FingerprintListener;
+import org.torproject.onionoo.docs.UpdateStatus;
 import org.torproject.onionoo.util.TimeFactory;
 
-public class DetailsDocumentWriter implements FingerprintListener,
-    DocumentWriter {
+public class DetailsDocumentWriter implements DocumentWriter {
 
   private final static Logger log = LoggerFactory.getLogger(
       DetailsDocumentWriter.class);
 
-  private DescriptorSource descriptorSource;
-
   private DocumentStore documentStore;
 
   private long now;
 
   public DetailsDocumentWriter() {
-    this.descriptorSource = DescriptorSourceFactory.getDescriptorSource();
     this.documentStore = DocumentStoreFactory.getDocumentStore();
     this.now = TimeFactory.getTime().currentTimeMillis();
-    this.registerFingerprintListeners();
-  }
-
-  private void registerFingerprintListeners() {
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.RELAY_CONSENSUSES);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.RELAY_SERVER_DESCRIPTORS);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.BRIDGE_STATUSES);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.BRIDGE_SERVER_DESCRIPTORS);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.BRIDGE_POOL_ASSIGNMENTS);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.EXIT_LISTS);
   }
 
   private SortedSet<String> newRelays = new TreeSet<String>(),
       newBridges = new TreeSet<String>();
 
-  public void processFingerprints(SortedSet<String> fingerprints,
-      boolean relay) {
-    if (relay) {
-      this.newRelays.addAll(fingerprints);
-    } else {
-      this.newBridges.addAll(fingerprints);
-    }
-  }
-
   public void writeDocuments() {
+    UpdateStatus updateStatus = this.documentStore.retrieve(
+        UpdateStatus.class, true);
+    long updatedMillis = updateStatus != null ?
+        updateStatus.getUpdatedMillis() : 0L;
+    SortedSet<String> updatedNodeStatuses = this.documentStore.list(
+        NodeStatus.class, updatedMillis);
+    for (String fingerprint : updatedNodeStatuses) {
+      NodeStatus nodeStatus = this.documentStore.retrieve(
+          NodeStatus.class, true, fingerprint);
+      if (nodeStatus.isRelay()) {
+        newRelays.add(fingerprint);
+      } else {
+        newBridges.add(fingerprint);
+      }
+    }
+    SortedSet<String> updatedDetailsStatuses = this.documentStore.list(
+        DetailsStatus.class, updatedMillis);
+    for (String fingerprint : updatedDetailsStatuses) {
+      NodeStatus nodeStatus = this.documentStore.retrieve(
+          NodeStatus.class, true, fingerprint);
+      if (nodeStatus == null) {
+        continue;
+      } else if (nodeStatus.isRelay()) {
+        newRelays.add(fingerprint);
+      } else {
+        newBridges.add(fingerprint);
+      }
+    }
     this.updateRelayDetailsFiles();
     this.updateBridgeDetailsFiles();
     log.info("Wrote details document files");
diff --git a/src/main/java/org/torproject/onionoo/writer/UptimeDocumentWriter.java b/src/main/java/org/torproject/onionoo/writer/UptimeDocumentWriter.java
index 973fa67..093bc98 100644
--- a/src/main/java/org/torproject/onionoo/writer/UptimeDocumentWriter.java
+++ b/src/main/java/org/torproject/onionoo/writer/UptimeDocumentWriter.java
@@ -7,7 +7,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.SortedSet;
-import java.util.TreeSet;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -15,52 +14,25 @@ import org.torproject.onionoo.docs.DateTimeHelper;
 import org.torproject.onionoo.docs.DocumentStore;
 import org.torproject.onionoo.docs.DocumentStoreFactory;
 import org.torproject.onionoo.docs.GraphHistory;
+import org.torproject.onionoo.docs.UpdateStatus;
 import org.torproject.onionoo.docs.UptimeDocument;
 import org.torproject.onionoo.docs.UptimeHistory;
 import org.torproject.onionoo.docs.UptimeStatus;
-import org.torproject.onionoo.updater.DescriptorSource;
-import org.torproject.onionoo.updater.DescriptorSourceFactory;
-import org.torproject.onionoo.updater.DescriptorType;
-import org.torproject.onionoo.updater.FingerprintListener;
 import org.torproject.onionoo.util.FormattingUtils;
 import org.torproject.onionoo.util.TimeFactory;
 
-public class UptimeDocumentWriter implements FingerprintListener,
-    DocumentWriter {
+public class UptimeDocumentWriter implements DocumentWriter {
 
   private final static Logger log = LoggerFactory.getLogger(
       UptimeDocumentWriter.class);
 
-  private DescriptorSource descriptorSource;
-
   private DocumentStore documentStore;
 
   private long now;
 
   public UptimeDocumentWriter() {
-    this.descriptorSource = DescriptorSourceFactory.getDescriptorSource();
     this.documentStore = DocumentStoreFactory.getDocumentStore();
     this.now = TimeFactory.getTime().currentTimeMillis();
-    this.registerFingerprintListeners();
-  }
-
-  private void registerFingerprintListeners() {
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.RELAY_CONSENSUSES);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.BRIDGE_STATUSES);
-  }
-
-  private SortedSet<String> newRelayFingerprints = new TreeSet<String>(),
-      newBridgeFingerprints = new TreeSet<String>();
-
-  public void processFingerprints(SortedSet<String> fingerprints,
-      boolean relay) {
-    if (relay) {
-      this.newRelayFingerprints.addAll(fingerprints);
-    } else {
-      this.newBridgeFingerprints.addAll(fingerprints);
-    }
   }
 
   public void writeDocuments() {
@@ -69,29 +41,34 @@ public class UptimeDocumentWriter implements FingerprintListener,
     if (uptimeStatus == null) {
       return;
     }
-    for (String fingerprint : this.newRelayFingerprints) {
-      this.updateDocument(true, fingerprint,
-          uptimeStatus.getRelayHistory());
-    }
-    for (String fingerprint : this.newBridgeFingerprints) {
-      this.updateDocument(false, fingerprint,
-          uptimeStatus.getBridgeHistory());
+    UpdateStatus updateStatus = this.documentStore.retrieve(
+        UpdateStatus.class, true);
+    long updatedMillis = updateStatus != null ?
+        updateStatus.getUpdatedMillis() : 0L;
+    SortedSet<String> updatedUptimeStatuses = this.documentStore.list(
+        UptimeStatus.class, updatedMillis);
+    for (String fingerprint : updatedUptimeStatuses) {
+      this.updateDocument(fingerprint, uptimeStatus);
     }
     log.info("Wrote uptime document files");
   }
 
   private int writtenDocuments = 0;
 
-  private void updateDocument(boolean relay, String fingerprint,
-      SortedSet<UptimeHistory> knownStatuses) {
+  private void updateDocument(String fingerprint,
+      UptimeStatus knownStatuses) {
     UptimeStatus uptimeStatus = this.documentStore.retrieve(
         UptimeStatus.class, true, fingerprint);
     if (uptimeStatus != null) {
+      boolean relay = uptimeStatus.getBridgeHistory().isEmpty();
       SortedSet<UptimeHistory> history = relay
           ? uptimeStatus.getRelayHistory()
           : uptimeStatus.getBridgeHistory();
+      SortedSet<UptimeHistory> knownStatusesHistory = relay
+          ? knownStatuses.getRelayHistory()
+          : knownStatuses.getBridgeHistory();
       UptimeDocument uptimeDocument = this.compileUptimeDocument(relay,
-          fingerprint, history, knownStatuses);
+          fingerprint, history, knownStatusesHistory);
       this.documentStore.store(uptimeDocument, fingerprint);
       this.writtenDocuments++;
     }
diff --git a/src/main/java/org/torproject/onionoo/writer/WeightsDocumentWriter.java b/src/main/java/org/torproject/onionoo/writer/WeightsDocumentWriter.java
index 00c529e..7d52a47 100644
--- a/src/main/java/org/torproject/onionoo/writer/WeightsDocumentWriter.java
+++ b/src/main/java/org/torproject/onionoo/writer/WeightsDocumentWriter.java
@@ -3,11 +3,9 @@
 package org.torproject.onionoo.writer;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.SortedMap;
 import java.util.SortedSet;
 
@@ -17,56 +15,33 @@ import org.torproject.onionoo.docs.DateTimeHelper;
 import org.torproject.onionoo.docs.DocumentStore;
 import org.torproject.onionoo.docs.DocumentStoreFactory;
 import org.torproject.onionoo.docs.GraphHistory;
+import org.torproject.onionoo.docs.UpdateStatus;
 import org.torproject.onionoo.docs.WeightsDocument;
 import org.torproject.onionoo.docs.WeightsStatus;
-import org.torproject.onionoo.updater.DescriptorSource;
-import org.torproject.onionoo.updater.DescriptorSourceFactory;
-import org.torproject.onionoo.updater.DescriptorType;
-import org.torproject.onionoo.updater.FingerprintListener;
 import org.torproject.onionoo.util.TimeFactory;
 
-public class WeightsDocumentWriter implements FingerprintListener,
-    DocumentWriter {
+public class WeightsDocumentWriter implements DocumentWriter {
 
   private final static Logger log = LoggerFactory.getLogger(
       WeightsDocumentWriter.class);
 
-  private DescriptorSource descriptorSource;
-
   private DocumentStore documentStore;
 
   private long now;
 
   public WeightsDocumentWriter() {
-    this.descriptorSource = DescriptorSourceFactory.getDescriptorSource();
     this.documentStore = DocumentStoreFactory.getDocumentStore();
     this.now = TimeFactory.getTime().currentTimeMillis();
-    this.registerFingerprintListeners();
-  }
-
-  private void registerFingerprintListeners() {
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.RELAY_CONSENSUSES);
-    this.descriptorSource.registerFingerprintListener(this,
-        DescriptorType.RELAY_SERVER_DESCRIPTORS);
-  }
-
-  private Set<String> updateWeightsDocuments = new HashSet<String>();
-
-  public void processFingerprints(SortedSet<String> fingerprints,
-      boolean relay) {
-    if (relay) {
-      this.updateWeightsDocuments.addAll(fingerprints);
-    }
   }
 
   public void writeDocuments() {
-    this.writeWeightsDataFiles();
-    log.info("Wrote weights document files");
-  }
-
-  private void writeWeightsDataFiles() {
-    for (String fingerprint : this.updateWeightsDocuments) {
+    UpdateStatus updateStatus = this.documentStore.retrieve(
+        UpdateStatus.class, true);
+    long updatedMillis = updateStatus != null ?
+        updateStatus.getUpdatedMillis() : 0L;
+    SortedSet<String> updateWeightsDocuments = this.documentStore.list(
+        WeightsStatus.class, updatedMillis);
+    for (String fingerprint : updateWeightsDocuments) {
       WeightsStatus weightsStatus = this.documentStore.retrieve(
           WeightsStatus.class, true, fingerprint);
       if (weightsStatus == null) {
diff --git a/src/test/java/org/torproject/onionoo/DummyDescriptorSource.java b/src/test/java/org/torproject/onionoo/DummyDescriptorSource.java
index e93b063..4dbf066 100644
--- a/src/test/java/org/torproject/onionoo/DummyDescriptorSource.java
+++ b/src/test/java/org/torproject/onionoo/DummyDescriptorSource.java
@@ -5,14 +5,11 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
 
 import org.torproject.descriptor.Descriptor;
 import org.torproject.onionoo.updater.DescriptorListener;
 import org.torproject.onionoo.updater.DescriptorSource;
 import org.torproject.onionoo.updater.DescriptorType;
-import org.torproject.onionoo.updater.FingerprintListener;
 
 public class DummyDescriptorSource extends DescriptorSource {
 
@@ -39,27 +36,6 @@ public class DummyDescriptorSource extends DescriptorSource {
     return this.descriptors.get(descriptorType);
   }
 
-  private Map<DescriptorType, SortedSet<String>> fingerprints =
-      new HashMap<DescriptorType, SortedSet<String>>();
-
-  public void addFingerprints(DescriptorType descriptorType,
-      Collection<String> fingerprints) {
-    this.getFingerprintsByType(descriptorType).addAll(fingerprints);
-  }
-
-  public void addFingerprint(DescriptorType descriptorType,
-      String fingerprint) {
-    this.getFingerprintsByType(descriptorType).add(fingerprint);
-  }
-
-  private SortedSet<String> getFingerprintsByType(
-      DescriptorType descriptorType) {
-    if (!this.fingerprints.containsKey(descriptorType)) {
-      this.fingerprints.put(descriptorType, new TreeSet<String>());
-    }
-    return this.fingerprints.get(descriptorType);
-  }
-
   private Map<DescriptorType, Set<DescriptorListener>>
       descriptorListeners = new HashMap<DescriptorType,
       Set<DescriptorListener>>();
@@ -73,23 +49,9 @@ public class DummyDescriptorSource extends DescriptorSource {
     this.descriptorListeners.get(descriptorType).add(listener);
   }
 
-  private Map<DescriptorType, Set<FingerprintListener>>
-      fingerprintListeners = new HashMap<DescriptorType,
-      Set<FingerprintListener>>();
-
-  public void registerFingerprintListener(FingerprintListener listener,
-      DescriptorType descriptorType) {
-    if (!this.fingerprintListeners.containsKey(descriptorType)) {
-      this.fingerprintListeners.put(descriptorType,
-          new HashSet<FingerprintListener>());
-    }
-    this.fingerprintListeners.get(descriptorType).add(listener);
-  }
-
   public void readDescriptors() {
     Set<DescriptorType> descriptorTypes = new HashSet<DescriptorType>();
     descriptorTypes.addAll(this.descriptorListeners.keySet());
-    descriptorTypes.addAll(this.fingerprintListeners.keySet());
     for (DescriptorType descriptorType : descriptorTypes) {
       boolean relay;
       switch (descriptorType) {
@@ -118,15 +80,6 @@ public class DummyDescriptorSource extends DescriptorSource {
           }
         }
       }
-      if (this.fingerprints.containsKey(descriptorType) &&
-          this.fingerprintListeners.containsKey(descriptorType)) {
-        Set<FingerprintListener> listeners =
-            this.fingerprintListeners.get(descriptorType);
-        for (FingerprintListener listener : listeners) {
-          listener.processFingerprints(this.getFingerprintsByType(
-              descriptorType), relay);
-        }
-      }
     }
   }
 
diff --git a/src/test/java/org/torproject/onionoo/DummyDocumentStore.java b/src/test/java/org/torproject/onionoo/DummyDocumentStore.java
index 54311aa..f5601b0 100644
--- a/src/test/java/org/torproject/onionoo/DummyDocumentStore.java
+++ b/src/test/java/org/torproject/onionoo/DummyDocumentStore.java
@@ -54,10 +54,17 @@ public class DummyDocumentStore extends DocumentStore {
   }
 
   public <T extends Document> SortedSet<String> list(
+      Class<T> documentType, long modifiedAfter) {
+    return this.list(documentType);
+  }
+
+  public <T extends Document> SortedSet<String> list(
       Class<T> documentType) {
     this.performedListOperations++;
-    return new TreeSet<String>(this.getStoredDocumentsByClass(
-        documentType).keySet());
+    SortedSet<String> fingerprints = new TreeSet<String>(
+        this.getStoredDocumentsByClass(documentType).keySet());
+    fingerprints.remove(FINGERPRINT_NULL);
+    return fingerprints;
   }
 
   private int performedRemoveOperations = 0;
diff --git a/src/test/java/org/torproject/onionoo/ResourceServletTest.java b/src/test/java/org/torproject/onionoo/ResourceServletTest.java
index 1631661..cc48295 100644
--- a/src/test/java/org/torproject/onionoo/ResourceServletTest.java
+++ b/src/test/java/org/torproject/onionoo/ResourceServletTest.java
@@ -210,8 +210,7 @@ public class ResourceServletTest {
   private void createDummyDocumentStore() {
     DummyDocumentStore documentStore = new DummyDocumentStore();
     UpdateStatus updateStatus = new UpdateStatus();
-    updateStatus.setDocumentString(String.valueOf(
-        this.currentTimeMillis));
+    updateStatus.setUpdatedMillis(this.currentTimeMillis);
     documentStore.addDocument(updateStatus, null);
     for (Map.Entry<String, org.torproject.onionoo.docs.SummaryDocument> e :
         this.relays.entrySet()) {
diff --git a/src/test/java/org/torproject/onionoo/UptimeDocumentWriterTest.java b/src/test/java/org/torproject/onionoo/UptimeDocumentWriterTest.java
index 9b19e79..8f7fff0 100644
--- a/src/test/java/org/torproject/onionoo/UptimeDocumentWriterTest.java
+++ b/src/test/java/org/torproject/onionoo/UptimeDocumentWriterTest.java
@@ -16,7 +16,6 @@ import org.torproject.onionoo.docs.GraphHistory;
 import org.torproject.onionoo.docs.UptimeDocument;
 import org.torproject.onionoo.docs.UptimeStatus;
 import org.torproject.onionoo.updater.DescriptorSourceFactory;
-import org.torproject.onionoo.updater.DescriptorType;
 import org.torproject.onionoo.util.TimeFactory;
 import org.torproject.onionoo.writer.UptimeDocumentWriter;
 
@@ -71,8 +70,6 @@ public class UptimeDocumentWriterTest {
     status = new UptimeStatus();
     status.setFromDocumentString(gabelmooUptime);
     this.documentStore.addDocument(status, GABELMOO_FINGERPRINT);
-    this.descriptorSource.addFingerprint(DescriptorType.RELAY_CONSENSUSES,
-        GABELMOO_FINGERPRINT);
   }
 
   private static final long ONE_SECOND = 1000L,





More information about the tor-commits mailing list