From 8f9369ec5ffc98c3404583de1757c200a969378f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Simon=20K=C3=B6nnecke?= <simonkoennecke@gmail.com>
Date: Fri, 8 Jul 2016 13:42:53 +0200
Subject: [PATCH] snapshot based histograms

---
 .gitignore                                    |  1 +
 pom.xml                                       |  6 ++
 .../control/ActionWalletGetSnapshot.java      | 25 ++++++
 .../ActionWalletGetSnapshotAnswer.java        | 32 +++++++
 .../MassWalletConfiguration.java              |  2 +-
 .../java/fucoin/gui/SuperVisorGraphGUI.java   | 22 +++--
 .../fucoin/gui/SuperVisorGuiControlImpl.java  | 37 +++++---
 .../fucoin/gui/SuperVisorHistogramGUI.java    | 87 +++++++++++++++++++
 .../java/fucoin/gui/SuperVisorThreadGUI.java  | 13 ++-
 .../java/fucoin/wallet/AbstractWallet.java    |  2 +-
 src/main/java/fucoin/wallet/Snapshot.java     | 18 +++-
 11 files changed, 217 insertions(+), 28 deletions(-)
 create mode 100644 src/main/java/fucoin/actions/control/ActionWalletGetSnapshot.java
 create mode 100644 src/main/java/fucoin/actions/control/ActionWalletGetSnapshotAnswer.java
 create mode 100644 src/main/java/fucoin/gui/SuperVisorHistogramGUI.java

diff --git a/.gitignore b/.gitignore
index 064cdbf..02efb3d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 .idea/
 *.iml
 .DS_Store
+snapshots
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c923f4a..6d59532 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,6 +62,12 @@
             <artifactId>jgraphx</artifactId>
             <version>1.10.1.3</version>
         </dependency>
+        <!-- https://mvnrepository.com/artifact/org.jfree/jfreechart -->
+        <dependency>
+            <groupId>org.jfree</groupId>
+            <artifactId>jfreechart</artifactId>
+            <version>1.0.14</version>
+        </dependency>
         <dependency>
             <groupId>it.unimi.dsi</groupId>
             <artifactId>fastutil</artifactId>
