Merge pull request #4025 from stejbac/make-persistence-thread-safe

Make serialisation in FileManager::saveToFile thread-safe
This commit is contained in:
Christoph Atteneder 2020-03-23 13:49:27 +01:00 committed by GitHub
commit 557ec7f449
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 214 additions and 90 deletions

View file

@ -21,7 +21,6 @@ import bisq.common.util.CollectionUtils;
import com.google.protobuf.Message; import com.google.protobuf.Message;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -36,7 +35,7 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class NavigationPath implements PersistableEnvelope { public class NavigationPath implements PersistableEnvelope {
private List<String> path = new ArrayList<>(); private List<String> path = List.of();
@Override @Override
public Message toProtoMessage() { public Message toProtoMessage() {
@ -45,7 +44,7 @@ public class NavigationPath implements PersistableEnvelope {
return protobuf.PersistableEnvelope.newBuilder().setNavigationPath(builder).build(); return protobuf.PersistableEnvelope.newBuilder().setNavigationPath(builder).build();
} }
public static PersistableEnvelope fromProto(protobuf.NavigationPath proto) { public static NavigationPath fromProto(protobuf.NavigationPath proto) {
return new NavigationPath(new ArrayList<>(proto.getPathList())); return new NavigationPath(List.copyOf(proto.getPathList()));
} }
} }

View file

@ -19,8 +19,14 @@ package bisq.common.proto.persistable;
import bisq.common.Envelope; import bisq.common.Envelope;
import com.google.protobuf.Message;
/** /**
* Interface for the outside envelope object persisted to disk. * Interface for the outside envelope object persisted to disk.
*/ */
public interface PersistableEnvelope extends Envelope { public interface PersistableEnvelope extends Envelope {
default Message toPersistableMessage() {
return toProtoMessage();
}
} }

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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).
* <p>
* 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();
}
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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.
* <p>
* 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<Message> toProtoOnUserThread = new FutureTask<>(this::toProtoMessage);
UserThread.execute(toProtoOnUserThread);
//noinspection UnstableApiUsage
return Futures.getUnchecked(toProtoOnUserThread);
}
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
package bisq.common.proto.persistable;
import java.util.List;
public class UserThreadMappedPersistableList<T extends PersistablePayload> extends PersistableList<T>
implements UserThreadMappedPersistableEnvelope {
public UserThreadMappedPersistableList(List<T> list) {
super(list);
}
public UserThreadMappedPersistableList() {
}
}

View file

