forked from Qortal/qortal
More reliable start-up by removing some race conditions in Controller and Network
This commit is contained in:
parent
e9c94eb83b
commit
d01504a541
@ -16,7 +16,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
@ -116,14 +115,14 @@ public class Controller extends Thread {
|
||||
private static volatile boolean isStopping = false;
|
||||
private static BlockMinter blockMinter = null;
|
||||
private static volatile boolean requestSync = false;
|
||||
private static volatile boolean requestSysTrayUpdate = false;
|
||||
private static volatile boolean requestSysTrayUpdate = true;
|
||||
private static Controller instance;
|
||||
|
||||
private final String buildVersion;
|
||||
private final long buildTimestamp; // seconds
|
||||
private final String[] savedArgs;
|
||||
|
||||
private AtomicReference<BlockData> chainTip = new AtomicReference<>();
|
||||
private volatile BlockData chainTip = null;
|
||||
|
||||
private long repositoryBackupTimestamp = startTime + REPOSITORY_BACKUP_PERIOD; // ms
|
||||
private long ntpCheckTimestamp = startTime; // ms
|
||||
@ -188,7 +187,7 @@ public class Controller extends Thread {
|
||||
this.savedArgs = args;
|
||||
}
|
||||
|
||||
private static Controller newInstance(String[] args) {
|
||||
private static synchronized Controller newInstance(String[] args) {
|
||||
instance = new Controller(args);
|
||||
return instance;
|
||||
}
|
||||
@ -216,7 +215,7 @@ public class Controller extends Thread {
|
||||
|
||||
/** Returns current blockchain height, or 0 if it's not available. */
|
||||
public int getChainHeight() {
|
||||
BlockData blockData = this.chainTip.get();
|
||||
BlockData blockData = this.chainTip;
|
||||
if (blockData == null)
|
||||
return 0;
|
||||
|
||||
@ -225,12 +224,12 @@ public class Controller extends Thread {
|
||||
|
||||
/** Returns highest block, or null if it's not available. */
|
||||
public BlockData getChainTip() {
|
||||
return this.chainTip.get();
|
||||
return this.chainTip;
|
||||
}
|
||||
|
||||
/** Cache new blockchain tip, and also wipe cache of online accounts. */
|
||||
public void setChainTip(BlockData blockData) {
|
||||
this.chainTip.set(blockData);
|
||||
this.chainTip = blockData;
|
||||
}
|
||||
|
||||
public ReentrantLock getBlockchainLock() {
|
||||
@ -263,6 +262,8 @@ public class Controller extends Thread {
|
||||
return; // Not System.exit() so that GUI can display error
|
||||
}
|
||||
|
||||
Controller.newInstance(args);
|
||||
|
||||
LOGGER.info("Starting NTP");
|
||||
NTP.start();
|
||||
|
||||
@ -301,13 +302,13 @@ public class Controller extends Thread {
|
||||
}
|
||||
|
||||
LOGGER.info("Starting controller");
|
||||
Controller.newInstance(args).start();
|
||||
Controller.getInstance().start();
|
||||
|
||||
LOGGER.info(String.format("Starting networking on port %d", Settings.getInstance().getListenPort()));
|
||||
try {
|
||||
Network network = Network.getInstance();
|
||||
network.start();
|
||||
} catch (Exception e) {
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Unable to start networking", e);
|
||||
Gui.getInstance().fatalError("Networking failure", e);
|
||||
return; // Not System.exit() so that GUI can display error
|
||||
@ -372,15 +373,37 @@ public class Controller extends Thread {
|
||||
|
||||
try {
|
||||
while (!isStopping) {
|
||||
// Maybe update SysTray
|
||||
if (requestSysTrayUpdate) {
|
||||
requestSysTrayUpdate = false;
|
||||
updateSysTray();
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
|
||||
// Check NTP status
|
||||
if (now >= ntpCheckTimestamp) {
|
||||
Long ntpTime = NTP.getTime();
|
||||
|
||||
if (ntpTime != null) {
|
||||
LOGGER.info(String.format("Adjusting system time by NTP offset: %dms", ntpTime - now));
|
||||
ntpCheckTimestamp = now + NTP_POST_SYNC_CHECK_PERIOD;
|
||||
requestSysTrayUpdate = true;
|
||||
} else {
|
||||
LOGGER.info(String.format("No NTP offset yet"));
|
||||
ntpCheckTimestamp = now + NTP_PRE_SYNC_CHECK_PERIOD;
|
||||
// We can't do much without a valid NTP time
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (requestSync) {
|
||||
requestSync = false;
|
||||
potentiallySynchronize();
|
||||
}
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
|
||||
// Clean up arbitrary data request cache
|
||||
final long requestMinimumTimestamp = now - ARBITRARY_REQUEST_TIMEOUT;
|
||||
arbitraryDataRequests.entrySet().removeIf(entry -> entry.getValue().getC() < requestMinimumTimestamp);
|
||||
@ -391,21 +414,6 @@ public class Controller extends Thread {
|
||||
RepositoryManager.backup(true);
|
||||
}
|
||||
|
||||
// Check NTP status
|
||||
if (now >= ntpCheckTimestamp) {
|
||||
Long ntpTime = NTP.getTime();
|
||||
|
||||
if (ntpTime != null) {
|
||||
LOGGER.info(String.format("Adjusting system time by NTP offset: %dms", ntpTime - now));
|
||||
ntpCheckTimestamp = now + NTP_POST_SYNC_CHECK_PERIOD;
|
||||
} else {
|
||||
LOGGER.info(String.format("No NTP offset yet"));
|
||||
ntpCheckTimestamp = now + NTP_PRE_SYNC_CHECK_PERIOD;
|
||||
}
|
||||
|
||||
requestSysTrayUpdate = true;
|
||||
}
|
||||
|
||||
// Prune stuck/slow/old peers
|
||||
try {
|
||||
Network.getInstance().prunePeers();
|
||||
@ -419,12 +427,6 @@ public class Controller extends Thread {
|
||||
deleteExpiredTransactions();
|
||||
}
|
||||
|
||||
// Maybe update SysTray
|
||||
if (requestSysTrayUpdate) {
|
||||
requestSysTrayUpdate = false;
|
||||
updateSysTray();
|
||||
}
|
||||
|
||||
// Perform tasks to do with managing online accounts list
|
||||
if (now >= onlineAccountsTasksTimestamp) {
|
||||
onlineAccountsTasksTimestamp = now + ONLINE_ACCOUNTS_TASKS_INTERVAL;
|
||||
|
@ -118,30 +118,6 @@ public class Network {
|
||||
// Constructors
|
||||
|
||||
private Network() {
|
||||
// Grab P2P port from settings
|
||||
int listenPort = Settings.getInstance().getListenPort();
|
||||
|
||||
// Grab P2P bind address from settings
|
||||
try {
|
||||
InetAddress bindAddr = InetAddress.getByName(Settings.getInstance().getBindAddress());
|
||||
InetSocketAddress endpoint = new InetSocketAddress(bindAddr, listenPort);
|
||||
|
||||
channelSelector = Selector.open();
|
||||
|
||||
// Set up listen socket
|
||||
serverChannel = ServerSocketChannel.open();
|
||||
serverChannel.configureBlocking(false);
|
||||
serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
||||
serverChannel.bind(endpoint, LISTEN_BACKLOG);
|
||||
serverChannel.register(channelSelector, SelectionKey.OP_ACCEPT);
|
||||
} catch (UnknownHostException e) {
|
||||
LOGGER.error(String.format("Can't bind listen socket to address %s", Settings.getInstance().getBindAddress()));
|
||||
throw new RuntimeException("Can't bind listen socket to address", e);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error(String.format("Can't create listen socket: %s", e.getMessage()));
|
||||
throw new RuntimeException("Can't create listen socket", e);
|
||||
}
|
||||
|
||||
connectedPeers = new ArrayList<>();
|
||||
selfPeers = new ArrayList<>();
|
||||
|
||||
@ -169,14 +145,38 @@ public class Network {
|
||||
networkEPC = new NetworkProcessor(networkExecutor);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
public void start() throws IOException {
|
||||
// Grab P2P port from settings
|
||||
int listenPort = Settings.getInstance().getListenPort();
|
||||
|
||||
// Grab P2P bind address from settings
|
||||
try {
|
||||
InetAddress bindAddr = InetAddress.getByName(Settings.getInstance().getBindAddress());
|
||||
InetSocketAddress endpoint = new InetSocketAddress(bindAddr, listenPort);
|
||||
|
||||
channelSelector = Selector.open();
|
||||
|
||||
// Set up listen socket
|
||||
serverChannel = ServerSocketChannel.open();
|
||||
serverChannel.configureBlocking(false);
|
||||
serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
|
||||
serverChannel.bind(endpoint, LISTEN_BACKLOG);
|
||||
serverChannel.register(channelSelector, SelectionKey.OP_ACCEPT);
|
||||
} catch (UnknownHostException e) {
|
||||
LOGGER.error(String.format("Can't bind listen socket to address %s", Settings.getInstance().getBindAddress()));
|
||||
throw new IOException("Can't bind listen socket to address", e);
|
||||
} catch (IOException e) {
|
||||
LOGGER.error(String.format("Can't create listen socket: %s", e.getMessage()));
|
||||
throw new IOException("Can't create listen socket", e);
|
||||
}
|
||||
|
||||
// Start up first networking thread
|
||||
networkEPC.start();
|
||||
}
|
||||
|
||||
// Getters / setters
|
||||
|
||||
public static Network getInstance() {
|
||||
public static synchronized Network getInstance() {
|
||||
if (instance == null)
|
||||
instance = new Network();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user