diff --git a/src/main/java/fucoin/actions/control/ActionWalletGetSnapshot.java b/src/main/java/fucoin/actions/control/ActionWalletGetSnapshot.java
new file mode 100644
index 0000000..d300739
--- /dev/null
+++ b/src/main/java/fucoin/actions/control/ActionWalletGetSnapshot.java
@@ -0,0 +1,25 @@
+package fucoin.actions.control;
+
+import akka.actor.ActorRef;
+import akka.actor.UntypedActorContext;
+import fucoin.actions.ClientAction;
+import fucoin.wallet.AbstractWallet;
+
+import java.time.LocalDateTime;
+
+/**
+ * Ask Wallet x for his known neighbours.
+ */
+public class ActionWalletGetSnapshot extends ClientAction {
+
+    private final LocalDateTime time;
+
+    public ActionWalletGetSnapshot(LocalDateTime time) {
+        this.time = time;
+    }
+
+    @Override
+    protected void onAction(ActorRef sender, ActorRef self, UntypedActorContext context, AbstractWallet abstractNode) {
+        sender.tell(new ActionWalletGetSnapshotAnswer(abstractNode, time), self);
+    }
+}
diff --git a/src/main/java/fucoin/actions/control/ActionWalletGetSnapshotAnswer.java b/src/main/java/fucoin/actions/control/ActionWalletGetSnapshotAnswer.java
new file mode 100644
index 0000000..00cf807
--- /dev/null
+++ b/src/main/java/fucoin/actions/control/ActionWalletGetSnapshotAnswer.java
@@ -0,0 +1,32 @@
+package fucoin.actions.control;
+
+import akka.actor.ActorRef;
+import akka.actor.UntypedActorContext;
+import fucoin.actions.ClientAction;
+import fucoin.wallet.AbstractWallet;
+import fucoin.wallet.Snapshot;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+
+/**
+ * Tell
+ */
+public class ActionWalletGetSnapshotAnswer extends ClientAction {
+
+    private final Snapshot snapshot;
+
+
+    public ActionWalletGetSnapshotAnswer(AbstractWallet wallet, LocalDateTime time) {
+        snapshot = wallet.readSnapShot(time);
+    }
+
+    @Override
+    protected void onAction(ActorRef sender, ActorRef self, UntypedActorContext context, AbstractWallet abstractNode) {
+
+    }
+
+    public Snapshot getSnapshot() {
+        return snapshot;
+    }
+}
diff --git a/src/main/java/fucoin/configurations/MassWalletConfiguration.java b/src/main/java/fucoin/configurations/MassWalletConfiguration.java
index 3ea5b48..9095a9f 100644
--- a/src/main/java/fucoin/configurations/MassWalletConfiguration.java
+++ b/src/main/java/fucoin/configurations/MassWalletConfiguration.java
@@ -12,7 +12,7 @@ public class MassWalletConfiguration extends AbstractConfiguration {
     public void run() {
         //Config
         remainingWalletsToSpawn = 5;
-        remainingTransactions = 100;
+        remainingTransactions = 10;
 
         //Start SuperVisor
         initSupervisor();
diff --git a/src/main/java/fucoin/gui/SuperVisorGraphGUI.java b/src/main/java/fucoin/gui/SuperVisorGraphGUI.java
index 4ef3e87..70e960e 100644
--- a/src/main/java/fucoin/gui/SuperVisorGraphGUI.java
+++ b/src/main/java/fucoin/gui/SuperVisorGraphGUI.java
@@ -1,18 +1,21 @@
 package fucoin.gui;
 
-import akka.actor.ActorRef;
 import com.mxgraph.swing.mxGraphComponent;
 import com.mxgraph.view.mxGraph;
+import fucoin.wallet.Snapshot;
 
 import javax.swing.*;
-import java.util.*;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Vector;
 
 /**
  *
  */
 public class SuperVisorGraphGUI extends JFrame {
 
-    private SuperVisorGuiControlImpl superVisorGuiControl;
+    private final SuperVisorGuiControlImpl superVisorGuiControl;
+    private final LocalDateTime time;
 
     private static final int width = 1200;
     private static final int height = 800;
@@ -23,9 +26,10 @@ public class SuperVisorGraphGUI extends JFrame {
 
     private HashMap<String, Object> vertex = new HashMap<>();
 
-    public SuperVisorGraphGUI(SuperVisorGuiControlImpl superVisorGuiControl) {
-        super("Distributed Network Graph");
+    public SuperVisorGraphGUI(SuperVisorGuiControlImpl superVisorGuiControl, LocalDateTime time) {
+        super("Distributed Network Graph (Snapshot: " + time + ")");
         this.superVisorGuiControl = superVisorGuiControl;
+        this.time = time;
         setVisible(true);
         setSize(width, height);
     }
@@ -51,10 +55,10 @@ public class SuperVisorGraphGUI extends JFrame {
                 }
             }
 
-            for (Map.Entry<String, HashMap<String, ActorRef>> item1 :
-                    superVisorGuiControl.getNodeNeighbourList().entrySet()) {
-                for (Map.Entry<String, ActorRef> item2: item1.getValue().entrySet()) {
-                    graph.insertEdge(parent, null, "", vertex.get(item1.getKey()), vertex.get(item2.getKey()));
+            for (Snapshot item1 :
+                    superVisorGuiControl.getSnapshots()) {
+                for (String item2 : item1.getKnownNeighbour()) {
+                    graph.insertEdge(parent, null, "", vertex.get(item1.getName()), vertex.get(item2));
                 }
             }
         } finally {
diff --git a/src/main/java/fucoin/gui/SuperVisorGuiControlImpl.java b/src/main/java/fucoin/gui/SuperVisorGuiControlImpl.java
index ca7526e..64e7f91 100644
--- a/src/main/java/fucoin/gui/SuperVisorGuiControlImpl.java
+++ b/src/main/java/fucoin/gui/SuperVisorGuiControlImpl.java
@@ -4,17 +4,18 @@ import akka.actor.ActorRef;
 import akka.pattern.Patterns;
 import akka.util.Timeout;
 import fucoin.actions.control.ActionWalletCreateSnapshot;
-import fucoin.actions.control.ActionWalletGetNeighbours;
-import fucoin.actions.control.ActionWalletGetNeighboursAnswer;
+import fucoin.actions.control.ActionWalletGetSnapshot;
+import fucoin.actions.control.ActionWalletGetSnapshotAnswer;
 import fucoin.supervisor.AmountTableModel;
 import fucoin.supervisor.SuperVisorImpl;
+import fucoin.wallet.Snapshot;
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
 
 import java.time.LocalDateTime;
-import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
 public class SuperVisorGuiControlImpl implements SuperVisorGuiControl {
@@ -22,14 +23,16 @@ public class SuperVisorGuiControlImpl implements SuperVisorGuiControl {
 
     private AmountTableModel amountTableModel;
 
-    private HashMap<String, HashMap<String, ActorRef>> nodeNeighbours = new HashMap<>();
+    private List<Snapshot> loadedSnapshotsOfWallets = new LinkedList<>();
 
     private LinkedList<LocalDateTime> snapshotTimes = new LinkedList<>();
+    private LocalDateTime loadedSnapshotDateTime;
 
     private SuperVisorThreadGUI threadGUI;
 
     private boolean logActive = false;
 
+
     public SuperVisorGuiControlImpl(SuperVisorImpl sv) {
         superVisor = sv;
         init();
@@ -52,27 +55,35 @@ public class SuperVisorGuiControlImpl implements SuperVisorGuiControl {
         }
     }
 
-    public void updateNodeNeighbourList() {
+    public void loadSnapshot(LocalDateTime time) {
+        if (loadedSnapshotDateTime != null &&
+                loadedSnapshotDateTime.equals(time) &&
+                loadedSnapshotsOfWallets.size() > 0) {
+            return;
+        }
+
+        loadedSnapshotsOfWallets.clear();
+        loadedSnapshotDateTime = time;
+
         try {
             Timeout timeout = new Timeout(Duration.create(10, "seconds"));
-
             for (Map.Entry<String, ActorRef> item : superVisor.getKnownNeighbors().entrySet()) {
-                Future<Object> futureNeighbour = Patterns.ask(item.getValue(), new ActionWalletGetNeighbours(), timeout);
-                ActionWalletGetNeighboursAnswer neighboursAnswer = (ActionWalletGetNeighboursAnswer)
+                Future<Object> futureNeighbour = Patterns.ask(item.getValue(), new ActionWalletGetSnapshot(time), timeout);
+                ActionWalletGetSnapshotAnswer snapshot = (ActionWalletGetSnapshotAnswer)
                         Await.result(futureNeighbour, timeout.duration());
-                addNodeNeighbourList(item.getKey(), neighboursAnswer.getNeighbour());
+                addSnapshot(snapshot.getSnapshot());
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
-    public void addNodeNeighbourList(String name, HashMap<String, ActorRef> list) {
-        nodeNeighbours.put(name, list);
+    public void addSnapshot(Snapshot snapshot) {
+        loadedSnapshotsOfWallets.add(snapshot);
     }
 
-    public HashMap<String, HashMap<String, ActorRef>> getNodeNeighbourList() {
-        return nodeNeighbours;
+    public List<Snapshot> getSnapshots() {
+        return loadedSnapshotsOfWallets;
     }
 
     public void guiTerminated() {
diff --git a/src/main/java/fucoin/gui/SuperVisorHistogramGUI.java b/src/main/java/fucoin/gui/SuperVisorHistogramGUI.java
new file mode 100644
index 0000000..841c32a
--- /dev/null
+++ b/src/main/java/fucoin/gui/SuperVisorHistogramGUI.java
@@ -0,0 +1,87 @@
+package fucoin.gui;
+
+import fucoin.wallet.QDigest;
+import fucoin.wallet.Snapshot;
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.IntervalMarker;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.data.xy.IntervalXYDataset;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import org.jfree.ui.Layer;
+import org.jfree.ui.RectangleAnchor;
+import org.jfree.ui.TextAnchor;
+
+import javax.swing.*;
+import java.awt.*;
+import java.time.LocalDateTime;
+
+/**
+ *
+ */
+public class SuperVisorHistogramGUI extends JFrame {
+
+    private final SuperVisorGuiControlImpl superVisorGuiControl;
+    private final LocalDateTime time;
+
+    private static final int width = 1200;
+    private static final int height = 800;
+
+
+    public SuperVisorHistogramGUI(SuperVisorGuiControlImpl superVisorGuiControl, LocalDateTime time) {
+        super("Histogram of distributed granted commit (Snapshot " + time + ")");
+        this.superVisorGuiControl = superVisorGuiControl;
+        this.time = time;
+
+        setVisible(true);
+        setSize(width, height);
+    }
+
+    private JFreeChart createChart(IntervalXYDataset dataset) {
+        final JFreeChart chart = ChartFactory.createXYBarChart(
+                "",
+                "Transaction size [FUCoins]",
+                false,
+                "Frequency",
+                dataset,
+                PlotOrientation.VERTICAL,
+                true,
+                true,
+                false
+        );
+        XYPlot plot = (XYPlot) chart.getPlot();
+        final IntervalMarker target = new IntervalMarker(400.0, 700.0);
+        target.setLabel("Target Range");
+        target.setLabelFont(new Font("SansSerif", Font.ITALIC, 11));
+        target.setLabelAnchor(RectangleAnchor.LEFT);
+        target.setLabelTextAnchor(TextAnchor.CENTER_LEFT);
+        target.setPaint(new Color(222, 222, 255, 128));
+        plot.addRangeMarker(target, Layer.BACKGROUND);
+        return chart;
+    }
+
+    public void init() {
+        QDigest qDigest = null;
+        for (Snapshot item : superVisorGuiControl.getSnapshots()) {
+            if (qDigest == null) {
+                qDigest = item.getqDigest();
+            } else {
+                qDigest = QDigest.unionOf(qDigest, item.getqDigest());
+            }
+        }
+
+        final XYSeries series = new XYSeries("Transactions");
+        for (long[] item : qDigest.toAscRanges()) {
+            series.add(item[1], item[2]);
+        }
+        final XYSeriesCollection dataset = new XYSeriesCollection(series);
+
+        JFreeChart chart = createChart(dataset);
+        final ChartPanel chartPanel = new ChartPanel(chart);
+        setContentPane(chartPanel);
+    }
+
+}
diff --git a/src/main/java/fucoin/gui/SuperVisorThreadGUI.java b/src/main/java/fucoin/gui/SuperVisorThreadGUI.java
index c8a8721..d1d3ef3 100644
--- a/src/main/java/fucoin/gui/SuperVisorThreadGUI.java
+++ b/src/main/java/fucoin/gui/SuperVisorThreadGUI.java
@@ -84,11 +84,20 @@ public class SuperVisorThreadGUI {
 
             JButton showGraphBtn = new JButton("Show Graph");
             showGraphBtn.addActionListener(e -> {
-                superVisorGuiControl.updateNodeNeighbourList();
-                new SuperVisorGraphGUI(superVisorGuiControl).init();
+                LocalDateTime time = (LocalDateTime) dropdown.getSelectedItem();
+                superVisorGuiControl.loadSnapshot(time);
+                new SuperVisorGraphGUI(superVisorGuiControl, time).init();
             });
             btnPanel.add(showGraphBtn);
 
+            JButton showHistogramBtn = new JButton("Show Histogram");
+            showHistogramBtn.addActionListener(e -> {
+                LocalDateTime time = (LocalDateTime) dropdown.getSelectedItem();
+                superVisorGuiControl.loadSnapshot(time);
+                new SuperVisorHistogramGUI(superVisorGuiControl, time).init();
+            });
+            btnPanel.add(showHistogramBtn);
+
             JButton createSnapshot = new JButton("Create Snapshot");
             createSnapshot.addActionListener(e -> {
                 LocalDateTime time = LocalDateTime.now();
diff --git a/src/main/java/fucoin/wallet/AbstractWallet.java b/src/main/java/fucoin/wallet/AbstractWallet.java
index 8f76327..f831e2e 100644
--- a/src/main/java/fucoin/wallet/AbstractWallet.java
+++ b/src/main/java/fucoin/wallet/AbstractWallet.java
@@ -14,7 +14,7 @@ import java.time.LocalDateTime;
  */
 public abstract class AbstractWallet extends AbstractNode implements Serializable, TransactionLogger {
 
-    private static final double sCompression = 0.1;
+    private static final double sCompression = 5;
     private QDigest qDigest = new QDigest(sCompression);
 
     /**
diff --git a/src/main/java/fucoin/wallet/Snapshot.java b/src/main/java/fucoin/wallet/Snapshot.java
index 5171e0e..a2fc864 100644
--- a/src/main/java/fucoin/wallet/Snapshot.java
+++ b/src/main/java/fucoin/wallet/Snapshot.java
@@ -11,7 +11,7 @@ public class Snapshot implements Serializable {
     private final String name;
     private final int amount;
     private final Set<String> knownNeighbour;
-    private final HashMap<ActorRef, Integer> knownNeighbourAmounts;
+    private final HashMap<String, Integer> knownNeighbourAmounts = new HashMap<>();
     private final List<long[]> qDigestVal;
     private final byte[] qDigest;
 
@@ -22,7 +22,9 @@ public class Snapshot implements Serializable {
         this.qDigest = QDigest.serialize(wallet.getqDigest());
         this.qDigestVal = wallet.getqDigest().toAscRanges();
         this.knownNeighbour = wallet.getKnownNeighbors().keySet();
-        this.knownNeighbourAmounts = wallet.amounts;
+        wallet.amounts.forEach((actorRef, amount) -> {
+            knownNeighbourAmounts.put(actorRef.toString(), amount);
+        });
     }
 
     public String getName() {
@@ -33,6 +35,18 @@ public class Snapshot implements Serializable {
         return amount;
     }
 
+    public Set<String> getKnownNeighbour() {
+        return knownNeighbour;
+    }
+
+    public HashMap<String, Integer> getKnownNeighbourAmounts() {
+        return knownNeighbourAmounts;
+    }
+
+    public List<long[]> getqDigestVal() {
+        return qDigestVal;
+    }
+
     public QDigest getqDigest() {
         return QDigest.deserialize(this.qDigest);
     }
-- 
GitLab