mirror of
https://github.com/haveno-dex/haveno.git
synced 2024-12-24 23:09:36 -05:00
synchronize P2PDataStorage to avoid race conditions
This commit is contained in:
parent
93a93d757c
commit
870630b381
@ -232,8 +232,10 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
|
|
||||||
appendOnlyDataStoreService.readFromResources(postFix, () -> appendOnlyDataStoreServiceReady.set(true));
|
appendOnlyDataStoreService.readFromResources(postFix, () -> appendOnlyDataStoreServiceReady.set(true));
|
||||||
protectedDataStoreService.readFromResources(postFix, () -> {
|
protectedDataStoreService.readFromResources(postFix, () -> {
|
||||||
|
synchronized (map) {
|
||||||
map.putAll(protectedDataStoreService.getMap());
|
map.putAll(protectedDataStoreService.getMap());
|
||||||
protectedDataStoreServiceReady.set(true);
|
protectedDataStoreServiceReady.set(true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
resourceDataStoreService.readFromResources(postFix, () -> resourceDataStoreServiceReady.set(true));
|
resourceDataStoreService.readFromResources(postFix, () -> resourceDataStoreServiceReady.set(true));
|
||||||
}
|
}
|
||||||
@ -241,21 +243,25 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
// Uses synchronous execution on the userThread. Only used by tests. The async methods should be used by app code.
|
// Uses synchronous execution on the userThread. Only used by tests. The async methods should be used by app code.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void readFromResourcesSync(String postFix) {
|
public void readFromResourcesSync(String postFix) {
|
||||||
|
synchronized (map) {
|
||||||
appendOnlyDataStoreService.readFromResourcesSync(postFix);
|
appendOnlyDataStoreService.readFromResourcesSync(postFix);
|
||||||
protectedDataStoreService.readFromResourcesSync(postFix);
|
protectedDataStoreService.readFromResourcesSync(postFix);
|
||||||
resourceDataStoreService.readFromResourcesSync(postFix);
|
resourceDataStoreService.readFromResourcesSync(postFix);
|
||||||
|
|
||||||
map.putAll(protectedDataStoreService.getMap());
|
map.putAll(protectedDataStoreService.getMap());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We get added mailbox message data from MailboxMessageService. We want to add those early so we can get it added
|
// We get added mailbox message data from MailboxMessageService. We want to add those early so we can get it added
|
||||||
// to our excluded keys to reduce initial data response data size.
|
// to our excluded keys to reduce initial data response data size.
|
||||||
public void addProtectedMailboxStorageEntryToMap(ProtectedStorageEntry protectedStorageEntry) {
|
public void addProtectedMailboxStorageEntryToMap(ProtectedStorageEntry protectedStorageEntry) {
|
||||||
|
synchronized (map) {
|
||||||
ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload();
|
ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload();
|
||||||
ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload);
|
ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload);
|
||||||
map.put(hashOfPayload, protectedStorageEntry);
|
map.put(hashOfPayload, protectedStorageEntry);
|
||||||
//log.trace("## addProtectedMailboxStorageEntryToMap hashOfPayload={}, map={}", hashOfPayload, printMap());
|
//log.trace("## addProtectedMailboxStorageEntryToMap hashOfPayload={}, map={}", hashOfPayload, printMap());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// RequestData API
|
// RequestData API
|
||||||
@ -627,6 +633,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void removeExpiredEntries() {
|
void removeExpiredEntries() {
|
||||||
|
synchronized (map) {
|
||||||
// The moment when an object becomes expired will not be synchronous in the network and we could
|
// The moment when an object becomes expired will not be synchronous in the network and we could
|
||||||
// get add network_messages after the object has expired. To avoid repeated additions of already expired
|
// get add network_messages after the object has expired. To avoid repeated additions of already expired
|
||||||
// object when we get it sent from new peers, we don’t remove the sequence number from the map.
|
// object when we get it sent from new peers, we don’t remove the sequence number from the map.
|
||||||
@ -651,6 +658,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
requestPersistence();
|
requestPersistence();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void onBootstrapped() {
|
public void onBootstrapped() {
|
||||||
removeExpiredEntriesTimer = UserThread.runPeriodically(this::removeExpiredEntries, CHECK_TTL_INTERVAL_SEC);
|
removeExpiredEntriesTimer = UserThread.runPeriodically(this::removeExpiredEntries, CHECK_TTL_INTERVAL_SEC);
|
||||||
@ -699,6 +707,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
NodeAddress peersNodeAddress = connection.getPeersNodeAddressOptional().get();
|
NodeAddress peersNodeAddress = connection.getPeersNodeAddressOptional().get();
|
||||||
|
|
||||||
// Backdate all the eligible payloads based on the node that disconnected
|
// Backdate all the eligible payloads based on the node that disconnected
|
||||||
|
synchronized (map) {
|
||||||
map.values().stream()
|
map.values().stream()
|
||||||
.filter(protectedStorageEntry -> protectedStorageEntry.getProtectedStoragePayload() instanceof RequiresOwnerIsOnlinePayload)
|
.filter(protectedStorageEntry -> protectedStorageEntry.getProtectedStoragePayload() instanceof RequiresOwnerIsOnlinePayload)
|
||||||
.filter(protectedStorageEntry -> ((RequiresOwnerIsOnlinePayload) protectedStorageEntry.getProtectedStoragePayload()).getOwnerNodeAddress().equals(peersNodeAddress))
|
.filter(protectedStorageEntry -> ((RequiresOwnerIsOnlinePayload) protectedStorageEntry.getProtectedStoragePayload()).getOwnerNodeAddress().equals(peersNodeAddress))
|
||||||
@ -716,6 +725,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
protectedStorageEntry.backDate();
|
protectedStorageEntry.backDate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Client API
|
// Client API
|
||||||
@ -818,6 +828,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
@Nullable NodeAddress sender,
|
@Nullable NodeAddress sender,
|
||||||
@Nullable BroadcastHandler.Listener listener,
|
@Nullable BroadcastHandler.Listener listener,
|
||||||
boolean allowBroadcast) {
|
boolean allowBroadcast) {
|
||||||
|
synchronized (map) {
|
||||||
ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload();
|
ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload();
|
||||||
ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload);
|
ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload);
|
||||||
|
|
||||||
@ -894,6 +905,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We do not do all checks as it is used for republishing existing mailbox messages from seed nodes which
|
* We do not do all checks as it is used for republishing existing mailbox messages from seed nodes which
|
||||||
@ -935,7 +947,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
*/
|
*/
|
||||||
public boolean refreshTTL(RefreshOfferMessage refreshTTLMessage,
|
public boolean refreshTTL(RefreshOfferMessage refreshTTLMessage,
|
||||||
@Nullable NodeAddress sender) {
|
@Nullable NodeAddress sender) {
|
||||||
|
synchronized (map) {
|
||||||
try {
|
try {
|
||||||
ByteArray hashOfPayload = new ByteArray(refreshTTLMessage.getHashOfPayload());
|
ByteArray hashOfPayload = new ByteArray(refreshTTLMessage.getHashOfPayload());
|
||||||
ProtectedStorageEntry storedData = map.get(hashOfPayload);
|
ProtectedStorageEntry storedData = map.get(hashOfPayload);
|
||||||
@ -980,6 +992,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a ProtectedStorageEntry from the local P2P data storage. If it is successful, it will broadcast that
|
* Removes a ProtectedStorageEntry from the local P2P data storage. If it is successful, it will broadcast that
|
||||||
@ -991,6 +1004,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
*/
|
*/
|
||||||
public boolean remove(ProtectedStorageEntry protectedStorageEntry,
|
public boolean remove(ProtectedStorageEntry protectedStorageEntry,
|
||||||
@Nullable NodeAddress sender) {
|
@Nullable NodeAddress sender) {
|
||||||
|
synchronized (map) {
|
||||||
ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload();
|
ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload();
|
||||||
ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload);
|
ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload);
|
||||||
|
|
||||||
@ -1034,6 +1048,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ProtectedStorageEntry getProtectedStorageEntry(ProtectedStoragePayload protectedStoragePayload,
|
public ProtectedStorageEntry getProtectedStorageEntry(ProtectedStoragePayload protectedStoragePayload,
|
||||||
KeyPair ownerStoragePubKey)
|
KeyPair ownerStoragePubKey)
|
||||||
@ -1107,6 +1122,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void removeFromMapAndDataStore(Collection<Map.Entry<ByteArray, ProtectedStorageEntry>> entriesToRemove) {
|
private void removeFromMapAndDataStore(Collection<Map.Entry<ByteArray, ProtectedStorageEntry>> entriesToRemove) {
|
||||||
|
synchronized (map) {
|
||||||
if (entriesToRemove.isEmpty())
|
if (entriesToRemove.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1132,6 +1148,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers
|
|||||||
|
|
||||||
hashMapChangedListeners.forEach(e -> e.onRemoved(removedProtectedStorageEntries));
|
hashMapChangedListeners.forEach(e -> e.onRemoved(removedProtectedStorageEntries));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasSequenceNrIncreased(int newSequenceNumber, ByteArray hashOfData) {
|
private boolean hasSequenceNrIncreased(int newSequenceNumber, ByteArray hashOfData) {
|
||||||
if (sequenceNumberMap.containsKey(hashOfData)) {
|
if (sequenceNumberMap.containsKey(hashOfData)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user