From 97b9f733ab2134265495447e73e98eaddb06a8a1 Mon Sep 17 00:00:00 2001 From: Steven Barclay Date: Sun, 9 Feb 2020 21:54:09 +0000 Subject: [PATCH 1/2] Do some minor tidying of DAO SupplyView * Use Java Time instead of java.sql.Date for local date calculations; * Avoid raw types & unsafe varargs warnings; * Fix false compiler error in IDEA due to discrepancy with javac; * Formatting & method visibility. --- .../main/dao/economy/supply/SupplyView.java | 71 ++++++++----------- 1 file changed, 30 insertions(+), 41 deletions(-) diff --git a/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java b/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java index cb1dec2057c..47723fadd20 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java @@ -61,6 +61,7 @@ import javafx.util.StringConverter; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.OffsetDateTime; @@ -88,9 +89,6 @@ import static bisq.desktop.util.FormBuilder.addTitledGroupBg; import static bisq.desktop.util.FormBuilder.addTopLabelReadOnlyTextField; - -import java.sql.Date; - @FxmlView public class SupplyView extends ActivatableView implements DaoStateListener { @@ -110,7 +108,7 @@ public class SupplyView extends ActivatableView implements DaoSt private XYChart.Series seriesBSQIssuedMonthly2; - private ListChangeListener changeListenerBSQBurntDaily; + private ListChangeListener> changeListenerBSQBurntDaily; private NumberAxis yAxisBSQBurntDaily; private ToggleButton zoomToInliersSlide; @@ -194,22 +192,19 @@ private void initializeSeries() { var burntLabel = Res.get("dao.factsAndFigures.supply.burnt"); seriesBSQIssuedMonthly = new XYChart.Series<>(); - var issuedMonthlyLabel = issuedLabel; - seriesBSQIssuedMonthly.setName(issuedMonthlyLabel); + seriesBSQIssuedMonthly.setName(issuedLabel); // Because Series cannot be reused in multiple charts, we create a // "second" Series and populate it at the same time as the original. // Some other solutions: https://stackoverflow.com/questions/49770442 seriesBSQIssuedMonthly2 = new XYChart.Series<>(); - seriesBSQIssuedMonthly2.setName(issuedMonthlyLabel); + seriesBSQIssuedMonthly2.setName(issuedLabel); seriesBSQBurntMonthly = new XYChart.Series<>(); - var burntMonthlyLabel = burntLabel; - seriesBSQBurntMonthly.setName(burntMonthlyLabel); + seriesBSQBurntMonthly.setName(burntLabel); seriesBSQBurntDaily = new XYChart.Series<>(); - var burntDailyLabel = burntLabel; - seriesBSQBurntDaily.setName(burntDailyLabel); + seriesBSQBurntDaily.setName(burntLabel); seriesBSQBurntDailyMA = new XYChart.Series<>(); var burntMALabel = Res.get("dao.factsAndFigures.supply.burntMovingAverage"); @@ -223,21 +218,20 @@ private void createSupplyIncreasedVsDecreasedInformation() { var chartPane = wrapInChartPane(chart); - addToTopMargin(chartPane, Layout.COMPACT_FIRST_ROW_DISTANCE); + addToTopMargin(chartPane); root.getChildren().add(chartPane); } - private void addToTopMargin(Node child, double amount) { + private void addToTopMargin(Node child) { var margin = GridPane.getMargin(child); - var new_insets = - new Insets( - margin.getTop() + amount, - margin.getRight(), - margin.getBottom(), - margin.getLeft() - ); + var new_insets = new Insets( + margin.getTop() + Layout.COMPACT_FIRST_ROW_DISTANCE, + margin.getRight(), + margin.getBottom(), + margin.getLeft() + ); GridPane.setMargin(child, new_insets); } @@ -318,7 +312,7 @@ private Node createBSQIssuedVsBurntChart( configureChart(chart); chart.setCreateSymbols(false); - chart.getData().addAll(seriesBSQIssuedMonthly, seriesBSQBurntMonthly); + chart.getData().addAll(List.of(seriesBSQIssuedMonthly, seriesBSQBurntMonthly)); chart.setLegendVisible(true); @@ -344,7 +338,6 @@ private Node createBSQIssuedChart(XYChart.Series series) { return chart; } - @SuppressWarnings("unchecked") private Node createBSQBurntChart( XYChart.Series seriesBSQBurntDaily, XYChart.Series seriesBSQBurntDailyMA @@ -371,7 +364,7 @@ private Node createBSQBurntChart( configureChart(chart); chart.setCreateSymbols(false); - chart.getData().addAll(seriesBSQBurntDaily, seriesBSQBurntDailyMA); + chart.getData().addAll(List.of(seriesBSQBurntDaily, seriesBSQBurntDailyMA)); chart.setLegendVisible(true); @@ -501,11 +494,9 @@ private List getSortedBurntTxs() { Set burntTxs = new HashSet<>(daoStateService.getBurntFeeTxs()); burntTxs.addAll(daoStateService.getInvalidTxs()); - List sortedBurntTxs = burntTxs.stream() + return burntTxs.stream() .sorted(Comparator.comparing(Tx::getTime)) .collect(Collectors.toList()); - - return sortedBurntTxs; } private List> updateBSQBurntDaily(List sortedBurntTxs) { @@ -515,18 +506,16 @@ private List> updateBSQBurntDaily(List sortedBu sortedBurntTxs .stream() .collect(Collectors.groupingBy( - tx -> - new Date(tx.getTime()) - .toLocalDate() - .with(ADJUSTERS.get(DAY)) + tx -> Instant.ofEpochMilli(tx.getTime()).atZone(ZoneId.systemDefault()) + .toLocalDate() + .with(ADJUSTERS.get(DAY)) )); List> updatedBurntBsqDaily = burntBsqByDay .keySet() .stream() - .map(date -> - { + .map(date -> { ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault()); return new XYChart.Data( zonedDateTime.toInstant().getEpochSecond(), @@ -550,18 +539,16 @@ private void updateBSQBurntMonthly(List sortedBurntTxs) { sortedBurntTxs .stream() .collect(Collectors.groupingBy( - tx -> - new Date(tx.getTime()) - .toLocalDate() - .with(ADJUSTERS.get(MONTH)) + tx -> Instant.ofEpochMilli(tx.getTime()).atZone(ZoneId.systemDefault()) + .toLocalDate() + .with(ADJUSTERS.get(MONTH)) )); List> updatedBurntBsqMonthly = burntBsqByMonth .keySet() .stream() - .map(date -> - { + .map(date -> { ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneId.systemDefault()); return new XYChart.Data( zonedDateTime.toInstant().getEpochSecond(), @@ -603,7 +590,7 @@ private void updateBSQBurntDailyMA(List> updatedBur maPeriod); BiFunction> xyToXyData = - XYChart.Data::new; + XYChart.Data::new; List> burntBsqMA = zip(burntBsqXValues, burntBsqMAYValues, xyToXyData) @@ -621,7 +608,9 @@ private void updateBSQIssuedMonthly() { .sorted(Comparator.comparing(Issuance::getChainHeight)); Map> bsqAddedByVote = Stream.concat(bsqByCompensation, bsqByReimbursement) - .collect(Collectors.groupingBy(item -> new Date(daoFacade.getBlockTime(item.getChainHeight())).toLocalDate() + .collect(Collectors.groupingBy(item -> Instant.ofEpochMilli(daoFacade.getBlockTime(item.getChainHeight())) + .atZone(ZoneId.systemDefault()) + .toLocalDate() .with(ADJUSTERS.get(MONTH)))); List> updatedAddedBSQ = bsqAddedByVote.keySet().stream() @@ -686,7 +675,7 @@ private void triggerZoomToInliers() { // When Guava version is bumped to at least 21.0, // can be replaced with com.google.common.collect.Streams.zip - public static Stream zip( + private static Stream zip( Stream leftStream, Stream rightStream, BiFunction combiner From 459f0db661cdf039369dd6351cad318b55eebbcf Mon Sep 17 00:00:00 2001 From: Steven Barclay Date: Mon, 10 Feb 2020 04:46:59 +0000 Subject: [PATCH 2/2] Memoise block times to speed up display of BSQ issued graph Avoid repeatedly calling DaoFacade.getBlockTime for Issuance objects with the same chain height, as that method linearly scans the entire linked list of DaoState blocks, making it quite slow. Instead, memoise the mapping from chain height to block-time month, so that it is only computed once per graph point instead of once for every BSQ issuance. --- .../main/dao/economy/supply/SupplyView.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java b/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java index 47723fadd20..87372ba4ea8 100644 --- a/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java +++ b/desktop/src/main/java/bisq/desktop/main/dao/economy/supply/SupplyView.java @@ -78,8 +78,10 @@ import java.util.Map; import java.util.Set; import java.util.Spliterators.AbstractSpliterator; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -601,6 +603,11 @@ private void updateBSQBurntDailyMA(List> updatedBur } private void updateBSQIssuedMonthly() { + Function blockTimeFn = memoize(height -> + Instant.ofEpochMilli(daoFacade.getBlockTime(height)).atZone(ZoneId.systemDefault()) + .toLocalDate() + .with(ADJUSTERS.get(MONTH))); + Stream bsqByCompensation = daoStateService.getIssuanceSet(IssuanceType.COMPENSATION).stream() .sorted(Comparator.comparing(Issuance::getChainHeight)); @@ -608,10 +615,7 @@ private void updateBSQIssuedMonthly() { .sorted(Comparator.comparing(Issuance::getChainHeight)); Map> bsqAddedByVote = Stream.concat(bsqByCompensation, bsqByReimbursement) - .collect(Collectors.groupingBy(item -> Instant.ofEpochMilli(daoFacade.getBlockTime(item.getChainHeight())) - .atZone(ZoneId.systemDefault()) - .toLocalDate() - .with(ADJUSTERS.get(MONTH)))); + .collect(Collectors.groupingBy(blockTimeFn.compose(Issuance::getChainHeight))); List> updatedAddedBSQ = bsqAddedByVote.keySet().stream() .map(date -> { @@ -701,4 +705,9 @@ public boolean tryAdvance(Consumer action) { }; return StreamSupport.stream(spliterator, false); } + + private static Function memoize(Function fn) { + Map map = new ConcurrentHashMap<>(); + return x -> map.computeIfAbsent(x, fn); + } }