@ -189,7 +189,7 @@ public class FileManager<T extends PersistableEnvelope> {
log.debug("Write to disc: {}", storageFile.getName()); log.debug("Write to disc: {}", storageFile.getName());
protobuf.PersistableEnvelope protoPersistable; protobuf.PersistableEnvelope protoPersistable;
try { try {
protoPersistable = (protobuf.PersistableEnvelope) persistable.toProtoMessage(); protoPersistable = (protobuf.PersistableEnvelope) persistable.toPersistableMessage();
if (protoPersistable.toByteArray().length == 0) if (protoPersistable.toByteArray().length == 0)
log.error("protoPersistable is empty. persistable=" + persistable.getClass().getSimpleName()); log.error("protoPersistable is empty. persistable=" + persistable.getClass().getSimpleName());
} catch (Throwable e) { } catch (Throwable e) {

View file

@ -21,7 +21,7 @@ package bisq.core.account.sign;
import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -40,7 +40,7 @@ import lombok.extern.slf4j.Slf4j;
* definition and provide a hashMap for the domain access. * definition and provide a hashMap for the domain access.
*/ */
@Slf4j @Slf4j
public class SignedWitnessStore implements PersistableEnvelope { public class SignedWitnessStore implements ThreadedPersistableEnvelope {
@Getter @Getter
private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>();
@ -70,7 +70,7 @@ public class SignedWitnessStore implements PersistableEnvelope {
return protobuf.SignedWitnessStore.newBuilder().addAllItems(protoList); return protobuf.SignedWitnessStore.newBuilder().addAllItems(protoList);
} }
public static PersistableEnvelope fromProto(protobuf.SignedWitnessStore proto) { public static SignedWitnessStore fromProto(protobuf.SignedWitnessStore proto) {
List<SignedWitness> list = proto.getItemsList().stream() List<SignedWitness> list = proto.getItemsList().stream()
.map(SignedWitness::fromProto).collect(Collectors.toList()); .map(SignedWitness::fromProto).collect(Collectors.toList());
return new SignedWitnessStore(list); return new SignedWitnessStore(list);

View file

@ -20,7 +20,7 @@ package bisq.core.account.witness;
import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -39,7 +39,7 @@ import lombok.extern.slf4j.Slf4j;
* definition and provide a hashMap for the domain access. * definition and provide a hashMap for the domain access.
*/ */
@Slf4j @Slf4j
public class AccountAgeWitnessStore implements PersistableEnvelope { public class AccountAgeWitnessStore implements ThreadedPersistableEnvelope {
@Getter @Getter
private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>();
@ -69,7 +69,7 @@ public class AccountAgeWitnessStore implements PersistableEnvelope {
return protobuf.AccountAgeWitnessStore.newBuilder().addAllItems(protoList); return protobuf.AccountAgeWitnessStore.newBuilder().addAllItems(protoList);
} }
public static PersistableEnvelope fromProto(protobuf.AccountAgeWitnessStore proto) { public static AccountAgeWitnessStore fromProto(protobuf.AccountAgeWitnessStore proto) {
List<AccountAgeWitness> list = proto.getItemsList().stream() List<AccountAgeWitness> list = proto.getItemsList().stream()
.map(AccountAgeWitness::fromProto).collect(Collectors.toList()); .map(AccountAgeWitness::fromProto).collect(Collectors.toList());
return new AccountAgeWitnessStore(list); return new AccountAgeWitnessStore(list);

View file

@ -17,8 +17,8 @@
package bisq.core.btc.model; package bisq.core.btc.model;
import bisq.common.proto.persistable.PersistableEnvelope;
import bisq.common.proto.persistable.PersistedDataHost; import bisq.common.proto.persistable.PersistedDataHost;
import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope;
import bisq.common.storage.Storage; import bisq.common.storage.Storage;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -44,7 +44,7 @@ import lombok.extern.slf4j.Slf4j;
*/ */
@ToString @ToString
@Slf4j @Slf4j
public final class AddressEntryList implements PersistableEnvelope, PersistedDataHost { public final class AddressEntryList implements UserThreadMappedPersistableEnvelope, PersistedDataHost {
transient private Storage<AddressEntryList> storage; transient private Storage<AddressEntryList> storage;
transient private Wallet wallet; transient private Wallet wallet;
@Getter @Getter

View file

@ -19,8 +19,7 @@ package bisq.core.dao.governance.blindvote;
import bisq.core.dao.governance.ConsensusCritical; import bisq.core.dao.governance.ConsensusCritical;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.UserThreadMappedPersistableList;
import bisq.common.proto.persistable.PersistableList;
import com.google.protobuf.Message; 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. * List of my own blind votes. Blind votes received from other voters are stored in the BlindVoteStore.
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class MyBlindVoteList extends PersistableList<BlindVote> implements ConsensusCritical { public class MyBlindVoteList extends UserThreadMappedPersistableList<BlindVote> implements ConsensusCritical {
MyBlindVoteList() { MyBlindVoteList() {
super(); super();
@ -59,7 +58,7 @@ public class MyBlindVoteList extends PersistableList<BlindVote> implements Conse
.build(); .build();
} }
public static PersistableEnvelope fromProto(protobuf.MyBlindVoteList proto) { public static MyBlindVoteList fromProto(protobuf.MyBlindVoteList proto) {
return new MyBlindVoteList(new ArrayList<>(proto.getBlindVoteList().stream() return new MyBlindVoteList(new ArrayList<>(proto.getBlindVoteList().stream()
.map(BlindVote::fromProto) .map(BlindVote::fromProto)
.collect(Collectors.toList()))); .collect(Collectors.toList())));

View file

@ -20,7 +20,7 @@ package bisq.core.dao.governance.blindvote.storage;
import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -39,7 +39,7 @@ import lombok.extern.slf4j.Slf4j;
* definition and provide a hashMap for the domain access. * definition and provide a hashMap for the domain access.
*/ */
@Slf4j @Slf4j
public class BlindVoteStore implements PersistableEnvelope { public class BlindVoteStore implements ThreadedPersistableEnvelope {
@Getter @Getter
private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>();
@ -69,7 +69,7 @@ public class BlindVoteStore implements PersistableEnvelope {
return protobuf.BlindVoteStore.newBuilder().addAllItems(protoList); return protobuf.BlindVoteStore.newBuilder().addAllItems(protoList);
} }
public static PersistableEnvelope fromProto(protobuf.BlindVoteStore proto) { public static BlindVoteStore fromProto(protobuf.BlindVoteStore proto) {
List<BlindVotePayload> list = proto.getItemsList().stream() List<BlindVotePayload> list = proto.getItemsList().stream()
.map(BlindVotePayload::fromProto).collect(Collectors.toList()); .map(BlindVotePayload::fromProto).collect(Collectors.toList());
return new BlindVoteStore(list); return new BlindVoteStore(list);

View file

@ -17,7 +17,7 @@
package bisq.core.dao.governance.bond.reputation; 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.ArrayList;
import java.util.List; import java.util.List;
@ -29,7 +29,7 @@ import lombok.EqualsAndHashCode;
* PersistableEnvelope wrapper for list of MyReputations. * PersistableEnvelope wrapper for list of MyReputations.
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class MyReputationList extends PersistableList<MyReputation> { public class MyReputationList extends UserThreadMappedPersistableList<MyReputation> {
private MyReputationList(List<MyReputation> list) { private MyReputationList(List<MyReputation> list) {
super(list); super(list);
@ -69,4 +69,3 @@ public class MyReputationList extends PersistableList<MyReputation> {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View file

@ -17,8 +17,7 @@
package bisq.core.dao.governance.myvote; package bisq.core.dao.governance.myvote;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.UserThreadMappedPersistableList;
import bisq.common.proto.persistable.PersistableList;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -29,9 +28,9 @@ import java.util.stream.Collectors;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class MyVoteList extends PersistableList<MyVote> { public class MyVoteList extends UserThreadMappedPersistableList<MyVote> {
public MyVoteList() { MyVoteList() {
super(); super();
} }
@ -53,7 +52,7 @@ public class MyVoteList extends PersistableList<MyVote> {
.build(); .build();
} }
public static PersistableEnvelope fromProto(protobuf.MyVoteList proto) { public static MyVoteList fromProto(protobuf.MyVoteList proto) {
return new MyVoteList(new ArrayList<>(proto.getMyVoteList().stream() return new MyVoteList(new ArrayList<>(proto.getMyVoteList().stream()
.map(MyVote::fromProto) .map(MyVote::fromProto)
.collect(Collectors.toList()))); .collect(Collectors.toList())));
@ -66,4 +65,3 @@ public class MyVoteList extends PersistableList<MyVote> {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View file

@ -17,7 +17,7 @@
package bisq.core.dao.governance.proofofburn; 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.ArrayList;
import java.util.List; import java.util.List;
@ -29,7 +29,7 @@ import lombok.EqualsAndHashCode;
* PersistableEnvelope wrapper for list of MyProofOfBurn objects. * PersistableEnvelope wrapper for list of MyProofOfBurn objects.
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class MyProofOfBurnList extends PersistableList<MyProofOfBurn> { public class MyProofOfBurnList extends UserThreadMappedPersistableList<MyProofOfBurn> {
private MyProofOfBurnList(List<MyProofOfBurn> list) { private MyProofOfBurnList(List<MyProofOfBurn> list) {
super(list); super(list);
@ -69,4 +69,3 @@ public class MyProofOfBurnList extends PersistableList<MyProofOfBurn> {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View file

@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal;
import bisq.core.dao.governance.ConsensusCritical; import bisq.core.dao.governance.ConsensusCritical;
import bisq.core.dao.state.model.governance.Proposal; 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.ArrayList;
import java.util.List; 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! * PersistableEnvelope wrapper for list of proposals. Used in vote consensus, so changes can break consensus!
*/ */
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class MyProposalList extends PersistableList<Proposal> implements ConsensusCritical { public class MyProposalList extends UserThreadMappedPersistableList<Proposal> implements ConsensusCritical {
public MyProposalList(List<Proposal> list) { public MyProposalList(List<Proposal> list) {
super(list); super(list);
@ -72,4 +72,3 @@ public class MyProposalList extends PersistableList<Proposal> implements Consens
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View file

@ -20,7 +20,7 @@ package bisq.core.dao.governance.proposal.storage.appendonly;
import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -39,7 +39,7 @@ import lombok.extern.slf4j.Slf4j;
* definition and provide a hashMap for the domain access. * definition and provide a hashMap for the domain access.
*/ */
@Slf4j @Slf4j
public class ProposalStore implements PersistableEnvelope { public class ProposalStore implements ThreadedPersistableEnvelope {
@Getter @Getter
private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>();
@ -69,7 +69,7 @@ public class ProposalStore implements PersistableEnvelope {
return protobuf.ProposalStore.newBuilder().addAllItems(protoList); return protobuf.ProposalStore.newBuilder().addAllItems(protoList);
} }
public static PersistableEnvelope fromProto(protobuf.ProposalStore proto) { public static ProposalStore fromProto(protobuf.ProposalStore proto) {
List<ProposalPayload> list = proto.getItemsList().stream() List<ProposalPayload> list = proto.getItemsList().stream()
.map(ProposalPayload::fromProto).collect(Collectors.toList()); .map(ProposalPayload::fromProto).collect(Collectors.toList());
return new ProposalStore(list); return new ProposalStore(list);

View file

@ -21,7 +21,7 @@ import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.ProtectedStorageEntry; import bisq.network.p2p.storage.payload.ProtectedStorageEntry;
import bisq.common.proto.network.NetworkProtoResolver; import bisq.common.proto.network.NetworkProtoResolver;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -42,7 +42,7 @@ import lombok.extern.slf4j.Slf4j;
* definition and provide a hashMap for the domain access. * definition and provide a hashMap for the domain access.
*/ */
@Slf4j @Slf4j
public class TempProposalStore implements PersistableEnvelope { public class TempProposalStore implements ThreadedPersistableEnvelope {
@Getter @Getter
private Map<P2PDataStorage.ByteArray, ProtectedStorageEntry> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, ProtectedStorageEntry> map = new ConcurrentHashMap<>();
@ -72,7 +72,7 @@ public class TempProposalStore implements PersistableEnvelope {
return protobuf.TempProposalStore.newBuilder().addAllItems(protoList); 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<ProtectedStorageEntry> list = proto.getItemsList().stream() List<ProtectedStorageEntry> list = proto.getItemsList().stream()
.map(entry -> ProtectedStorageEntry.fromProto(entry, networkProtoResolver)) .map(entry -> ProtectedStorageEntry.fromProto(entry, networkProtoResolver))
.collect(Collectors.toList()); .collect(Collectors.toList());

View file

@ -86,8 +86,10 @@ public class DaoStateStorageService extends StoreService<DaoStateStore> {
} }
private void persist(DaoState daoState, LinkedList<DaoStateHash> daoStateHashChain, long delayInMilli) { private void persist(DaoState daoState, LinkedList<DaoStateHash> daoStateHashChain, long delayInMilli) {
store.setDaoState(daoState); store.modifySynchronized(() -> {
store.setDaoStateHashChain(daoStateHashChain); store.setDaoState(daoState);
store.setDaoStateHashChain(daoStateHashChain);
});
storage.queueUpForSave(store, delayInMilli); storage.queueUpForSave(store, delayInMilli);
} }

View file

@ -20,7 +20,7 @@ package bisq.core.dao.state;
import bisq.core.dao.monitoring.model.DaoStateHash; import bisq.core.dao.monitoring.model.DaoStateHash;
import bisq.core.dao.state.model.DaoState; import bisq.core.dao.state.model.DaoState;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -35,7 +35,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
@Slf4j @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 // DaoState is always a clone and must not be used for read access beside initial read from disc when we apply
// the snapshot! // the snapshot!
@Getter @Getter
@ -67,7 +67,7 @@ public class DaoStateStore implements PersistableEnvelope {
.build(); .build();
} }
public static PersistableEnvelope fromProto(protobuf.DaoStateStore proto) { public static DaoStateStore fromProto(protobuf.DaoStateStore proto) {
LinkedList<DaoStateHash> daoStateHashList = proto.getDaoStateHashList().isEmpty() ? LinkedList<DaoStateHash> daoStateHashList = proto.getDaoStateHashList().isEmpty() ?
new LinkedList<>() : new LinkedList<>() :
new LinkedList<>(proto.getDaoStateHashList().stream() new LinkedList<>(proto.getDaoStateHashList().stream()

View file

@ -20,7 +20,7 @@ package bisq.core.dao.state.model.governance;
import bisq.core.dao.governance.ConsensusCritical; import bisq.core.dao.governance.ConsensusCritical;
import bisq.core.dao.state.model.ImmutableDaoStateModel; 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.ArrayList;
import java.util.List; import java.util.List;
@ -35,7 +35,7 @@ import javax.annotation.concurrent.Immutable;
*/ */
@Immutable @Immutable
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class BallotList extends PersistableList<Ballot> implements ConsensusCritical, ImmutableDaoStateModel { public class BallotList extends UserThreadMappedPersistableList<Ballot> implements ConsensusCritical, ImmutableDaoStateModel {
public BallotList(List<Ballot> list) { public BallotList(List<Ballot> list) {
super(list); super(list);
@ -75,4 +75,3 @@ public class BallotList extends PersistableList<Ballot> implements ConsensusCrit
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View file

@ -17,8 +17,7 @@
package bisq.core.dao.state.unconfirmed; package bisq.core.dao.state.unconfirmed;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.UserThreadMappedPersistableList;
import bisq.common.proto.persistable.PersistableList;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -29,7 +28,7 @@ import java.util.stream.Collectors;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class UnconfirmedBsqChangeOutputList extends PersistableList<UnconfirmedTxOutput> { public class UnconfirmedBsqChangeOutputList extends UserThreadMappedPersistableList<UnconfirmedTxOutput> {
UnconfirmedBsqChangeOutputList() { UnconfirmedBsqChangeOutputList() {
super(); super();
@ -52,7 +51,7 @@ public class UnconfirmedBsqChangeOutputList extends PersistableList<UnconfirmedT
.build(); .build();
} }
public static PersistableEnvelope fromProto(protobuf.UnconfirmedBsqChangeOutputList proto) { public static UnconfirmedBsqChangeOutputList fromProto(protobuf.UnconfirmedBsqChangeOutputList proto) {
return new UnconfirmedBsqChangeOutputList(new ArrayList<>(proto.getUnconfirmedTxOutputList().stream() return new UnconfirmedBsqChangeOutputList(new ArrayList<>(proto.getUnconfirmedTxOutputList().stream()
.map(UnconfirmedTxOutput::fromProto) .map(UnconfirmedTxOutput::fromProto)
.collect(Collectors.toList()))); .collect(Collectors.toList())));

View file

@ -19,8 +19,7 @@ package bisq.core.payment;
import bisq.core.proto.CoreProtoResolver; import bisq.core.proto.CoreProtoResolver;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.UserThreadMappedPersistableList;
import bisq.common.proto.persistable.PersistableList;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -31,7 +30,7 @@ import java.util.stream.Collectors;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public class PaymentAccountList extends PersistableList<PaymentAccount> { public class PaymentAccountList extends UserThreadMappedPersistableList<PaymentAccount> {
public PaymentAccountList(List<PaymentAccount> list) { public PaymentAccountList(List<PaymentAccount> list) {
super(list); super(list);
@ -45,7 +44,7 @@ public class PaymentAccountList extends PersistableList<PaymentAccount> {
.build(); .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() return new PaymentAccountList(new ArrayList<>(proto.getPaymentAccountList().stream()
.map(e -> PaymentAccount.fromProto(e, coreProtoResolver)) .map(e -> PaymentAccount.fromProto(e, coreProtoResolver))
.collect(Collectors.toList()))); .collect(Collectors.toList())));

View file

@ -19,6 +19,7 @@ package bisq.core.support.dispute;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.PersistableEnvelope;
import bisq.common.proto.persistable.PersistedDataHost; import bisq.common.proto.persistable.PersistedDataHost;
import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope;
import bisq.common.storage.Storage; import bisq.common.storage.Storage;
import javafx.collections.FXCollections; 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 * Calls to the List are delegated because this class intercepts the add/remove calls so changes
* can be saved to disc. * can be saved to disc.
*/ */
public abstract class DisputeList<T extends PersistableEnvelope> implements PersistableEnvelope, PersistedDataHost { public abstract class DisputeList<T extends PersistableEnvelope> implements UserThreadMappedPersistableEnvelope, PersistedDataHost {
transient protected final Storage<T> storage; transient protected final Storage<T> storage;
@Getter @Getter

View file

@ -23,7 +23,7 @@ import bisq.core.proto.CoreProtoResolver;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import bisq.common.proto.ProtobufferRuntimeException; import bisq.common.proto.ProtobufferRuntimeException;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope;
import bisq.common.storage.Storage; import bisq.common.storage.Storage;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -41,7 +41,7 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public final class TradableList<T extends Tradable> implements PersistableEnvelope { public final class TradableList<T extends Tradable> implements UserThreadMappedPersistableEnvelope {
transient final private Storage<TradableList<T>> storage; transient final private Storage<TradableList<T>> storage;
@Getter @Getter
private final ObservableList<T> list = FXCollections.observableArrayList(); private final ObservableList<T> list = FXCollections.observableArrayList();
@ -78,10 +78,10 @@ public final class TradableList<T extends Tradable> implements PersistableEnvelo
.build(); .build();
} }
public static TradableList fromProto(protobuf.TradableList proto, public static TradableList<Tradable> fromProto(protobuf.TradableList proto,
CoreProtoResolver coreProtoResolver, CoreProtoResolver coreProtoResolver,
Storage<TradableList<Tradable>> storage, Storage<TradableList<Tradable>> storage,
BtcWalletService btcWalletService) { BtcWalletService btcWalletService) {
List<Tradable> list = proto.getTradableList().stream() List<Tradable> list = proto.getTradableList().stream()
.map(tradable -> { .map(tradable -> {
switch (tradable.getMessageCase()) { switch (tradable.getMessageCase()) {

View file

@ -20,7 +20,7 @@ package bisq.core.trade.statistics;
import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -38,7 +38,7 @@ import lombok.extern.slf4j.Slf4j;
* definition and provide a hashMap for the domain access. * definition and provide a hashMap for the domain access.
*/ */
@Slf4j @Slf4j
public class TradeStatistics2Store implements PersistableEnvelope { public class TradeStatistics2Store implements ThreadedPersistableEnvelope {
@Getter @Getter
private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>();
@ -68,7 +68,7 @@ public class TradeStatistics2Store implements PersistableEnvelope {
return protobuf.TradeStatistics2Store.newBuilder().addAllItems(protoList); return protobuf.TradeStatistics2Store.newBuilder().addAllItems(protoList);
} }
public static PersistableEnvelope fromProto(protobuf.TradeStatistics2Store proto) { public static TradeStatistics2Store fromProto(protobuf.TradeStatistics2Store proto) {
List<TradeStatistics2> list = proto.getItemsList().stream() List<TradeStatistics2> list = proto.getItemsList().stream()
.map(TradeStatistics2::fromProto).collect(Collectors.toList()); .map(TradeStatistics2::fromProto).collect(Collectors.toList());
return new TradeStatistics2Store(list); return new TradeStatistics2Store(list);

View file

@ -25,7 +25,7 @@ import bisq.core.payment.PaymentAccount;
import bisq.core.proto.CoreProtoResolver; import bisq.core.proto.CoreProtoResolver;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -49,7 +49,7 @@ import static bisq.core.btc.wallet.Restrictions.getDefaultBuyerSecurityDepositAs
@Slf4j @Slf4j
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public final class PreferencesPayload implements PersistableEnvelope { public final class PreferencesPayload implements UserThreadMappedPersistableEnvelope {
private String userLanguage; private String userLanguage;
private Country userCountry; private Country userCountry;
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection") @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@ -132,7 +132,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
// Constructor // Constructor
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public PreferencesPayload() { PreferencesPayload() {
} }
@ -207,7 +207,7 @@ public final class PreferencesPayload implements PersistableEnvelope {
return protobuf.PersistableEnvelope.newBuilder().setPreferencesPayload(builder).build(); 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(); final protobuf.Country userCountry = proto.getUserCountry();
PaymentAccount paymentAccount = null; PaymentAccount paymentAccount = null;
if (proto.hasSelectedPaymentAccountForCreateOffer() && proto.getSelectedPaymentAccountForCreateOffer().hasPaymentMethod()) if (proto.hasSelectedPaymentAccountForCreateOffer() && proto.getSelectedPaymentAccountForCreateOffer().hasPaymentMethod())
@ -275,6 +275,5 @@ public final class PreferencesPayload implements PersistableEnvelope {
proto.getBuyerSecurityDepositAsPercentForCrypto(), proto.getBuyerSecurityDepositAsPercentForCrypto(),
proto.getBlockNotifyPort(), proto.getBlockNotifyPort(),
proto.getTacAcceptedV120()); proto.getTacAcceptedV120());
} }
} }

View file

@ -28,7 +28,7 @@ import bisq.core.support.dispute.mediation.mediator.Mediator;
import bisq.core.support.dispute.refund.refundagent.RefundAgent; import bisq.core.support.dispute.refund.refundagent.RefundAgent;
import bisq.common.proto.ProtoUtil; import bisq.common.proto.ProtoUtil;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
@ -46,7 +46,7 @@ import javax.annotation.Nullable;
@Slf4j @Slf4j
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class UserPayload implements PersistableEnvelope { public class UserPayload implements UserThreadMappedPersistableEnvelope {
@Nullable @Nullable
private String accountId; private String accountId;
@Nullable @Nullable

View file

@ -141,7 +141,7 @@ public final class Navigation implements PersistedDataHost {
private void queueUpForSave() { private void queueUpForSave() {
if (currentPath.tip() != null) { 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); storage.queueUpForSave(navigationPath, 1000);
} }

View file

@ -18,7 +18,6 @@
package bisq.network.p2p.peers.peerexchange; package bisq.network.p2p.peers.peerexchange;
import bisq.common.proto.persistable.PersistableEnvelope; import bisq.common.proto.persistable.PersistableEnvelope;
import bisq.common.proto.persistable.PersistableList;
import com.google.protobuf.Message; import com.google.protobuf.Message;
@ -27,23 +26,30 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode
public class PeerList extends PersistableList<Peer> { public class PeerList implements PersistableEnvelope {
@Getter
private final List<Peer> list;
public PeerList(List<Peer> list) { public PeerList(List<Peer> list) {
super(list); this.list = list;
}
public int size() {
return list.size();
} }
@Override @Override
public Message toProtoMessage() { public Message toProtoMessage() {
return protobuf.PersistableEnvelope.newBuilder() return protobuf.PersistableEnvelope.newBuilder()
.setPeerList(protobuf.PeerList.newBuilder() .setPeerList(protobuf.PeerList.newBuilder()
.addAllPeer(getList().stream().map(Peer::toProtoMessage).collect(Collectors.toList()))) .addAllPeer(list.stream().map(Peer::toProtoMessage).collect(Collectors.toList())))
.build(); .build();
} }
public static PersistableEnvelope fromProto(protobuf.PeerList proto) { public static PeerList fromProto(protobuf.PeerList proto) {
return new PeerList(new ArrayList<>(proto.getPeerList().stream() return new PeerList(new ArrayList<>(proto.getPeerList().stream()
.map(Peer::fromProto) .map(Peer::fromProto)
.collect(Collectors.toList()))); .collect(Collectors.toList())));

View file

@ -20,8 +20,8 @@ package bisq.network.p2p.storage.persistence;
import bisq.network.p2p.storage.P2PDataStorage; import bisq.network.p2p.storage.P2PDataStorage;
import bisq.network.p2p.storage.payload.PersistableNetworkPayload; import bisq.network.p2p.storage.payload.PersistableNetworkPayload;
import bisq.common.proto.persistable.PersistableEnvelope;
import bisq.common.proto.persistable.PersistenceProtoResolver; import bisq.common.proto.persistable.PersistenceProtoResolver;
import bisq.common.proto.persistable.ThreadedPersistableEnvelope;
import com.google.protobuf.Message; 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. // TODO at next hard fork we can rename the PB definition and class name.
@Deprecated @Deprecated
@Slf4j @Slf4j
public class PersistableNetworkPayloadList implements PersistableEnvelope { public class PersistableNetworkPayloadList implements ThreadedPersistableEnvelope {
@Getter @Getter
private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new ConcurrentHashMap<>();
public PersistableNetworkPayloadList() { PersistableNetworkPayloadList() {
} }
@ -54,7 +54,7 @@ public class PersistableNetworkPayloadList implements PersistableEnvelope {
// PROTO BUFFER // PROTO BUFFER
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public PersistableNetworkPayloadList(Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map) { private PersistableNetworkPayloadList(Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map) {
this.map.putAll(map); this.map.putAll(map);
} }
@ -69,8 +69,8 @@ public class PersistableNetworkPayloadList implements PersistableEnvelope {
.build(); .build();
} }
public static PersistableEnvelope fromProto(protobuf.PersistableNetworkPayloadList proto, public static PersistableNetworkPayloadList fromProto(protobuf.PersistableNetworkPayloadList proto,
PersistenceProtoResolver resolver) { PersistenceProtoResolver resolver) {
Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new HashMap<>(); Map<P2PDataStorage.ByteArray, PersistableNetworkPayload> map = new HashMap<>();
proto.getItemsList() proto.getItemsList()
.forEach(e -> { .forEach(e -> {

View file

@ -19,7 +19,7 @@ package bisq.network.p2p.storage.persistence;
import bisq.network.p2p.storage.P2PDataStorage; 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.HashMap;
import java.util.Map; 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. * in protobuffer the map construct can't be anything, so the straightforward mapping was not possible.
* Hence this Persistable class. * Hence this Persistable class.
*/ */
public class SequenceNumberMap implements PersistableEnvelope { public class SequenceNumberMap implements ThreadedPersistableEnvelope {
@Getter @Getter
@Setter @Setter
private Map<P2PDataStorage.ByteArray, P2PDataStorage.MapValue> map = new ConcurrentHashMap<>(); private Map<P2PDataStorage.ByteArray, P2PDataStorage.MapValue> map = new ConcurrentHashMap<>();
@ -70,7 +70,7 @@ public class SequenceNumberMap implements PersistableEnvelope {
public static SequenceNumberMap fromProto(protobuf.SequenceNumberMap proto) { public static SequenceNumberMap fromProto(protobuf.SequenceNumberMap proto) {
HashMap<P2PDataStorage.ByteArray, P2PDataStorage.MapValue> map = new HashMap<>(); HashMap<P2PDataStorage.ByteArray, P2PDataStorage.MapValue> map = new HashMap<>();
proto.getSequenceNumberEntriesList().stream() proto.getSequenceNumberEntriesList()
.forEach(e -> map.put(P2PDataStorage.ByteArray.fromProto(e.getBytes()), P2PDataStorage.MapValue.fromProto(e.getMapValue()))); .forEach(e -> map.put(P2PDataStorage.ByteArray.fromProto(e.getBytes()), P2PDataStorage.MapValue.fromProto(e.getMapValue())));
return new SequenceNumberMap(map); return new SequenceNumberMap(map);
} }