diff --git a/common/src/main/java/bisq/common/proto/persistable/NavigationPath.java b/common/src/main/java/bisq/common/proto/persistable/NavigationPath.java index a1cc756687..1cb22d428a 100644 --- a/common/src/main/java/bisq/common/proto/persistable/NavigationPath.java +++ b/common/src/main/java/bisq/common/proto/persistable/NavigationPath.java @@ -21,7 +21,6 @@ import bisq.common.util.CollectionUtils; import com.google.protobuf.Message; -import java.util.ArrayList; import java.util.List; import lombok.AllArgsConstructor; @@ -36,7 +35,7 @@ import lombok.Setter; @Getter @Setter public class NavigationPath implements PersistableEnvelope { - private List path = new ArrayList<>(); + private List path = List.of(); @Override public Message toProtoMessage() { @@ -45,7 +44,7 @@ public class NavigationPath implements PersistableEnvelope { return protobuf.PersistableEnvelope.newBuilder().setNavigationPath(builder).build(); } - public static PersistableEnvelope fromProto(protobuf.NavigationPath proto) { - return new NavigationPath(new ArrayList<>(proto.getPathList())); + public static NavigationPath fromProto(protobuf.NavigationPath proto) { + return new NavigationPath(List.copyOf(proto.getPathList())); } } diff --git a/common/src/main/java/bisq/common/proto/persistable/PersistableEnvelope.java b/common/src/main/java/bisq/common/proto/persistable/PersistableEnvelope.java index dfab4f0b4d..6700839eaf 100644 --- a/common/src/main/java/bisq/common/proto/persistable/PersistableEnvelope.java +++ b/common/src/main/java/bisq/common/proto/persistable/PersistableEnvelope.java @@ -19,8 +19,14 @@ package bisq.common.proto.persistable; import bisq.common.Envelope; +import com.google.protobuf.Message; + /** * Interface for the outside envelope object persisted to disk. */ public interface PersistableEnvelope extends Envelope { + + default Message toPersistableMessage() { + return toProtoMessage(); + } } diff --git a/common/src/main/java/bisq/common/proto/persistable/ThreadedPersistableEnvelope.java b/common/src/main/java/bisq/common/proto/persistable/ThreadedPersistableEnvelope.java new file mode 100644 index 0000000000..7cee389f07 --- /dev/null +++ b/common/src/main/java/bisq/common/proto/persistable/ThreadedPersistableEnvelope.java @@ -0,0 +1,44 @@ +/* + * 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.common.proto.persistable; + +import com.google.protobuf.Message; + +/** + * Interface for the outer envelope object persisted to disk, where its serialization + * during persistence takes place on a separate thread (for performance). + *

+ * To make the serialization thread-safe, all modifications of the object must be + * synchronized with it. This may be achieved by wrapping such modifications with the + * provided {@link ThreadedPersistableEnvelope#modifySynchronized(Runnable)} method. + */ +public interface ThreadedPersistableEnvelope extends PersistableEnvelope { + + @Override + default Message toPersistableMessage() { + synchronized (this) { + return toProtoMessage(); + } + } + + default void modifySynchronized(Runnable modifyTask) { + synchronized (this) { + modifyTask.run(); + } + } +} diff --git a/common/src/main/java/bisq/common/proto/persistable/UserThreadMappedPersistableEnvelope.java b/common/src/main/java/bisq/common/proto/persistable/UserThreadMappedPersistableEnvelope.java new file mode 100644 index 0000000000..aa5e84cda7 --- /dev/null +++ b/common/src/main/java/bisq/common/proto/persistable/UserThreadMappedPersistableEnvelope.java @@ -0,0 +1,45 @@ +/* + * 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.common.proto.persistable; + +import bisq.common.UserThread; + +import com.google.protobuf.Message; + +import com.google.common.util.concurrent.Futures; + +import java.util.concurrent.FutureTask; + +/** + * Interface for the outer envelope object persisted to disk, where its serialization + * during persistence is forced to take place on the user thread. + *

+ * To avoid jitter, this should be only be used for small, safely critical stores. Larger + * or frequently written stores should either implement {@link PersistableEnvelope} + * directly (where thread-safety isn't needed) or use {@link ThreadedPersistableEnvelope}. + */ +public interface UserThreadMappedPersistableEnvelope extends PersistableEnvelope { + + @Override + default Message toPersistableMessage() { + FutureTask toProtoOnUserThread = new FutureTask<>(this::toProtoMessage); + UserThread.execute(toProtoOnUserThread); + //noinspection UnstableApiUsage + return Futures.getUnchecked(toProtoOnUserThread); + } +} diff --git a/common/src/main/java/bisq/common/proto/persistable/UserThreadMappedPersistableList.java b/common/src/main/java/bisq/common/proto/persistable/UserThreadMappedPersistableList.java new file mode 100644 index 0000000000..5337af5efe --- /dev/null +++ b/common/src/main/java/bisq/common/proto/persistable/UserThreadMappedPersistableList.java @@ -0,0 +1,31 @@ +/* + * 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.common.proto.persistable; + +import java.util.List; + +public class UserThreadMappedPersistableList extends PersistableList + implements UserThreadMappedPersistableEnvelope { + + public UserThreadMappedPersistableList(List list) { + super(list); + } + + public UserThreadMappedPersistableList() { + } +} diff --git a/common/src/main/java/bisq/common/storage/FileManager.java b/common/src/main/java/bisq/common/storage/FileManager.java index 764fdcde6f..06ae86b869 100644 --- a/common/src/main/java/bisq/common/storage/FileManager.java +++ b/common/src/main/java/bisq/common/storage/FileManager.java @@ -189,7 +189,7 @@ public class FileManager { log.debug("Write to disc: {}", storageFile.getName()); protobuf.PersistableEnvelope protoPersistable; try { - protoPersistable = (protobuf.PersistableEnvelope) persistable.toProtoMessage(); + protoPersistable = (protobuf.PersistableEnvelope) persistable.toPersistableMessage(); if (protoPersistable.toByteArray().length == 0) log.error("protoPersistable is empty. persistable=" + persistable.getClass().getSimpleName()); } catch (Throwable e) { diff --git a/core/src/main/java/bisq/core/account/sign/SignedWitnessStore.java b/core/src/main/java/bisq/core/account/sign/SignedWitnessStore.java index 1f05e66ff5..8b0e340c41 100644 --- a/core/src/main/java/bisq/core/account/sign/SignedWitnessStore.java +++ b/core/src/main/java/bisq/core/account/sign/SignedWitnessStore.java @@ -21,7 +21,7 @@ package bisq.core.account.sign; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -40,7 +40,7 @@ import lombok.extern.slf4j.Slf4j; * definition and provide a hashMap for the domain access. */ @Slf4j -public class SignedWitnessStore implements PersistableEnvelope { +public class SignedWitnessStore implements ThreadedPersistableEnvelope { @Getter private Map map = new ConcurrentHashMap<>(); @@ -70,7 +70,7 @@ public class SignedWitnessStore implements PersistableEnvelope { return protobuf.SignedWitnessStore.newBuilder().addAllItems(protoList); } - public static PersistableEnvelope fromProto(protobuf.SignedWitnessStore proto) { + public static SignedWitnessStore fromProto(protobuf.SignedWitnessStore proto) { List list = proto.getItemsList().stream() .map(SignedWitness::fromProto).collect(Collectors.toList()); return new SignedWitnessStore(list); diff --git a/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStore.java b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStore.java index e25f73e28b..4731cb9e62 100644 --- a/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStore.java +++ b/core/src/main/java/bisq/core/account/witness/AccountAgeWitnessStore.java @@ -20,7 +20,7 @@ package bisq.core.account.witness; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -39,7 +39,7 @@ import lombok.extern.slf4j.Slf4j; * definition and provide a hashMap for the domain access. */ @Slf4j -public class AccountAgeWitnessStore implements PersistableEnvelope { +public class AccountAgeWitnessStore implements ThreadedPersistableEnvelope { @Getter private Map map = new ConcurrentHashMap<>(); @@ -69,7 +69,7 @@ public class AccountAgeWitnessStore implements PersistableEnvelope { return protobuf.AccountAgeWitnessStore.newBuilder().addAllItems(protoList); } - public static PersistableEnvelope fromProto(protobuf.AccountAgeWitnessStore proto) { + public static AccountAgeWitnessStore fromProto(protobuf.AccountAgeWitnessStore proto) { List list = proto.getItemsList().stream() .map(AccountAgeWitness::fromProto).collect(Collectors.toList()); return new AccountAgeWitnessStore(list); 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 867474132e..becb46dfbe 100644 --- a/core/src/main/java/bisq/core/btc/model/AddressEntryList.java +++ b/core/src/main/java/bisq/core/btc/model/AddressEntryList.java @@ -17,8 +17,8 @@ package bisq.core.btc.model; -import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.PersistedDataHost; +import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope; import bisq.common.storage.Storage; import com.google.protobuf.Message; @@ -44,7 +44,7 @@ import lombok.extern.slf4j.Slf4j; */ @ToString @Slf4j -public final class AddressEntryList implements PersistableEnvelope, PersistedDataHost { +public final class AddressEntryList implements UserThreadMappedPersistableEnvelope, PersistedDataHost { transient private Storage storage; transient private Wallet wallet; @Getter diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteList.java b/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteList.java index 47dca594eb..313fc07d34 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteList.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/MyBlindVoteList.java @@ -19,8 +19,7 @@ package bisq.core.dao.governance.blindvote; import bisq.core.dao.governance.ConsensusCritical; -import bisq.common.proto.persistable.PersistableEnvelope; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import com.google.protobuf.Message; @@ -34,7 +33,7 @@ import lombok.EqualsAndHashCode; * List of my own blind votes. Blind votes received from other voters are stored in the BlindVoteStore. */ @EqualsAndHashCode(callSuper = true) -public class MyBlindVoteList extends PersistableList implements ConsensusCritical { +public class MyBlindVoteList extends UserThreadMappedPersistableList implements ConsensusCritical { MyBlindVoteList() { super(); @@ -59,7 +58,7 @@ public class MyBlindVoteList extends PersistableList implements Conse .build(); } - public static PersistableEnvelope fromProto(protobuf.MyBlindVoteList proto) { + public static MyBlindVoteList fromProto(protobuf.MyBlindVoteList proto) { return new MyBlindVoteList(new ArrayList<>(proto.getBlindVoteList().stream() .map(BlindVote::fromProto) .collect(Collectors.toList()))); diff --git a/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVoteStore.java b/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVoteStore.java index e7f1103806..3b7266fca3 100644 --- a/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVoteStore.java +++ b/core/src/main/java/bisq/core/dao/governance/blindvote/storage/BlindVoteStore.java @@ -20,7 +20,7 @@ package bisq.core.dao.governance.blindvote.storage; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -39,7 +39,7 @@ import lombok.extern.slf4j.Slf4j; * definition and provide a hashMap for the domain access. */ @Slf4j -public class BlindVoteStore implements PersistableEnvelope { +public class BlindVoteStore implements ThreadedPersistableEnvelope { @Getter private Map map = new ConcurrentHashMap<>(); @@ -69,7 +69,7 @@ public class BlindVoteStore implements PersistableEnvelope { return protobuf.BlindVoteStore.newBuilder().addAllItems(protoList); } - public static PersistableEnvelope fromProto(protobuf.BlindVoteStore proto) { + public static BlindVoteStore fromProto(protobuf.BlindVoteStore proto) { List list = proto.getItemsList().stream() .map(BlindVotePayload::fromProto).collect(Collectors.toList()); return new BlindVoteStore(list); diff --git a/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationList.java b/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationList.java index 729ef5ae31..9e705d2642 100644 --- a/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationList.java +++ b/core/src/main/java/bisq/core/dao/governance/bond/reputation/MyReputationList.java @@ -17,7 +17,7 @@ package bisq.core.dao.governance.bond.reputation; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import java.util.ArrayList; import java.util.List; @@ -29,7 +29,7 @@ import lombok.EqualsAndHashCode; * PersistableEnvelope wrapper for list of MyReputations. */ @EqualsAndHashCode(callSuper = true) -public class MyReputationList extends PersistableList { +public class MyReputationList extends UserThreadMappedPersistableList { private MyReputationList(List list) { super(list); @@ -69,4 +69,3 @@ public class MyReputationList extends PersistableList { .collect(Collectors.toList()); } } - diff --git a/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteList.java b/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteList.java index ef66f624c9..c840faf7e6 100644 --- a/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteList.java +++ b/core/src/main/java/bisq/core/dao/governance/myvote/MyVoteList.java @@ -17,8 +17,7 @@ package bisq.core.dao.governance.myvote; -import bisq.common.proto.persistable.PersistableEnvelope; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import com.google.protobuf.Message; @@ -29,9 +28,9 @@ import java.util.stream.Collectors; import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) -public class MyVoteList extends PersistableList { +public class MyVoteList extends UserThreadMappedPersistableList { - public MyVoteList() { + MyVoteList() { super(); } @@ -53,7 +52,7 @@ public class MyVoteList extends PersistableList { .build(); } - public static PersistableEnvelope fromProto(protobuf.MyVoteList proto) { + public static MyVoteList fromProto(protobuf.MyVoteList proto) { return new MyVoteList(new ArrayList<>(proto.getMyVoteList().stream() .map(MyVote::fromProto) .collect(Collectors.toList()))); @@ -66,4 +65,3 @@ public class MyVoteList extends PersistableList { .collect(Collectors.toList()); } } - diff --git a/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnList.java b/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnList.java index ed0fb32e16..0845b4efb7 100644 --- a/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnList.java +++ b/core/src/main/java/bisq/core/dao/governance/proofofburn/MyProofOfBurnList.java @@ -17,7 +17,7 @@ package bisq.core.dao.governance.proofofburn; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import java.util.ArrayList; import java.util.List; @@ -29,7 +29,7 @@ import lombok.EqualsAndHashCode; * PersistableEnvelope wrapper for list of MyProofOfBurn objects. */ @EqualsAndHashCode(callSuper = true) -public class MyProofOfBurnList extends PersistableList { +public class MyProofOfBurnList extends UserThreadMappedPersistableList { private MyProofOfBurnList(List list) { super(list); @@ -69,4 +69,3 @@ public class MyProofOfBurnList extends PersistableList { .collect(Collectors.toList()); } } - diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalList.java b/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalList.java index 5ec0126d36..0729043232 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalList.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/MyProposalList.java @@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal; import bisq.core.dao.governance.ConsensusCritical; import bisq.core.dao.state.model.governance.Proposal; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import java.util.ArrayList; import java.util.List; @@ -32,7 +32,7 @@ import lombok.EqualsAndHashCode; * PersistableEnvelope wrapper for list of proposals. Used in vote consensus, so changes can break consensus! */ @EqualsAndHashCode(callSuper = true) -public class MyProposalList extends PersistableList implements ConsensusCritical { +public class MyProposalList extends UserThreadMappedPersistableList implements ConsensusCritical { public MyProposalList(List list) { super(list); @@ -72,4 +72,3 @@ public class MyProposalList extends PersistableList implements Consens .collect(Collectors.toList()); } } - diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalStore.java b/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalStore.java index cd18dc8274..2173f7c477 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalStore.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/storage/appendonly/ProposalStore.java @@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal.storage.appendonly; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -39,7 +39,7 @@ import lombok.extern.slf4j.Slf4j; * definition and provide a hashMap for the domain access. */ @Slf4j -public class ProposalStore implements PersistableEnvelope { +public class ProposalStore implements ThreadedPersistableEnvelope { @Getter private Map map = new ConcurrentHashMap<>(); @@ -69,7 +69,7 @@ public class ProposalStore implements PersistableEnvelope { return protobuf.ProposalStore.newBuilder().addAllItems(protoList); } - public static PersistableEnvelope fromProto(protobuf.ProposalStore proto) { + public static ProposalStore fromProto(protobuf.ProposalStore proto) { List list = proto.getItemsList().stream() .map(ProposalPayload::fromProto).collect(Collectors.toList()); return new ProposalStore(list); diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStore.java b/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStore.java index 169ba028a6..229f173368 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStore.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/storage/temp/TempProposalStore.java @@ -21,7 +21,7 @@ import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.ProtectedStorageEntry; import bisq.common.proto.network.NetworkProtoResolver; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -42,7 +42,7 @@ import lombok.extern.slf4j.Slf4j; * definition and provide a hashMap for the domain access. */ @Slf4j -public class TempProposalStore implements PersistableEnvelope { +public class TempProposalStore implements ThreadedPersistableEnvelope { @Getter private Map map = new ConcurrentHashMap<>(); @@ -72,7 +72,7 @@ public class TempProposalStore implements PersistableEnvelope { return protobuf.TempProposalStore.newBuilder().addAllItems(protoList); } - public static PersistableEnvelope fromProto(protobuf.TempProposalStore proto, NetworkProtoResolver networkProtoResolver) { + public static TempProposalStore fromProto(protobuf.TempProposalStore proto, NetworkProtoResolver networkProtoResolver) { List list = proto.getItemsList().stream() .map(entry -> ProtectedStorageEntry.fromProto(entry, networkProtoResolver)) .collect(Collectors.toList()); diff --git a/core/src/main/java/bisq/core/dao/state/DaoStateStorageService.java b/core/src/main/java/bisq/core/dao/state/DaoStateStorageService.java index 669a0c5666..2e1e9abd1d 100644 --- a/core/src/main/java/bisq/core/dao/state/DaoStateStorageService.java +++ b/core/src/main/java/bisq/core/dao/state/DaoStateStorageService.java @@ -86,8 +86,10 @@ public class DaoStateStorageService extends StoreService { } private void persist(DaoState daoState, LinkedList daoStateHashChain, long delayInMilli) { - store.setDaoState(daoState); - store.setDaoStateHashChain(daoStateHashChain); + store.modifySynchronized(() -> { + store.setDaoState(daoState); + store.setDaoStateHashChain(daoStateHashChain); + }); storage.queueUpForSave(store, delayInMilli); } diff --git a/core/src/main/java/bisq/core/dao/state/DaoStateStore.java b/core/src/main/java/bisq/core/dao/state/DaoStateStore.java index a0a28e6600..144479c281 100644 --- a/core/src/main/java/bisq/core/dao/state/DaoStateStore.java +++ b/core/src/main/java/bisq/core/dao/state/DaoStateStore.java @@ -20,7 +20,7 @@ package bisq.core.dao.state; import bisq.core.dao.monitoring.model.DaoStateHash; import bisq.core.dao.state.model.DaoState; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -35,7 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j -public class DaoStateStore implements PersistableEnvelope { +public class DaoStateStore implements ThreadedPersistableEnvelope { // DaoState is always a clone and must not be used for read access beside initial read from disc when we apply // the snapshot! @Getter @@ -67,7 +67,7 @@ public class DaoStateStore implements PersistableEnvelope { .build(); } - public static PersistableEnvelope fromProto(protobuf.DaoStateStore proto) { + public static DaoStateStore fromProto(protobuf.DaoStateStore proto) { LinkedList daoStateHashList = proto.getDaoStateHashList().isEmpty() ? new LinkedList<>() : new LinkedList<>(proto.getDaoStateHashList().stream() diff --git a/core/src/main/java/bisq/core/dao/state/model/governance/BallotList.java b/core/src/main/java/bisq/core/dao/state/model/governance/BallotList.java index b5a4651a1a..d3b4a1f97e 100644 --- a/core/src/main/java/bisq/core/dao/state/model/governance/BallotList.java +++ b/core/src/main/java/bisq/core/dao/state/model/governance/BallotList.java @@ -20,7 +20,7 @@ package bisq.core.dao.state.model.governance; import bisq.core.dao.governance.ConsensusCritical; import bisq.core.dao.state.model.ImmutableDaoStateModel; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import java.util.ArrayList; import java.util.List; @@ -35,7 +35,7 @@ import javax.annotation.concurrent.Immutable; */ @Immutable @EqualsAndHashCode(callSuper = true) -public class BallotList extends PersistableList implements ConsensusCritical, ImmutableDaoStateModel { +public class BallotList extends UserThreadMappedPersistableList implements ConsensusCritical, ImmutableDaoStateModel { public BallotList(List list) { super(list); @@ -75,4 +75,3 @@ public class BallotList extends PersistableList implements ConsensusCrit .collect(Collectors.toList()); } } - diff --git a/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputList.java b/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputList.java index 141bc1a853..391afda22f 100644 --- a/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputList.java +++ b/core/src/main/java/bisq/core/dao/state/unconfirmed/UnconfirmedBsqChangeOutputList.java @@ -17,8 +17,7 @@ package bisq.core.dao.state.unconfirmed; -import bisq.common.proto.persistable.PersistableEnvelope; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import com.google.protobuf.Message; @@ -29,7 +28,7 @@ import java.util.stream.Collectors; import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) -public class UnconfirmedBsqChangeOutputList extends PersistableList { +public class UnconfirmedBsqChangeOutputList extends UserThreadMappedPersistableList { UnconfirmedBsqChangeOutputList() { super(); @@ -52,7 +51,7 @@ public class UnconfirmedBsqChangeOutputList extends PersistableList(proto.getUnconfirmedTxOutputList().stream() .map(UnconfirmedTxOutput::fromProto) .collect(Collectors.toList()))); diff --git a/core/src/main/java/bisq/core/payment/PaymentAccountList.java b/core/src/main/java/bisq/core/payment/PaymentAccountList.java index edd2169538..efe9cccc22 100644 --- a/core/src/main/java/bisq/core/payment/PaymentAccountList.java +++ b/core/src/main/java/bisq/core/payment/PaymentAccountList.java @@ -19,8 +19,7 @@ package bisq.core.payment; import bisq.core.proto.CoreProtoResolver; -import bisq.common.proto.persistable.PersistableEnvelope; -import bisq.common.proto.persistable.PersistableList; +import bisq.common.proto.persistable.UserThreadMappedPersistableList; import com.google.protobuf.Message; @@ -31,7 +30,7 @@ import java.util.stream.Collectors; import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) -public class PaymentAccountList extends PersistableList { +public class PaymentAccountList extends UserThreadMappedPersistableList { public PaymentAccountList(List list) { super(list); @@ -45,7 +44,7 @@ public class PaymentAccountList extends PersistableList { .build(); } - public static PersistableEnvelope fromProto(protobuf.PaymentAccountList proto, CoreProtoResolver coreProtoResolver) { + public static PaymentAccountList fromProto(protobuf.PaymentAccountList proto, CoreProtoResolver coreProtoResolver) { return new PaymentAccountList(new ArrayList<>(proto.getPaymentAccountList().stream() .map(e -> PaymentAccount.fromProto(e, coreProtoResolver)) .collect(Collectors.toList()))); diff --git a/core/src/main/java/bisq/core/support/dispute/DisputeList.java b/core/src/main/java/bisq/core/support/dispute/DisputeList.java index d2dd6cca12..468699c4ab 100644 --- a/core/src/main/java/bisq/core/support/dispute/DisputeList.java +++ b/core/src/main/java/bisq/core/support/dispute/DisputeList.java @@ -19,6 +19,7 @@ package bisq.core.support.dispute; import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.PersistedDataHost; +import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope; import bisq.common.storage.Storage; import javafx.collections.FXCollections; @@ -39,7 +40,7 @@ import lombok.extern.slf4j.Slf4j; * Calls to the List are delegated because this class intercepts the add/remove calls so changes * can be saved to disc. */ -public abstract class DisputeList implements PersistableEnvelope, PersistedDataHost { +public abstract class DisputeList implements UserThreadMappedPersistableEnvelope, PersistedDataHost { transient protected final Storage storage; @Getter diff --git a/core/src/main/java/bisq/core/trade/TradableList.java b/core/src/main/java/bisq/core/trade/TradableList.java index 9e0b9cf3b3..eae2c3a60b 100644 --- a/core/src/main/java/bisq/core/trade/TradableList.java +++ b/core/src/main/java/bisq/core/trade/TradableList.java @@ -23,7 +23,7 @@ import bisq.core.proto.CoreProtoResolver; import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtobufferRuntimeException; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope; import bisq.common.storage.Storage; import com.google.protobuf.Message; @@ -41,7 +41,7 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; @Slf4j -public final class TradableList implements PersistableEnvelope { +public final class TradableList implements UserThreadMappedPersistableEnvelope { transient final private Storage> storage; @Getter private final ObservableList list = FXCollections.observableArrayList(); @@ -78,10 +78,10 @@ public final class TradableList implements PersistableEnvelo .build(); } - public static TradableList fromProto(protobuf.TradableList proto, - CoreProtoResolver coreProtoResolver, - Storage> storage, - BtcWalletService btcWalletService) { + public static TradableList fromProto(protobuf.TradableList proto, + CoreProtoResolver coreProtoResolver, + Storage> storage, + BtcWalletService btcWalletService) { List list = proto.getTradableList().stream() .map(tradable -> { switch (tradable.getMessageCase()) { diff --git a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2Store.java b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2Store.java index f84be42cf2..d3ea468907 100644 --- a/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2Store.java +++ b/core/src/main/java/bisq/core/trade/statistics/TradeStatistics2Store.java @@ -20,7 +20,7 @@ package bisq.core.trade.statistics; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -38,7 +38,7 @@ import lombok.extern.slf4j.Slf4j; * definition and provide a hashMap for the domain access. */ @Slf4j -public class TradeStatistics2Store implements PersistableEnvelope { +public class TradeStatistics2Store implements ThreadedPersistableEnvelope { @Getter private Map map = new ConcurrentHashMap<>(); @@ -68,7 +68,7 @@ public class TradeStatistics2Store implements PersistableEnvelope { return protobuf.TradeStatistics2Store.newBuilder().addAllItems(protoList); } - public static PersistableEnvelope fromProto(protobuf.TradeStatistics2Store proto) { + public static TradeStatistics2Store fromProto(protobuf.TradeStatistics2Store proto) { List list = proto.getItemsList().stream() .map(TradeStatistics2::fromProto).collect(Collectors.toList()); return new TradeStatistics2Store(list); diff --git a/core/src/main/java/bisq/core/user/PreferencesPayload.java b/core/src/main/java/bisq/core/user/PreferencesPayload.java index 15b4bbe466..3e0997d68b 100644 --- a/core/src/main/java/bisq/core/user/PreferencesPayload.java +++ b/core/src/main/java/bisq/core/user/PreferencesPayload.java @@ -25,7 +25,7 @@ import bisq.core.payment.PaymentAccount; import bisq.core.proto.CoreProtoResolver; import bisq.common.proto.ProtoUtil; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope; import com.google.protobuf.Message; @@ -49,7 +49,7 @@ import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAs @Slf4j @Data @AllArgsConstructor -public final class PreferencesPayload implements PersistableEnvelope { +public final class PreferencesPayload implements UserThreadMappedPersistableEnvelope { private String userLanguage; private Country userCountry; @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @@ -132,7 +132,7 @@ public final class PreferencesPayload implements PersistableEnvelope { // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public PreferencesPayload() { + PreferencesPayload() { } @@ -207,7 +207,7 @@ public final class PreferencesPayload implements PersistableEnvelope { return protobuf.PersistableEnvelope.newBuilder().setPreferencesPayload(builder).build(); } - public static PersistableEnvelope fromProto(protobuf.PreferencesPayload proto, CoreProtoResolver coreProtoResolver) { + public static PreferencesPayload fromProto(protobuf.PreferencesPayload proto, CoreProtoResolver coreProtoResolver) { final protobuf.Country userCountry = proto.getUserCountry(); PaymentAccount paymentAccount = null; if (proto.hasSelectedPaymentAccountForCreateOffer() && proto.getSelectedPaymentAccountForCreateOffer().hasPaymentMethod()) @@ -275,6 +275,5 @@ public final class PreferencesPayload implements PersistableEnvelope { proto.getBuyerSecurityDepositAsPercentForCrypto(), proto.getBlockNotifyPort(), proto.getTacAcceptedV120()); - } } diff --git a/core/src/main/java/bisq/core/user/UserPayload.java b/core/src/main/java/bisq/core/user/UserPayload.java index 212570a6f7..f7bbb5ab03 100644 --- a/core/src/main/java/bisq/core/user/UserPayload.java +++ b/core/src/main/java/bisq/core/user/UserPayload.java @@ -28,7 +28,7 @@ import bisq.core.support.dispute.mediation.mediator.Mediator; import bisq.core.support.dispute.refund.refundagent.RefundAgent; import bisq.common.proto.ProtoUtil; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope; import java.util.ArrayList; import java.util.HashSet; @@ -46,7 +46,7 @@ import javax.annotation.Nullable; @Slf4j @Data @AllArgsConstructor -public class UserPayload implements PersistableEnvelope { +public class UserPayload implements UserThreadMappedPersistableEnvelope { @Nullable private String accountId; @Nullable diff --git a/desktop/src/main/java/bisq/desktop/Navigation.java b/desktop/src/main/java/bisq/desktop/Navigation.java index 020b0720a4..0efeb8cc98 100644 --- a/desktop/src/main/java/bisq/desktop/Navigation.java +++ b/desktop/src/main/java/bisq/desktop/Navigation.java @@ -141,7 +141,7 @@ public final class Navigation implements PersistedDataHost { private void queueUpForSave() { if (currentPath.tip() != null) { - navigationPath.setPath(currentPath.stream().map(Class::getName).collect(Collectors.toList())); + navigationPath.setPath(currentPath.stream().map(Class::getName).collect(Collectors.toUnmodifiableList())); } storage.queueUpForSave(navigationPath, 1000); } diff --git a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/PeerList.java b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/PeerList.java index 03acd3f930..b09c67df06 100644 --- a/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/PeerList.java +++ b/p2p/src/main/java/bisq/network/p2p/peers/peerexchange/PeerList.java @@ -18,7 +18,6 @@ package bisq.network.p2p.peers.peerexchange; import bisq.common.proto.persistable.PersistableEnvelope; -import bisq.common.proto.persistable.PersistableList; import com.google.protobuf.Message; @@ -27,23 +26,30 @@ import java.util.List; import java.util.stream.Collectors; import lombok.EqualsAndHashCode; +import lombok.Getter; -@EqualsAndHashCode(callSuper = true) -public class PeerList extends PersistableList { +@EqualsAndHashCode +public class PeerList implements PersistableEnvelope { + @Getter + private final List list; public PeerList(List list) { - super(list); + this.list = list; + } + + public int size() { + return list.size(); } @Override public Message toProtoMessage() { return protobuf.PersistableEnvelope.newBuilder() .setPeerList(protobuf.PeerList.newBuilder() - .addAllPeer(getList().stream().map(Peer::toProtoMessage).collect(Collectors.toList()))) + .addAllPeer(list.stream().map(Peer::toProtoMessage).collect(Collectors.toList()))) .build(); } - public static PersistableEnvelope fromProto(protobuf.PeerList proto) { + public static PeerList fromProto(protobuf.PeerList proto) { return new PeerList(new ArrayList<>(proto.getPeerList().stream() .map(Peer::fromProto) .collect(Collectors.toList()))); diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/PersistableNetworkPayloadList.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/PersistableNetworkPayloadList.java index e3e74aa479..50cb5d7b20 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/PersistableNetworkPayloadList.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/PersistableNetworkPayloadList.java @@ -20,8 +20,8 @@ package bisq.network.p2p.storage.persistence; import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.payload.PersistableNetworkPayload; -import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.PersistenceProtoResolver; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import com.google.protobuf.Message; @@ -42,11 +42,11 @@ import lombok.extern.slf4j.Slf4j; // TODO at next hard fork we can rename the PB definition and class name. @Deprecated @Slf4j -public class PersistableNetworkPayloadList implements PersistableEnvelope { +public class PersistableNetworkPayloadList implements ThreadedPersistableEnvelope { @Getter private Map map = new ConcurrentHashMap<>(); - public PersistableNetworkPayloadList() { + PersistableNetworkPayloadList() { } @@ -54,7 +54,7 @@ public class PersistableNetworkPayloadList implements PersistableEnvelope { // PROTO BUFFER /////////////////////////////////////////////////////////////////////////////////////////// - public PersistableNetworkPayloadList(Map map) { + private PersistableNetworkPayloadList(Map map) { this.map.putAll(map); } @@ -69,8 +69,8 @@ public class PersistableNetworkPayloadList implements PersistableEnvelope { .build(); } - public static PersistableEnvelope fromProto(protobuf.PersistableNetworkPayloadList proto, - PersistenceProtoResolver resolver) { + public static PersistableNetworkPayloadList fromProto(protobuf.PersistableNetworkPayloadList proto, + PersistenceProtoResolver resolver) { Map map = new HashMap<>(); proto.getItemsList() .forEach(e -> { diff --git a/p2p/src/main/java/bisq/network/p2p/storage/persistence/SequenceNumberMap.java b/p2p/src/main/java/bisq/network/p2p/storage/persistence/SequenceNumberMap.java index cd82336000..cbb4f77398 100644 --- a/p2p/src/main/java/bisq/network/p2p/storage/persistence/SequenceNumberMap.java +++ b/p2p/src/main/java/bisq/network/p2p/storage/persistence/SequenceNumberMap.java @@ -19,7 +19,7 @@ package bisq.network.p2p.storage.persistence; import bisq.network.p2p.storage.P2PDataStorage; -import bisq.common.proto.persistable.PersistableEnvelope; +import bisq.common.proto.persistable.ThreadedPersistableEnvelope; import java.util.HashMap; import java.util.Map; @@ -34,7 +34,7 @@ import lombok.Setter; * in protobuffer the map construct can't be anything, so the straightforward mapping was not possible. * Hence this Persistable class. */ -public class SequenceNumberMap implements PersistableEnvelope { +public class SequenceNumberMap implements ThreadedPersistableEnvelope { @Getter @Setter private Map map = new ConcurrentHashMap<>(); @@ -70,7 +70,7 @@ public class SequenceNumberMap implements PersistableEnvelope { public static SequenceNumberMap fromProto(protobuf.SequenceNumberMap proto) { HashMap map = new HashMap<>(); - proto.getSequenceNumberEntriesList().stream() + proto.getSequenceNumberEntriesList() .forEach(e -> map.put(P2PDataStorage.ByteArray.fromProto(e.getBytes()), P2PDataStorage.MapValue.fromProto(e.getMapValue()))); return new SequenceNumberMap(map); }