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