From fa2163fb0f25dd870cdec81c2b3a50229d8350af Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Sun, 11 Oct 2020 21:02:32 -0500 Subject: [PATCH] Use a thread in PersistenceManager for reading persisted files instead of using thread in client code Before we use a thread in readFromResources and readAllPersisted. To avoid that client code need to deal with threading we moved that to the PersistenceManager and changed the API accordingly so it will not return the persisted object but calls a consumer once it is completed with reading. --- .../persistence/PersistenceManager.java | 34 ++++++- .../proto/persistable/PersistedDataHost.java | 8 +- .../java/bisq/core/app/BisqExecutable.java | 9 +- .../main/java/bisq/core/app/BisqSetup.java | 8 +- .../main/java/bisq/core/app/SetupUtils.java | 49 ---------- .../bisq/core/app/misc/AppSetupWithP2P.java | 10 +-- .../bisq/core/btc/model/AddressEntryList.java | 25 +++--- .../governance/ballot/BallotListService.java | 15 ++-- .../blindvote/MyBlindVoteListService.java | 13 +-- .../reputation/MyReputationListService.java | 13 +-- .../governance/myvote/MyVoteListService.java | 16 ++-- .../proofofburn/MyProofOfBurnListService.java | 13 +-- .../proposal/MyProposalListService.java | 15 ++-- .../temp/TempProposalStorageService.java | 4 +- ...UnconfirmedBsqChangeOutputListService.java | 13 +-- .../bisq/core/offer/OpenOfferManager.java | 17 ++-- .../support/dispute/DisputeListService.java | 11 +-- .../java/bisq/core/trade/TradeManager.java | 23 +++-- .../trade/closed/ClosedTradableManager.java | 19 ++-- .../trade/failed/FailedTradesManager.java | 23 +++-- .../TradeStatistics2StorageService.java | 7 +- .../main/java/bisq/core/user/Preferences.java | 90 +++++++++++-------- core/src/main/java/bisq/core/user/User.java | 22 +++-- .../main/java/bisq/desktop/Navigation.java | 38 ++++---- .../main/java/bisq/desktop/util/GUIUtil.java | 37 ++++---- .../java/bisq/network/p2p/P2PService.java | 6 +- .../bisq/network/p2p/peers/PeerManager.java | 11 +-- .../network/p2p/storage/P2PDataStorage.java | 49 +++++++--- .../AppendOnlyDataStoreService.java | 14 ++- .../HistoricalDataStoreService.java | 45 +++++----- .../ProtectedDataStoreService.java | 13 ++- .../persistence/ResourceDataStoreService.java | 13 ++- .../p2p/storage/persistence/StoreService.java | 36 ++++---- .../storage/mocks/MapStoreServiceFake.java | 2 +- 34 files changed, 387 insertions(+), 334 deletions(-) delete mode 100644 core/src/main/java/bisq/core/app/SetupUtils.java diff --git a/common/src/main/java/bisq/common/persistence/PersistenceManager.java b/common/src/main/java/bisq/common/persistence/PersistenceManager.java index ec8d1ee005f..20691de0447 100644 --- a/common/src/main/java/bisq/common/persistence/PersistenceManager.java +++ b/common/src/main/java/bisq/common/persistence/PersistenceManager.java @@ -45,6 +45,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -213,14 +214,41 @@ public void shutdown() { // Reading file /////////////////////////////////////////////////////////////////////////////////////////// + /** + * Read persisted file in a thread. + * + * @param resultHandler Consumer of persisted data once it was read from disk. + * @param orElse Called if no file exists or reading of file failed. + */ + public void readPersisted(Consumer resultHandler, Runnable orElse) { + readPersisted(checkNotNull(fileName), resultHandler, orElse); + } + + /** + * Read persisted file in a thread. + * + * @param fileName File name of our persisted data. + * @param resultHandler Consumer of persisted data once it was read from disk. + * @param orElse Called if no file exists or reading of file failed. + */ + public void readPersisted(String fileName, Consumer resultHandler, Runnable orElse) { + new Thread(() -> { + T persisted = getPersisted(fileName); + if (persisted != null) { + resultHandler.accept(persisted); + } else { + orElse.run(); + } + }, "BisqExecutable-read-" + fileName).start(); + } + + // API for synchronous reading of data. Not recommended to be used in application code. + // Currently used by tests and monitor. Should be converted to the threaded API as well. @Nullable public T getPersisted() { return getPersisted(checkNotNull(fileName)); } - //TODO use threading here instead in the clients - // We get called at startup either by readAllPersisted or readFromResources. Both are wrapped in a thread so we - // are not on the user thread. @Nullable public T getPersisted(String fileName) { File storageFile = new File(dir, fileName); diff --git a/common/src/main/java/bisq/common/proto/persistable/PersistedDataHost.java b/common/src/main/java/bisq/common/proto/persistable/PersistedDataHost.java index f2e53cf19f1..0aca05732d8 100644 --- a/common/src/main/java/bisq/common/proto/persistable/PersistedDataHost.java +++ b/common/src/main/java/bisq/common/proto/persistable/PersistedDataHost.java @@ -17,12 +17,6 @@ package bisq.common.proto.persistable; -import java.util.List; - public interface PersistedDataHost { - void readPersisted(); - - static void apply(List persistedDataHosts) { - persistedDataHosts.forEach(PersistedDataHost::readPersisted); - } + void readPersisted(Runnable completeHandler); } diff --git a/core/src/main/java/bisq/core/app/BisqExecutable.java b/core/src/main/java/bisq/core/app/BisqExecutable.java index 66c03dede43..18104e292e8 100644 --- a/core/src/main/java/bisq/core/app/BisqExecutable.java +++ b/core/src/main/java/bisq/core/app/BisqExecutable.java @@ -169,14 +169,11 @@ protected void readAllPersisted(@Nullable List additionalHost AtomicInteger remaining = new AtomicInteger(hosts.size()); hosts.forEach(e -> { - new Thread(() -> { - e.readPersisted(); - remaining.decrementAndGet(); - if (remaining.get() == 0) { + e.readPersisted(() -> { + if (remaining.decrementAndGet() == 0) { UserThread.execute(completeHandler); } - - }, "BisqExecutable-read-" + e.getClass().getSimpleName()).start(); + }); }); } diff --git a/core/src/main/java/bisq/core/app/BisqSetup.java b/core/src/main/java/bisq/core/app/BisqSetup.java index 3660544f60d..130c635fe7d 100644 --- a/core/src/main/java/bisq/core/app/BisqSetup.java +++ b/core/src/main/java/bisq/core/app/BisqSetup.java @@ -317,11 +317,9 @@ private void maybeShowTac(Runnable nextStep) { } } - private void readMapsFromResources(Runnable nextStep) { - SetupUtils.readFromResources(p2PService.getP2PDataStorage(), config).addListener((observable, oldValue, newValue) -> { - if (newValue) - nextStep.run(); - }); + private void readMapsFromResources(Runnable completeHandler) { + String postFix = "_" + config.baseCurrencyNetwork.name(); + p2PService.getP2PDataStorage().readFromResources(postFix, completeHandler); } private void startP2pNetworkAndWallet(Runnable nextStep) { diff --git a/core/src/main/java/bisq/core/app/SetupUtils.java b/core/src/main/java/bisq/core/app/SetupUtils.java deleted file mode 100644 index eb210da5fea..00000000000 --- a/core/src/main/java/bisq/core/app/SetupUtils.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of Bisq. - * - * Bisq is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bisq is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bisq. If not, see . - */ - -package bisq.core.app; - -import bisq.network.p2p.storage.P2PDataStorage; - -import bisq.common.UserThread; -import bisq.common.config.BaseCurrencyNetwork; -import bisq.common.config.Config; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; - -import java.util.Date; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class SetupUtils { - - public static BooleanProperty readFromResources(P2PDataStorage p2PDataStorage, Config config) { - BooleanProperty result = new SimpleBooleanProperty(); - new Thread(() -> { - // Used to load different files per base currency (EntryMap_BTC_MAINNET, EntryMap_LTC,...) - final BaseCurrencyNetwork baseCurrencyNetwork = config.baseCurrencyNetwork; - final String postFix = "_" + baseCurrencyNetwork.name(); - long ts = new Date().getTime(); - p2PDataStorage.readFromResources(postFix); - log.info("readFromResources took {} ms", (new Date().getTime() - ts)); - UserThread.execute(() -> result.set(true)); - }, "BisqSetup-readFromResources").start(); - return result; - } -} diff --git a/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java b/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java index 8b2dc545d6c..dc28aac2d06 100644 --- a/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java +++ b/core/src/main/java/bisq/core/app/misc/AppSetupWithP2P.java @@ -19,7 +19,6 @@ import bisq.core.account.sign.SignedWitnessService; import bisq.core.account.witness.AccountAgeWitnessService; -import bisq.core.app.SetupUtils; import bisq.core.app.TorSetup; import bisq.core.filter.FilterManager; import bisq.core.trade.statistics.TradeStatisticsManager; @@ -79,7 +78,8 @@ public void initPersistedDataHosts() { // we apply at startup the reading of persisted data but don't want to get it triggered in the constructor persistedDataHosts.forEach(e -> { try { - e.readPersisted(); + e.readPersisted(() -> { + }); } catch (Throwable e1) { log.error("readPersisted error", e1); } @@ -88,10 +88,8 @@ public void initPersistedDataHosts() { @Override protected void initBasicServices() { - SetupUtils.readFromResources(p2PService.getP2PDataStorage(), config).addListener((observable, oldValue, newValue) -> { - if (newValue) - startInitP2PNetwork(); - }); + String postFix = "_" + config.baseCurrencyNetwork.name(); + p2PService.getP2PDataStorage().readFromResources(postFix, this::startInitP2PNetwork); } private void startInitP2PNetwork() { diff --git a/core/src/main/java/bisq/core/btc/model/AddressEntryList.java b/core/src/main/java/bisq/core/btc/model/AddressEntryList.java index c88ebc40fbd..ea25be37756 100644 --- a/core/src/main/java/bisq/core/btc/model/AddressEntryList.java +++ b/core/src/main/java/bisq/core/btc/model/AddressEntryList.java @@ -63,12 +63,13 @@ public AddressEntryList(PersistenceManager persistenceManager) } @Override - public void readPersisted() { - AddressEntryList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - entrySet.clear(); - entrySet.addAll(persisted.entrySet); - } + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + entrySet.clear(); + entrySet.addAll(persisted.entrySet); + completeHandler.run(); + }, + completeHandler); } @@ -110,12 +111,12 @@ public void onWalletReady(Wallet wallet) { Set toBeRemoved = new HashSet<>(); entrySet.forEach(addressEntry -> { Script.ScriptType scriptType = addressEntry.isSegwit() ? Script.ScriptType.P2WPKH - : Script.ScriptType.P2PKH; + : Script.ScriptType.P2PKH; DeterministicKey keyFromPubHash = (DeterministicKey) wallet.findKeyFromPubKeyHash( - addressEntry.getPubKeyHash(), scriptType); + addressEntry.getPubKeyHash(), scriptType); if (keyFromPubHash != null) { Address addressFromKey = Address.fromKey(Config.baseCurrencyNetworkParameters(), keyFromPubHash, - scriptType); + scriptType); // We want to ensure key and address matches in case we have address in entry available already if (addressEntry.getAddress() == null || addressFromKey.equals(addressEntry.getAddress())) { addressEntry.setDeterministicKey(keyFromPubHash); @@ -197,8 +198,8 @@ public void addAddressEntry(AddressEntry addressEntry) { public void swapToAvailable(AddressEntry addressEntry) { boolean setChangedByRemove = entrySet.remove(addressEntry); boolean setChangedByAdd = entrySet.add(new AddressEntry(addressEntry.getKeyPair(), - AddressEntry.Context.AVAILABLE, - addressEntry.isSegwit())); + AddressEntry.Context.AVAILABLE, + addressEntry.isSegwit())); if (setChangedByRemove || setChangedByAdd) { requestPersistence(); } @@ -234,7 +235,7 @@ private void maybeAddNewAddressEntry(Transaction tx) { .map(address -> Pair.of(address, (DeterministicKey) wallet.findKeyFromAddress(address))) .filter(pair -> pair.getRight() != null) .map(pair -> new AddressEntry(pair.getRight(), AddressEntry.Context.AVAILABLE, - pair.getLeft() instanceof SegwitAddress)) + pair.getLeft() instanceof SegwitAddress)) .forEach(this::addAddressEntry); } diff --git a/core/src/main/java/bisq/core/dao/governance/ballot/BallotListService.java b/core/src/main/java/bisq/core/dao/governance/ballot/BallotListService.java index cb01694fdf6..053246f3d96 100644 --- a/core/src/main/java/bisq/core/dao/governance/ballot/BallotListService.java +++ b/core/src/main/java/bisq/core/dao/governance/ballot/BallotListService.java @@ -129,13 +129,16 @@ public void start() { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { + public void readPersisted(Runnable completeHandler) { if (DevEnv.isDaoActivated()) { - BallotList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - ballotList.setAll(persisted.getList()); - listeners.forEach(l -> l.onListChanged(ballotList.getList())); - } + persistenceManager.readPersisted(persisted -> { + ballotList.setAll(persisted.getList()); + listeners.forEach(l -> l.onListChanged(ballotList.getList())); + completeHandler.run(); + }, + completeHandler); + } else { + completeHandler.run(); } } diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java b/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java index cc70c4a002e..cee5d1b9174 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteListService.java @@ -162,12 +162,15 @@ public void start() { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { + public void readPersisted(Runnable completeHandler) { if (DevEnv.isDaoActivated()) { - MyBlindVoteList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - myBlindVoteList.setAll(persisted.getList()); - } + persistenceManager.readPersisted(persisted -> { + myBlindVoteList.setAll(persisted.getList()); + completeHandler.run(); + }, + completeHandler); + } else { + completeHandler.run(); } } diff --git a/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationListService.java b/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationListService.java index c417b9c61ce..5995a3be356 100644 --- a/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationListService.java +++ b/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationListService.java @@ -55,12 +55,15 @@ public MyReputationListService(PersistenceManager persistenceM /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { + public void readPersisted(Runnable completeHandler) { if (DevEnv.isDaoActivated()) { - MyReputationList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - myReputationList.setAll(persisted.getList()); - } + persistenceManager.readPersisted(persisted -> { + myReputationList.setAll(persisted.getList()); + completeHandler.run(); + }, + completeHandler); + } else { + completeHandler.run(); } } diff --git a/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteListService.java b/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteListService.java index 390ee4ee608..ecd3faf1628 100644 --- a/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteListService.java +++ b/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteListService.java @@ -69,12 +69,15 @@ public MyVoteListService(DaoStateService daoStateService, /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { + public void readPersisted(Runnable completeHandler) { if (DevEnv.isDaoActivated()) { - MyVoteList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - this.myVoteList.setAll(persisted.getList()); - } + persistenceManager.readPersisted(persisted -> { + myVoteList.setAll(persisted.getList()); + completeHandler.run(); + }, + completeHandler); + } else { + completeHandler.run(); } } @@ -97,7 +100,8 @@ public void applyRevealTxId(MyVote myVote, String voteRevealTxId) { requestPersistence(); } - public Tuple2 getMeritAndStakeForProposal(String proposalTxId, MyBlindVoteListService myBlindVoteListService) { + public Tuple2 getMeritAndStakeForProposal(String proposalTxId, + MyBlindVoteListService myBlindVoteListService) { long merit = 0; long stake = 0; List list = new ArrayList<>(myVoteList.getList()); diff --git a/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnListService.java b/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnListService.java index 39d8ed5a525..d61c6a93be3 100644 --- a/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnListService.java +++ b/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnListService.java @@ -55,12 +55,15 @@ public MyProofOfBurnListService(PersistenceManager persistenc /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { + public void readPersisted(Runnable completeHandler) { if (DevEnv.isDaoActivated()) { - MyProofOfBurnList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - myProofOfBurnList.setAll(persisted.getList()); - } + persistenceManager.readPersisted(persisted -> { + myProofOfBurnList.setAll(persisted.getList()); + completeHandler.run(); + }, + completeHandler); + } else { + completeHandler.run(); } } diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalListService.java b/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalListService.java index 19284a0c042..96ab94ed66a 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalListService.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalListService.java @@ -107,13 +107,16 @@ public MyProposalListService(P2PService p2PService, /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { + public void readPersisted(Runnable completeHandler) { if (DevEnv.isDaoActivated()) { - MyProposalList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - myProposalList.setAll(persisted.getList()); - listeners.forEach(l -> l.onListChanged(getList())); - } + persistenceManager.readPersisted(persisted -> { + myProposalList.setAll(persisted.getList()); + listeners.forEach(l -> l.onListChanged(getList())); + completeHandler.run(); + }, + completeHandler); + } else { + completeHandler.run(); } } diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStorageService.java b/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStorageService.java index d39b6f5470d..b8af27c6726 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStorageService.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStorageService.java @@ -73,9 +73,9 @@ public boolean canHandle(ProtectedStorageEntry entry) { } @Override - protected void readFromResources(String postFix) { + protected void readFromResources(String postFix, Runnable completeHandler) { // We do not have a resource file for that store, so we just call the readStore method instead. - readStore(); + readStore(persisted -> completeHandler.run()); } diff --git a/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputListService.java b/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputListService.java index 467800748ff..4436c2bcb83 100644 --- a/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputListService.java +++ b/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputListService.java @@ -55,12 +55,15 @@ public UnconfirmedBsqChangeOutputListService(PersistenceManager { + unconfirmedBsqChangeOutputList.setAll(persisted.getList()); + completeHandler.run(); + }, + completeHandler); + } else { + completeHandler.run(); } } diff --git a/core/src/main/java/bisq/core/offer/OpenOfferManager.java b/core/src/main/java/bisq/core/offer/OpenOfferManager.java index 1e72532a612..c06b6d11fd2 100644 --- a/core/src/main/java/bisq/core/offer/OpenOfferManager.java +++ b/core/src/main/java/bisq/core/offer/OpenOfferManager.java @@ -166,16 +166,13 @@ public OpenOfferManager(CreateOfferService createOfferService, } @Override - public void readPersisted() { - TradableList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - openOffers.setAll(persisted.getList()); - } - - openOffers.forEach(e -> { - Offer offer = e.getOffer(); - offer.setPriceFeedService(priceFeedService); - }); + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + openOffers.setAll(persisted.getList()); + openOffers.forEach(openOffer -> openOffer.getOffer().setPriceFeedService(priceFeedService)); + completeHandler.run(); + }, + completeHandler); } public void onAllServicesInitialized() { diff --git a/core/src/main/java/bisq/core/support/dispute/DisputeListService.java b/core/src/main/java/bisq/core/support/dispute/DisputeListService.java index ffbec7dc985..d54b5e8b858 100644 --- a/core/src/main/java/bisq/core/support/dispute/DisputeListService.java +++ b/core/src/main/java/bisq/core/support/dispute/DisputeListService.java @@ -79,11 +79,12 @@ public DisputeListService(PersistenceManager persistenceManager) { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { - T persisted = persistenceManager.getPersisted(getFileName()); - if (persisted != null) { - disputeList.setAll(persisted.getList()); - } + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(getFileName(), persisted -> { + disputeList.setAll(persisted.getList()); + completeHandler.run(); + }, + completeHandler); } protected String getFileName() { diff --git a/core/src/main/java/bisq/core/trade/TradeManager.java b/core/src/main/java/bisq/core/trade/TradeManager.java index 42cb6b9e000..72378d9f010 100644 --- a/core/src/main/java/bisq/core/trade/TradeManager.java +++ b/core/src/main/java/bisq/core/trade/TradeManager.java @@ -191,19 +191,16 @@ public TradeManager(User user, /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { - TradableList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - tradableList.setAll(persisted.getList()); - } - - tradableList.forEach(trade -> { - Offer offer = trade.getOffer(); - if (offer != null) - offer.setPriceFeedService(priceFeedService); - }); - - dumpDelayedPayoutTx.maybeDumpDelayedPayoutTxs(tradableList, "delayed_payout_txs_pending"); + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + tradableList.setAll(persisted.getList()); + tradableList.stream() + .filter(trade -> trade.getOffer() != null) + .forEach(trade -> trade.getOffer().setPriceFeedService(priceFeedService)); + dumpDelayedPayoutTx.maybeDumpDelayedPayoutTxs(tradableList, "delayed_payout_txs_pending"); + completeHandler.run(); + }, + completeHandler); } diff --git a/core/src/main/java/bisq/core/trade/closed/ClosedTradableManager.java b/core/src/main/java/bisq/core/trade/closed/ClosedTradableManager.java index 69567270cbf..9341905db20 100644 --- a/core/src/main/java/bisq/core/trade/closed/ClosedTradableManager.java +++ b/core/src/main/java/bisq/core/trade/closed/ClosedTradableManager.java @@ -60,15 +60,16 @@ public ClosedTradableManager(KeyRing keyRing, } @Override - public void readPersisted() { - TradableList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - closedTradables.setAll(persisted.getList()); - } - - closedTradables.forEach(tradable -> tradable.getOffer().setPriceFeedService(priceFeedService)); - - dumpDelayedPayoutTx.maybeDumpDelayedPayoutTxs(closedTradables, "delayed_payout_txs_closed"); + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + closedTradables.setAll(persisted.getList()); + closedTradables.stream() + .filter(tradable -> tradable.getOffer() != null) + .forEach(tradable -> tradable.getOffer().setPriceFeedService(priceFeedService)); + dumpDelayedPayoutTx.maybeDumpDelayedPayoutTxs(closedTradables, "delayed_payout_txs_closed"); + completeHandler.run(); + }, + completeHandler); } public void add(Tradable tradable) { diff --git a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java index a584f6b783f..683ccc054d6 100644 --- a/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java +++ b/core/src/main/java/bisq/core/trade/failed/FailedTradesManager.java @@ -70,19 +70,16 @@ public FailedTradesManager(KeyRing keyRing, } @Override - public void readPersisted() { - TradableList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - failedTrades.setAll(persisted.getList()); - } - - failedTrades.forEach(trade -> { - if (trade.getOffer() != null) { - trade.getOffer().setPriceFeedService(priceFeedService); - } - }); - - dumpDelayedPayoutTx.maybeDumpDelayedPayoutTxs(failedTrades, "delayed_payout_txs_failed"); + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + failedTrades.setAll(persisted.getList()); + failedTrades.stream() + .filter(trade -> trade.getOffer() != null) + .forEach(trade -> trade.getOffer().setPriceFeedService(priceFeedService)); + dumpDelayedPayoutTx.maybeDumpDelayedPayoutTxs(failedTrades, "delayed_payout_txs_failed"); + completeHandler.run(); + }, + completeHandler); } public void add(Trade trade) { diff --git a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2StorageService.java b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2StorageService.java index 27024943903..29855fefe89 100644 --- a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2StorageService.java +++ b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2StorageService.java @@ -77,14 +77,13 @@ public Map getMap() { // seems to be not justified as it is needed only temporarily. @Override protected PersistableNetworkPayload putIfAbsent(P2PDataStorage.ByteArray hash, PersistableNetworkPayload payload) { - PersistableNetworkPayload previous = getMapOfAllData().putIfAbsent(hash, payload); - return previous; + return getMapOfAllData().putIfAbsent(hash, payload); } @Override - protected void readFromResources(String postFix) { + protected void readFromResources(String postFix, Runnable completeHandler) { // We do not attempt to read from resources as that file is not provided anymore - readStore(); + readStore(persisted -> completeHandler.run()); } public Map getMapOfAllData() { diff --git a/core/src/main/java/bisq/core/user/Preferences.java b/core/src/main/java/bisq/core/user/Preferences.java index 656f056522a..4052a217fbe 100644 --- a/core/src/main/java/bisq/core/user/Preferences.java +++ b/core/src/main/java/bisq/core/user/Preferences.java @@ -168,8 +168,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - - @SuppressWarnings("WeakerAccess") @Inject public Preferences(PersistenceManager persistenceManager, Config config, @@ -225,54 +223,67 @@ public Preferences(PersistenceManager persistenceManager, } @Override - public void readPersisted() { - BaseCurrencyNetwork baseCurrencyNetwork = Config.baseCurrencyNetwork(); - TradeCurrency preferredTradeCurrency; + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted("PreferencesPayload", + persisted -> { + initFromPersistedPreferences(persisted); + completeHandler.run(); + }, + () -> { + initNewPreferences(); + completeHandler.run(); + }); + } + + private void initFromPersistedPreferences(PreferencesPayload persisted) { + prefPayload = persisted; + GlobalSettings.setLocale(new Locale(prefPayload.getUserLanguage(), prefPayload.getUserCountry().code)); + GlobalSettings.setUseAnimations(prefPayload.isUseAnimations()); + TradeCurrency preferredTradeCurrency = checkNotNull(prefPayload.getPreferredTradeCurrency(), "preferredTradeCurrency must not be null"); + setPreferredTradeCurrency(preferredTradeCurrency); + setFiatCurrencies(prefPayload.getFiatCurrencies()); + setCryptoCurrencies(prefPayload.getCryptoCurrencies()); + setBsqBlockChainExplorer(prefPayload.getBsqBlockChainExplorer()); + GlobalSettings.setDefaultTradeCurrency(preferredTradeCurrency); + setupPreferences(); + } - PreferencesPayload persisted = persistenceManager.getPersisted("PreferencesPayload"); - if (persisted != null) { - prefPayload = persisted; - GlobalSettings.setLocale(new Locale(prefPayload.getUserLanguage(), prefPayload.getUserCountry().code)); - GlobalSettings.setUseAnimations(prefPayload.isUseAnimations()); - preferredTradeCurrency = checkNotNull(prefPayload.getPreferredTradeCurrency(), "preferredTradeCurrency must not be null"); - setPreferredTradeCurrency(preferredTradeCurrency); - setFiatCurrencies(prefPayload.getFiatCurrencies()); - setCryptoCurrencies(prefPayload.getCryptoCurrencies()); - setBsqBlockChainExplorer(prefPayload.getBsqBlockChainExplorer()); - } else { - prefPayload = new PreferencesPayload(); - prefPayload.setUserLanguage(GlobalSettings.getLocale().getLanguage()); - prefPayload.setUserCountry(CountryUtil.getDefaultCountry()); - GlobalSettings.setLocale(new Locale(prefPayload.getUserLanguage(), prefPayload.getUserCountry().code)); - preferredTradeCurrency = checkNotNull(CurrencyUtil.getCurrencyByCountryCode(prefPayload.getUserCountry().code), - "preferredTradeCurrency must not be null"); - prefPayload.setPreferredTradeCurrency(preferredTradeCurrency); - setFiatCurrencies(CurrencyUtil.getMainFiatCurrencies()); - setCryptoCurrencies(CurrencyUtil.getMainCryptoCurrencies()); + private void initNewPreferences() { + prefPayload = new PreferencesPayload(); + prefPayload.setUserLanguage(GlobalSettings.getLocale().getLanguage()); + prefPayload.setUserCountry(CountryUtil.getDefaultCountry()); + GlobalSettings.setLocale(new Locale(prefPayload.getUserLanguage(), prefPayload.getUserCountry().code)); + TradeCurrency preferredTradeCurrency = checkNotNull(CurrencyUtil.getCurrencyByCountryCode(prefPayload.getUserCountry().code), + "preferredTradeCurrency must not be null"); + prefPayload.setPreferredTradeCurrency(preferredTradeCurrency); + setFiatCurrencies(CurrencyUtil.getMainFiatCurrencies()); + setCryptoCurrencies(CurrencyUtil.getMainCryptoCurrencies()); - if ("BTC".equals(baseCurrencyNetwork.getCurrencyCode())) { - setBlockChainExplorerMainNet(BTC_MAIN_NET_EXPLORERS.get(0)); - setBlockChainExplorerTestNet(BTC_TEST_NET_EXPLORERS.get(0)); - } else { - throw new RuntimeException("BaseCurrencyNetwork not defined. BaseCurrencyNetwork=" + baseCurrencyNetwork); - } + BaseCurrencyNetwork baseCurrencyNetwork = Config.baseCurrencyNetwork(); + if ("BTC".equals(baseCurrencyNetwork.getCurrencyCode())) { + setBlockChainExplorerMainNet(BTC_MAIN_NET_EXPLORERS.get(0)); + setBlockChainExplorerTestNet(BTC_TEST_NET_EXPLORERS.get(0)); + } else { + throw new RuntimeException("BaseCurrencyNetwork not defined. BaseCurrencyNetwork=" + baseCurrencyNetwork); + } - prefPayload.setDirectoryChooserPath(Utilities.getSystemHomeDirectory()); + prefPayload.setDirectoryChooserPath(Utilities.getSystemHomeDirectory()); - prefPayload.setOfferBookChartScreenCurrencyCode(preferredTradeCurrency.getCode()); - prefPayload.setTradeChartsScreenCurrencyCode(preferredTradeCurrency.getCode()); - prefPayload.setBuyScreenCurrencyCode(preferredTradeCurrency.getCode()); - prefPayload.setSellScreenCurrencyCode(preferredTradeCurrency.getCode()); - } + prefPayload.setOfferBookChartScreenCurrencyCode(preferredTradeCurrency.getCode()); + prefPayload.setTradeChartsScreenCurrencyCode(preferredTradeCurrency.getCode()); + prefPayload.setBuyScreenCurrencyCode(preferredTradeCurrency.getCode()); + prefPayload.setSellScreenCurrencyCode(preferredTradeCurrency.getCode()); + GlobalSettings.setDefaultTradeCurrency(preferredTradeCurrency); + setupPreferences(); + } + private void setupPreferences() { persistenceManager.initialize(prefPayload, PersistenceManager.Source.PRIVATE); // We don't want to pass Preferences to all popups where the don't show again checkbox is used, so we use // that static lookup class to avoid static access to the Preferences directly. DontShowAgainLookup.setPreferences(this); - GlobalSettings.setDefaultTradeCurrency(preferredTradeCurrency); - // set all properties useAnimationsProperty.set(prefPayload.isUseAnimations()); useStandbyModeProperty.set(prefPayload.isUseStandbyMode()); @@ -336,6 +347,7 @@ public void readPersisted() { requestPersistence(); } + /////////////////////////////////////////////////////////////////////////////////////////// // API /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/main/java/bisq/core/user/User.java b/core/src/main/java/bisq/core/user/User.java index f101dc5f41a..2f8480e162d 100644 --- a/core/src/main/java/bisq/core/user/User.java +++ b/core/src/main/java/bisq/core/user/User.java @@ -89,13 +89,21 @@ public User() { } @Override - public void readPersisted() { - UserPayload persisted = checkNotNull(persistenceManager).getPersisted("UserPayload"); - if (persisted != null) { - userPayload = persisted; - } - - persistenceManager.initialize(userPayload, PersistenceManager.Source.PRIVATE); + public void readPersisted(Runnable completeHandler) { + checkNotNull(persistenceManager).readPersisted("UserPayload", + persisted -> { + userPayload = persisted; + init(); + completeHandler.run(); + }, + () -> { + init(); + completeHandler.run(); + }); + } + + private void init() { + checkNotNull(persistenceManager).initialize(userPayload, PersistenceManager.Source.PRIVATE); checkNotNull(userPayload.getPaymentAccounts(), "userPayload.getPaymentAccounts() must not be null"); checkNotNull(userPayload.getAcceptedLanguageLocaleCodes(), "userPayload.getAcceptedLanguageLocaleCodes() must not be null"); diff --git a/desktop/src/main/java/bisq/desktop/Navigation.java b/desktop/src/main/java/bisq/desktop/Navigation.java index adb73000231..cb9da123d79 100644 --- a/desktop/src/main/java/bisq/desktop/Navigation.java +++ b/desktop/src/main/java/bisq/desktop/Navigation.java @@ -79,24 +79,26 @@ public Navigation(PersistenceManager persistenceManager) { } @Override - public void readPersisted() { - NavigationPath persisted = persistenceManager.getPersisted(); - if (persisted != null) { - List> viewClasses = persisted.getPath().stream() - .map(className -> { - try { - return (Class) Class.forName(className).asSubclass(View.class); - } catch (ClassNotFoundException e) { - log.warn("Could not find the viewPath class {}; exception: {}", className, e); - } - return null; - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - if (!viewClasses.isEmpty()) - previousPath = new ViewPath(viewClasses); - } + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + List> viewClasses = persisted.getPath().stream() + .map(className -> { + try { + return (Class) Class.forName(className).asSubclass(View.class); + } catch (ClassNotFoundException e) { + log.warn("Could not find the viewPath class {}; exception: {}", className, e); + } + return null; + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + if (!viewClasses.isEmpty()) { + previousPath = new ViewPath(viewClasses); + } + completeHandler.run(); + }, + completeHandler); } @SafeVarargs diff --git a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java index 42f95f7e738..5c6a8b39353 100644 --- a/desktop/src/main/java/bisq/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/bisq/desktop/util/GUIUtil.java @@ -247,25 +247,24 @@ public static void importAccounts(User user, String directory = Paths.get(path).getParent().toString(); preferences.setDirectoryChooserPath(directory); PersistenceManager persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler); - PaymentAccountList persisted = persistenceManager.getPersisted(fileName); - if (persisted != null) { - final StringBuilder msg = new StringBuilder(); - final HashSet paymentAccounts = new HashSet<>(); - persisted.getList().forEach(paymentAccount -> { - final String id = paymentAccount.getId(); - if (user.getPaymentAccount(id) == null) { - paymentAccounts.add(paymentAccount); - msg.append(Res.get("guiUtil.accountExport.tradingAccount", id)); - } else { - msg.append(Res.get("guiUtil.accountImport.noImport", id)); - } - }); - user.addImportedPaymentAccounts(paymentAccounts); - new Popup().feedback(Res.get("guiUtil.accountImport.imported", path, msg)).show(); - - } else { - new Popup().warning(Res.get("guiUtil.accountImport.noAccountsFound", path, fileName)).show(); - } + persistenceManager.readPersisted(fileName, persisted -> { + StringBuilder msg = new StringBuilder(); + HashSet paymentAccounts = new HashSet<>(); + persisted.getList().forEach(paymentAccount -> { + String id = paymentAccount.getId(); + if (user.getPaymentAccount(id) == null) { + paymentAccounts.add(paymentAccount); + msg.append(Res.get("guiUtil.accountExport.tradingAccount", id)); + } else { + msg.append(Res.get("guiUtil.accountImport.noImport", id)); + } + }); + user.addImportedPaymentAccounts(paymentAccounts); + new Popup().feedback(Res.get("guiUtil.accountImport.imported", path, msg)).show(); + }, + () -> { + new Popup().warning(Res.get("guiUtil.accountImport.noAccountsFound", path, fileName)).show(); + }); } else { log.error("The selected file is not the expected file for import. The expected file name is: " + fileName + "."); } diff --git a/p2p/src/main/java/bisq/network/p2p/P2PService.java b/p2p/src/main/java/bisq/network/p2p/P2PService.java index 8716c81d9d1..29e8ebfd4a4 100644 --- a/p2p/src/main/java/bisq/network/p2p/P2PService.java +++ b/p2p/src/main/java/bisq/network/p2p/P2PService.java @@ -185,9 +185,9 @@ public P2PService(NetworkNode networkNode, } @Override - public void readPersisted() { - p2PDataStorage.readPersisted(); - peerManager.readPersisted(); + public void readPersisted(Runnable completeHandler) { + p2PDataStorage.readPersisted(completeHandler); + peerManager.readPersisted(completeHandler); } diff --git a/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java b/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java index 20af0453194..4765434f9a2 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/PeerManager.java @@ -183,11 +183,12 @@ public void shutDown() { /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void readPersisted() { - PeerList persisted = persistenceManager.getPersisted(); - if (persisted != null) { - peerList.setAll(persisted.getSet()); - } + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + peerList.setAll(persisted.getSet()); + completeHandler.run(); + }, + completeHandler); } diff --git a/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java b/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java index 7b9e3714cea..2a70baf609d 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/P2PDataStorage.java @@ -77,6 +77,12 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Maps; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.monadic.MonadicBinding; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; + import java.security.KeyPair; import java.security.PublicKey; @@ -143,6 +149,10 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers /// which removes entries after PURGE_AGE_DAYS. private final int maxSequenceNumberMapSizeBeforePurge; + // Don't convert to local variable as it might get GC'ed. + private MonadicBinding readFromResourcesCompleteBinding; + + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////////////////////////////////////////////// @@ -171,21 +181,36 @@ public P2PDataStorage(NetworkNode networkNode, } @Override - public void readPersisted() { - SequenceNumberMap persisted = persistenceManager.getPersisted(); - if (persisted != null) - sequenceNumberMap.setMap(getPurgedSequenceNumberMap(persisted.getMap())); + public void readPersisted(Runnable completeHandler) { + persistenceManager.readPersisted(persisted -> { + sequenceNumberMap.setMap(getPurgedSequenceNumberMap(persisted.getMap())); + completeHandler.run(); + }, + completeHandler); } - // This method is called at startup in a non-user thread. - // We should not have any threading issues here as the p2p network is just initializing + // Threading is done on the persistenceManager level + public void readFromResources(String postFix, Runnable completeHandler) { + BooleanProperty appendOnlyDataStoreServiceReady = new SimpleBooleanProperty(); + BooleanProperty protectedDataStoreServiceReady = new SimpleBooleanProperty(); + BooleanProperty resourceDataStoreServiceReady = new SimpleBooleanProperty(); - public synchronized void readFromResources(String postFix) { - appendOnlyDataStoreService.readFromResources(postFix); - protectedDataStoreService.readFromResources(postFix); - resourceDataStoreService.readFromResources(postFix); - - map.putAll(protectedDataStoreService.getMap()); + appendOnlyDataStoreService.readFromResources(postFix, () -> appendOnlyDataStoreServiceReady.set(true)); + protectedDataStoreService.readFromResources(postFix, () -> { + map.putAll(protectedDataStoreService.getMap()); + protectedDataStoreServiceReady.set(true); + }); + resourceDataStoreService.readFromResources(postFix, () -> resourceDataStoreServiceReady.set(true)); + + readFromResourcesCompleteBinding = EasyBind.combine(appendOnlyDataStoreServiceReady, + protectedDataStoreServiceReady, + resourceDataStoreServiceReady, + (a, b, c) -> a && b && c); + readFromResourcesCompleteBinding.subscribe((observable, oldValue, newValue) -> { + if (newValue) { + completeHandler.run(); + } + }); } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java index 916523fcc60..09ad36a1d22 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/AppendOnlyDataStoreService.java @@ -20,11 +20,14 @@ import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; +import bisq.common.UserThread; + import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import lombok.Getter; @@ -51,8 +54,15 @@ public void addService(MapStoreService service.readFromResources(postFix)); + public void readFromResources(String postFix, Runnable completeHandler) { + AtomicInteger remaining = new AtomicInteger(services.size()); + services.forEach(service -> { + service.readFromResources(postFix, () -> { + if (remaining.decrementAndGet() == 0) { + UserThread.execute(completeHandler); + } + }); + }); } public Map getMap() { diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java index 3c92ca706fd..aaff5ba1ebc 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/HistoricalDataStoreService.java @@ -145,19 +145,21 @@ protected PersistableNetworkPayload putIfAbsent(P2PDataStorage.ByteArray hash, P @Override - protected void readFromResources(String postFix) { - readStore(); - log.info("We have created the {} store for the live data and filled it with {} entries from the persisted data.", - getFileName(), getMapOfLiveData().size()); + protected void readFromResources(String postFix, Runnable completeHandler) { + readStore(persisted -> { + log.info("We have created the {} store for the live data and filled it with {} entries from the persisted data.", + getFileName(), getMapOfLiveData().size()); - // Now we add our historical data stores. As they are immutable after created we use an ImmutableMap - ImmutableMap.Builder allHistoricalPayloadsBuilder = ImmutableMap.builder(); - ImmutableMap.Builder> storesByVersionBuilder = ImmutableMap.builder(); + // Now we add our historical data stores. As they are immutable after created we use an ImmutableMap + ImmutableMap.Builder allHistoricalPayloadsBuilder = ImmutableMap.builder(); + ImmutableMap.Builder> storesByVersionBuilder = ImmutableMap.builder(); - Version.HISTORY.forEach(version -> readHistoricalStoreFromResources(version, postFix, allHistoricalPayloadsBuilder, storesByVersionBuilder)); + Version.HISTORY.forEach(version -> readHistoricalStoreFromResources(version, postFix, allHistoricalPayloadsBuilder, storesByVersionBuilder)); - allHistoricalPayloads = allHistoricalPayloadsBuilder.build(); - storesByVersion = storesByVersionBuilder.build(); + allHistoricalPayloads = allHistoricalPayloadsBuilder.build(); + storesByVersion = storesByVersionBuilder.build(); + completeHandler.run(); + }); } @@ -172,19 +174,18 @@ private void readHistoricalStoreFromResources(String version, String fileName = getFileName() + "_" + version; boolean wasCreatedFromResources = makeFileFromResourceFile(fileName, postFix); - // If resource file does not exist we return null. We do not create a new store as it would never get filled. - PersistableNetworkPayloadStore historicalStore = persistenceManager.getPersisted(fileName); - if (historicalStore == null) { - log.warn("Resource file with file name {} does not exits.", fileName); - return; - } - - storesByVersionBuilder.put(version, historicalStore); - allHistoricalDataBuilder.putAll(historicalStore.getMap()); + // If resource file does not exist we do not create a new store as it would never get filled. + persistenceManager.readPersisted(getFileName(), persisted -> { + storesByVersionBuilder.put(version, persisted); + allHistoricalDataBuilder.putAll(persisted.getMap()); - if (wasCreatedFromResources) { - pruneStore(historicalStore, version); - } + if (wasCreatedFromResources) { + pruneStore(persisted, version); + } + }, + () -> { + log.warn("Resource file with file name {} does not exits.", fileName); + }); } private void pruneStore(PersistableNetworkPayloadStore historicalStore, diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/ProtectedDataStoreService.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/ProtectedDataStoreService.java index 07f07ad7323..48df86af772 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/ProtectedDataStoreService.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/ProtectedDataStoreService.java @@ -20,6 +20,7 @@ import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.ProtectedStorageEntry; +import bisq.common.UserThread; import bisq.common.proto.persistable.PersistableEnvelope; import javax.inject.Inject; @@ -27,6 +28,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -52,8 +54,15 @@ public void addService(MapStoreService service.readFromResources(postFix)); + public void readFromResources(String postFix, Runnable completeHandler) { + AtomicInteger remaining = new AtomicInteger(services.size()); + services.forEach(service -> { + service.readFromResources(postFix, () -> { + if (remaining.decrementAndGet() == 0) { + UserThread.execute(completeHandler); + } + }); + }); } public Map getMap() { diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/ResourceDataStoreService.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/ResourceDataStoreService.java index b6002af580e..a6d3b06b514 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/ResourceDataStoreService.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/ResourceDataStoreService.java @@ -17,12 +17,14 @@ package bisq.network.p2p.storage.persistence; +import bisq.common.UserThread; import bisq.common.proto.persistable.PersistableEnvelope; import javax.inject.Inject; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import lombok.extern.slf4j.Slf4j; @@ -42,7 +44,14 @@ public void addService(StoreService service) { services.add(service); } - public void readFromResources(String postFix) { - services.forEach(service -> service.readFromResources(postFix)); + public void readFromResources(String postFix, Runnable completeHandler) { + AtomicInteger remaining = new AtomicInteger(services.size()); + services.forEach(service -> { + service.readFromResources(postFix, () -> { + if (remaining.decrementAndGet() == 0) { + UserThread.execute(completeHandler); + } + }); + }); } } diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/StoreService.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/StoreService.java index 5d1b57d9120..8e77fb2e140 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/StoreService.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/StoreService.java @@ -26,6 +26,8 @@ import java.io.File; +import java.util.function.Consumer; + import lombok.extern.slf4j.Slf4j; /** @@ -76,14 +78,14 @@ protected T getStore() { // Protected /////////////////////////////////////////////////////////////////////////////////////////// - protected void readFromResources(String postFix) { + protected void readFromResources(String postFix, Runnable completeHandler) { String fileName = getFileName(); makeFileFromResourceFile(fileName, postFix); try { - readStore(); + readStore(persisted -> completeHandler.run()); } catch (Throwable t) { makeFileFromResourceFile(fileName, postFix); - readStore(); + readStore(persisted -> completeHandler.run()); } } @@ -112,25 +114,19 @@ protected boolean makeFileFromResourceFile(String fileName, String postFix) { return false; } - protected T getStore(String fileName) { - T store; - T persisted = persistenceManager.getPersisted(fileName); - if (persisted != null) { - store = persisted; - /* int length = store.toProtoMessage().getSerializedSize(); - double size = length > 1_000_000D ? length / 1_000_000D : length / 1_000D; - String unit = length > 1_000_000D ? "MB" : "KB"; - log.info("{}: size of {}: {} {}", this.getClass().getSimpleName(), - persisted.getClass().getSimpleName(), size, unit);*/ - } else { - store = createStore(); - } - return store; + protected void readStore(String fileName, Consumer consumer) { + persistenceManager.readPersisted(fileName, + consumer, + () -> consumer.accept(createStore())); } - protected void readStore() { - store = getStore(getFileName()); - initializePersistenceManager(); + protected void readStore(Consumer consumer) { + readStore(getFileName(), + persisted -> { + store = persisted; + initializePersistenceManager(); + consumer.accept(persisted); + }); } protected abstract void initializePersistenceManager(); diff --git a/p2p/src/test/java/bisq/network/p2p/storage/mocks/MapStoreServiceFake.java b/p2p/src/test/java/bisq/network/p2p/storage/mocks/MapStoreServiceFake.java index 0f6f661fda0..9bf39989c9f 100644 --- a/p2p/src/test/java/bisq/network/p2p/storage/mocks/MapStoreServiceFake.java +++ b/p2p/src/test/java/bisq/network/p2p/storage/mocks/MapStoreServiceFake.java @@ -64,7 +64,7 @@ public boolean canHandle(PersistablePayload payload) { return true; } - protected void readFromResources(String postFix) { + protected void readFromResources(String postFix, Runnable completeHandler) { // do nothing. This Fake only supports in-memory storage. }