forked from Qortal/qortal
Add lock around some Peer.peerData actions to help sync
This commit is contained in:
parent
6a969f9473
commit
2f3123a315
@ -413,15 +413,16 @@ public class Controller extends Thread {
|
|||||||
LOGGER.trace(String.format("Processing %s message from %s", message.getType().name(), peer));
|
LOGGER.trace(String.format("Processing %s message from %s", message.getType().name(), peer));
|
||||||
|
|
||||||
switch (message.getType()) {
|
switch (message.getType()) {
|
||||||
case HEIGHT:
|
case HEIGHT: {
|
||||||
HeightMessage heightMessage = (HeightMessage) message;
|
HeightMessage heightMessage = (HeightMessage) message;
|
||||||
|
|
||||||
// Update our record of peer's height
|
// Update our record of peer's height
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
|
||||||
PeerData peerData = peer.getPeerData();
|
PeerData peerData = peer.getPeerData();
|
||||||
|
|
||||||
peer.getPeerData().setLastHeight(heightMessage.getHeight());
|
peer.getPeerData().setLastHeight(heightMessage.getHeight());
|
||||||
|
|
||||||
|
// Only save to repository if outbound peer
|
||||||
|
if (peer.isOutbound())
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
repository.getNetworkRepository().save(peerData);
|
repository.getNetworkRepository().save(peerData);
|
||||||
repository.saveChanges();
|
repository.saveChanges();
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
@ -429,19 +430,29 @@ public class Controller extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case HEIGHT_V2:
|
case HEIGHT_V2: {
|
||||||
HeightV2Message heightV2Message = (HeightV2Message) message;
|
HeightV2Message heightV2Message = (HeightV2Message) message;
|
||||||
|
|
||||||
// Update our record for peer's blockchain info
|
// Update our record for peer's blockchain info
|
||||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
|
||||||
PeerData peerData = peer.getPeerData();
|
PeerData peerData = peer.getPeerData();
|
||||||
|
|
||||||
|
// We want to update atomically so use lock
|
||||||
|
ReentrantLock peerDataLock = peer.getPeerDataLock();
|
||||||
|
peerDataLock.lock();
|
||||||
|
try {
|
||||||
peerData.setLastHeight(heightV2Message.getHeight());
|
peerData.setLastHeight(heightV2Message.getHeight());
|
||||||
peerData.setLastBlockSignature(heightV2Message.getSignature());
|
peerData.setLastBlockSignature(heightV2Message.getSignature());
|
||||||
peerData.setLastBlockTimestamp(heightV2Message.getTimestamp());
|
peerData.setLastBlockTimestamp(heightV2Message.getTimestamp());
|
||||||
peerData.setLastBlockGenerator(heightV2Message.getGenerator());
|
peerData.setLastBlockGenerator(heightV2Message.getGenerator());
|
||||||
|
} finally {
|
||||||
|
peerDataLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only save to repository if outbound peer
|
||||||
|
if (peer.isOutbound())
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
repository.getNetworkRepository().save(peerData);
|
repository.getNetworkRepository().save(peerData);
|
||||||
repository.saveChanges();
|
repository.saveChanges();
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
@ -449,6 +460,7 @@ public class Controller extends Thread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GET_SIGNATURES: {
|
case GET_SIGNATURES: {
|
||||||
GetSignaturesMessage getSignaturesMessage = (GetSignaturesMessage) message;
|
GetSignaturesMessage getSignaturesMessage = (GetSignaturesMessage) message;
|
||||||
@ -550,7 +562,7 @@ public class Controller extends Thread {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TRANSACTION:
|
case TRANSACTION: {
|
||||||
TransactionMessage transactionMessage = (TransactionMessage) message;
|
TransactionMessage transactionMessage = (TransactionMessage) message;
|
||||||
TransactionData transactionData = transactionMessage.getTransactionData();
|
TransactionData transactionData = transactionMessage.getTransactionData();
|
||||||
|
|
||||||
@ -589,6 +601,7 @@ public class Controller extends Thread {
|
|||||||
LOGGER.error(String.format("Repository issue while processing transaction %s from peer %s", Base58.encode(transactionData.getSignature()), peer), e);
|
LOGGER.error(String.format("Repository issue while processing transaction %s from peer %s", Base58.encode(transactionData.getSignature()), peer), e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case GET_BLOCK_SUMMARIES:
|
case GET_BLOCK_SUMMARIES:
|
||||||
GetBlockSummariesMessage getBlockSummariesMessage = (GetBlockSummariesMessage) message;
|
GetBlockSummariesMessage getBlockSummariesMessage = (GetBlockSummariesMessage) message;
|
||||||
@ -663,9 +676,16 @@ public class Controller extends Thread {
|
|||||||
// Remove peers with unknown height, lower height or same height and same block signature (unless we don't have their block signature)
|
// Remove peers with unknown height, lower height or same height and same block signature (unless we don't have their block signature)
|
||||||
peers.removeIf(hasShorterBlockchain());
|
peers.removeIf(hasShorterBlockchain());
|
||||||
|
|
||||||
|
// Remove peers that within 1 block of our height (actually ourHeight + 1)
|
||||||
|
final int maxHeight = getChainHeight() + 1;
|
||||||
|
peers.removeIf(peer -> peer.getPeerData().getLastHeight() <= maxHeight );
|
||||||
|
|
||||||
// Remove peers that have "misbehaved" recently
|
// Remove peers that have "misbehaved" recently
|
||||||
peers.removeIf(hasPeerMisbehaved);
|
peers.removeIf(hasPeerMisbehaved);
|
||||||
|
|
||||||
|
for (Peer peer : peers)
|
||||||
|
LOGGER.debug(String.format("Not up to date due to peer %s at height %d with block sig %s", peer, peer.getPeerData().getLastHeight(), Base58.encode(peer.getPeerData().getLastBlockSignature())));
|
||||||
|
|
||||||
// If we have any peers left, then they would be candidates for synchronization therefore we're not up to date.
|
// If we have any peers left, then they would be candidates for synchronization therefore we're not up to date.
|
||||||
return peers.isEmpty();
|
return peers.isEmpty();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import java.util.concurrent.BlockingQueue;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -47,6 +48,7 @@ public class Peer implements Runnable {
|
|||||||
private final boolean isOutbound;
|
private final boolean isOutbound;
|
||||||
private Socket socket = null;
|
private Socket socket = null;
|
||||||
private PeerData peerData = null;
|
private PeerData peerData = null;
|
||||||
|
private final ReentrantLock peerDataLock = new ReentrantLock();
|
||||||
private Long connectionTimestamp = null;
|
private Long connectionTimestamp = null;
|
||||||
private OutputStream out;
|
private OutputStream out;
|
||||||
private Handshake handshakeStatus = Handshake.STARTED;
|
private Handshake handshakeStatus = Handshake.STARTED;
|
||||||
@ -82,7 +84,13 @@ public class Peer implements Runnable {
|
|||||||
// Getters / setters
|
// Getters / setters
|
||||||
|
|
||||||
public PeerData getPeerData() {
|
public PeerData getPeerData() {
|
||||||
|
this.peerDataLock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
return this.peerData;
|
return this.peerData;
|
||||||
|
} finally {
|
||||||
|
this.peerDataLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOutbound() {
|
public boolean isOutbound() {
|
||||||
@ -160,6 +168,11 @@ public class Peer implements Runnable {
|
|||||||
this.verificationCodeExpected = expected;
|
this.verificationCodeExpected = expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the lock used for synchronizing access to peer's PeerData. */
|
||||||
|
public ReentrantLock getPeerDataLock() {
|
||||||
|
return this.peerDataLock;
|
||||||
|
}
|
||||||
|
|
||||||
// Easier, and nicer output, than peer.getRemoteSocketAddress()
|
// Easier, and nicer output, than peer.getRemoteSocketAddress()
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user