From 90b7f96fb22fdef5345fc6232555e41908f5d03e Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Wed, 4 Dec 2024 11:20:09 +0800 Subject: [PATCH] feat(exit): add exit manager --- build.gradle | 2 +- .../leveldb/LevelDbDataSourceImpl.java | 11 ++- .../rocksdb/RocksDbDataSourceImpl.java | 11 ++- .../tron/core/db2/core/SnapshotManager.java | 32 +++----- .../tron/core/service/RewardViCalService.java | 6 +- .../org/tron/common/exit/ExitManager.java | 77 +++++++++++++++++++ .../java/org/tron/common/exit/ExitReason.java | 22 ++++++ .../tron/common/exit/TronExitException.java | 21 +++++ .../tron/core/exception/ConfigException.java | 16 ++++ .../core/exception/EventTriggerException.java | 16 ++++ .../core/exception/GenesisBlockException.java | 16 ++++ framework/build.gradle | 5 -- .../common/application/ApplicationImpl.java | 6 +- .../java/org/tron/core/config/args/Args.java | 9 ++- .../main/java/org/tron/core/db/Manager.java | 31 ++++---- .../org/tron/core/net/TronNetDelegate.java | 52 ++----------- .../tron/core/services/SolidityService.java | 18 +++-- .../leveldb/LevelDbDataSourceImplTest.java | 7 +- .../leveldb/RocksDbDataSourceImplTest.java | 8 +- .../java/org/tron/core/db/ManagerTest.java | 8 +- .../tron/core/services/ComputeRewardTest.java | 7 +- .../services/stop/ConditionallyStopTest.java | 6 -- 22 files changed, 251 insertions(+), 136 deletions(-) create mode 100644 common/src/main/java/org/tron/common/exit/ExitManager.java create mode 100644 common/src/main/java/org/tron/common/exit/ExitReason.java create mode 100644 common/src/main/java/org/tron/common/exit/TronExitException.java create mode 100644 common/src/main/java/org/tron/core/exception/ConfigException.java create mode 100644 common/src/main/java/org/tron/core/exception/EventTriggerException.java create mode 100644 common/src/main/java/org/tron/core/exception/GenesisBlockException.java diff --git a/build.gradle b/build.gradle index 89bc5ff17bc..6b799788df6 100644 --- a/build.gradle +++ b/build.gradle @@ -100,7 +100,7 @@ subprojects { } tasks.withType(Test).configureEach { // https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test:environment - /* environment 'CI', 'true'*/ + environment 'CI', 'true' } } diff --git a/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java b/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java index c7ab8288fe7..1693578d341 100644 --- a/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java +++ b/chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java @@ -47,6 +47,8 @@ import org.iq80.leveldb.WriteBatch; import org.iq80.leveldb.WriteOptions; import org.slf4j.LoggerFactory; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.parameter.CommonParameter; import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.metric.DbStat; @@ -176,13 +178,14 @@ private void openDatabase(Options dbOptions) throws IOException { dbOptions.cacheSize() / 1024 / 1024, dbOptions.maxOpenFiles()); } } catch (IOException e) { + String info; if (e.getMessage().contains("Corruption:")) { - logger.error("Database {} corrupted, please delete database directory({}) and restart.", - dataBaseName, parentPath, e); + info = String.format("Database %s corrupted, please delete database directory(%s) " + + "and restart.", dataBaseName, parentPath); } else { - logger.error("Open Database {} failed", dataBaseName, e); + info = String.format("Open Database %s failed", dataBaseName); } - System.exit(1); + ExitManager.getInstance().exit(ExitReason.DATABASE_ERROR, info, e); } } diff --git a/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java b/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java index 5267d72e1f6..92edfb6a31f 100644 --- a/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java +++ b/chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java @@ -33,6 +33,8 @@ import org.rocksdb.WriteBatch; import org.rocksdb.WriteOptions; import org.slf4j.LoggerFactory; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.setting.RocksDbSettings; import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.metric.DbStat; @@ -239,13 +241,14 @@ protected void log(InfoLogLevel infoLogLevel, String logMsg) { try { database = RocksDB.open(options, dbPath.toString()); } catch (RocksDBException e) { + String info; if (Objects.equals(e.getStatus().getCode(), Status.Code.Corruption)) { - logger.error("Database {} corrupted, please delete database directory({}) " - + "and restart.", dataBaseName, parentPath, e); + info = String.format("Database %s corrupted, please delete database directory(%s) " + + "and restart.", dataBaseName, parentPath); } else { - logger.error("Open Database {} failed", dataBaseName, e); + info = String.format("Open Database %s failed", dataBaseName); } - System.exit(1); + ExitManager.getInstance().exit(ExitReason.DATABASE_ERROR, info, e); } alive = true; diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java index f0f169ae340..be0e0becf70 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java @@ -29,6 +29,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.tron.common.error.TronDBException; import org.tron.common.es.ExecutorServiceManager; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.parameter.CommonParameter; import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.utils.FileUtil; @@ -41,6 +43,7 @@ import org.tron.core.db2.common.Key; import org.tron.core.db2.common.Value; import org.tron.core.db2.common.WrappedByteArray; +import org.tron.core.exception.ConfigException; import org.tron.core.exception.RevokingStoreIllegalStateException; import org.tron.core.store.CheckPointV2Store; import org.tron.core.store.CheckTmpStore; @@ -68,7 +71,6 @@ public class SnapshotManager implements RevokingDatabase { private volatile int flushCount = 0; - private Thread exitThread; private volatile boolean hitDown; private Map flushServices = new HashMap<>(); @@ -105,15 +107,6 @@ public void init() { } }, 10000, 3600, TimeUnit.MILLISECONDS); } - exitThread = new Thread(() -> { - LockSupport.park(); - // to Guarantee Some other thread invokes unpark with the current thread as the target - if (hitDown) { - System.exit(1); - } - }); - exitThread.setName("exit-thread"); - exitThread.start(); } public static String simpleDecode(byte[] bytes) { @@ -281,13 +274,6 @@ public void shutdown() { ExecutorServiceManager.shutdownAndAwaitTermination(pruneCheckpointThread, pruneName); flushServices.forEach((key, value) -> ExecutorServiceManager.shutdownAndAwaitTermination(value, "flush-service-" + key)); - try { - exitThread.interrupt(); - // help GC - exitThread = null; - } catch (Exception e) { - logger.warn("exitThread interrupt error", e); - } } public void updateSolidity(int hops) { @@ -365,9 +351,9 @@ public void flush() { System.currentTimeMillis() - checkPointEnd ); } catch (TronDBException e) { - logger.error(" Find fatal error, program will be exited soon.", e); hitDown = true; - LockSupport.unpark(exitThread); + ExitManager.getInstance().exit(ExitReason.DATABASE_ERROR, + "Find fatal error, program will be exited soon.", e); } } } @@ -490,10 +476,10 @@ public void check() { if (!isV2Open()) { List cpList = getCheckpointList(); if (cpList != null && cpList.size() != 0) { - logger.error("checkpoint check failed, the checkpoint version of database not match your " + - "config file, please set storage.checkpoint.version = 2 in your config file " + - "and restart the node."); - System.exit(-1); + String info = "checkpoint check failed, the checkpoint version of database not match your " + + "config file, please set storage.checkpoint.version = 2 in your config file " + + "and restart the node."; + ExitManager.getInstance().exit(ExitReason.CONFIG_ERROR, new ConfigException(info)); } checkV1(); } else { diff --git a/chainbase/src/main/java/org/tron/core/service/RewardViCalService.java b/chainbase/src/main/java/org/tron/core/service/RewardViCalService.java index e27990f0403..a7938387de5 100644 --- a/chainbase/src/main/java/org/tron/core/service/RewardViCalService.java +++ b/chainbase/src/main/java/org/tron/core/service/RewardViCalService.java @@ -23,6 +23,8 @@ import org.springframework.stereotype.Component; import org.tron.common.error.TronDBException; import org.tron.common.es.ExecutorServiceManager; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.MerkleRoot; @@ -120,8 +122,8 @@ private void maybeRun() { } } } catch (Exception e) { - logger.error(" Find fatal error, program will be exited soon.", e); - System.exit(1); + ExitManager.getInstance().exit(ExitReason.DATABASE_ERROR, + "Find fatal error, program will be exited soon", e); } } diff --git a/common/src/main/java/org/tron/common/exit/ExitManager.java b/common/src/main/java/org/tron/common/exit/ExitManager.java new file mode 100644 index 00000000000..c4e9245a6cb --- /dev/null +++ b/common/src/main/java/org/tron/common/exit/ExitManager.java @@ -0,0 +1,77 @@ +package org.tron.common.exit; + +import java.util.Arrays; +import java.util.concurrent.ThreadFactory; + +import com.google.common.base.Strings; +import lombok.extern.slf4j.Slf4j; + +@Slf4j(topic = "Exit") +public class ExitManager { + + private static final ExitManager INSTANCE = new ExitManager(); + private static final String[] CI_ENVIRONMENT_VARIABLES = { + "CI", + "JENKINS_URL", + "TRAVIS", + "CIRCLECI", + "GITHUB_ACTIONS", + "GITLAB_CI" + }; + + private final ThreadFactory exitThreadFactory = r -> { + Thread thread = new Thread(r, "System-Exit-Thread"); + thread.setDaemon(true); + return thread; + }; + + private ExitManager() { + } + + public static ExitManager getInstance() { + return INSTANCE; + } + + public void exit(ExitReason reason) { + exit(reason, reason.getDescription()); + } + + public void exit(ExitReason reason, String message) { + exit(reason, message, null); + } + + public void exit(ExitReason reason, Throwable cause) { + exit(reason, cause.getMessage(), cause); + } + + public void exit(ExitReason reason, String message, Throwable cause) { + TronExitException exitException = new TronExitException(reason, message, cause); + if (isRunningInCI()) { + if (exitException.getExitReason() != ExitReason.NORMAL_SHUTDOWN) { + throw exitException; + } + } else { + logAndExit(exitException); + } + } + + private boolean isRunningInCI() { + return Arrays.stream(CI_ENVIRONMENT_VARIABLES).anyMatch(System.getenv()::containsKey); + } + + private void logAndExit(TronExitException exception) { + ExitReason reason = exception.getExitReason(); + String message = exception.getMessage(); + if (reason == ExitReason.NORMAL_SHUTDOWN) { + if (!Strings.isNullOrEmpty(message)) { + logger.info("Exiting with code: {}, {}, {}.", + reason.getCode(), reason.getDescription(), message); + } + } else { + logger.error("Exiting with code: {}, {}, {}.", reason.getCode(), reason.getDescription(), + message, exception); + } + Thread exitThread = exitThreadFactory.newThread(() -> System.exit(reason.getCode())); + exitThread.start(); + } +} \ No newline at end of file diff --git a/common/src/main/java/org/tron/common/exit/ExitReason.java b/common/src/main/java/org/tron/common/exit/ExitReason.java new file mode 100644 index 00000000000..a3991339878 --- /dev/null +++ b/common/src/main/java/org/tron/common/exit/ExitReason.java @@ -0,0 +1,22 @@ +package org.tron.common.exit; + +import lombok.Getter; + +@Getter +public enum ExitReason { + NORMAL_SHUTDOWN(0, "Normal"), + CONFIG_ERROR(1, "Configuration"), + INITIALIZATION_ERROR(2, "Initialization"), + DATABASE_ERROR(3, "Database"), + EVENT_ERROR(4, "Event Trigger"), + FATAL_ERROR(-1, "Fatal"); + + + private final int code; + private final String description; + + ExitReason(int code, String description) { + this.code = code; + this.description = description; + } +} diff --git a/common/src/main/java/org/tron/common/exit/TronExitException.java b/common/src/main/java/org/tron/common/exit/TronExitException.java new file mode 100644 index 00000000000..3d3d0617e84 --- /dev/null +++ b/common/src/main/java/org/tron/common/exit/TronExitException.java @@ -0,0 +1,21 @@ +package org.tron.common.exit; + +import lombok.Getter; + + +@Getter +public class TronExitException extends RuntimeException { + + private final ExitReason exitReason; + + public TronExitException(ExitReason exitReason, String message) { + super(message); + this.exitReason = exitReason; + } + + public TronExitException(ExitReason exitReason, String message, Throwable cause) { + super(message, cause); + this.exitReason = exitReason; + } + +} diff --git a/common/src/main/java/org/tron/core/exception/ConfigException.java b/common/src/main/java/org/tron/core/exception/ConfigException.java new file mode 100644 index 00000000000..9743342dd55 --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/ConfigException.java @@ -0,0 +1,16 @@ +package org.tron.core.exception; + +public class ConfigException extends TronRuntimeException { + + public ConfigException() { + super(); + } + + public ConfigException(String message) { + super(message); + } + + public ConfigException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/common/src/main/java/org/tron/core/exception/EventTriggerException.java b/common/src/main/java/org/tron/core/exception/EventTriggerException.java new file mode 100644 index 00000000000..55d1426aed1 --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/EventTriggerException.java @@ -0,0 +1,16 @@ +package org.tron.core.exception; + +public class EventTriggerException extends TronRuntimeException { + + public EventTriggerException() { + super(); + } + + public EventTriggerException(String message) { + super(message); + } + + public EventTriggerException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/common/src/main/java/org/tron/core/exception/GenesisBlockException.java b/common/src/main/java/org/tron/core/exception/GenesisBlockException.java new file mode 100644 index 00000000000..2bf59c4d271 --- /dev/null +++ b/common/src/main/java/org/tron/core/exception/GenesisBlockException.java @@ -0,0 +1,16 @@ +package org.tron.core.exception; + +public class GenesisBlockException extends TronRuntimeException { + + public GenesisBlockException() { + super(); + } + + public GenesisBlockException(String message) { + super(message); + } + + public GenesisBlockException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/framework/build.gradle b/framework/build.gradle index 91956a9c702..8b162fa44a9 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -40,11 +40,6 @@ dependencies { implementation fileTree(dir: 'libs', include: '*.jar') // end local libraries testImplementation group: 'org.hamcrest', name: 'hamcrest-junit', version: '1.0.0.1' - // https://github.com/stefanbirkner/system-rules/issues/85 - // https://openjdk.org/jeps/411, JEP 411: Deprecate the Security Manager for Removal from JDK17 - // WARNING: A terminally deprecated method in java.lang.System has been called - // WARNING: System::setSecurityManager will be removed in a future release - testImplementation group: 'com.github.stefanbirkner', name: 'system-rules', version: '1.16.0' implementation group: 'com.google.inject', name: 'guice', version: '4.1.0' implementation group: 'io.dropwizard.metrics', name: 'metrics-core', version: '3.1.2' diff --git a/framework/src/main/java/org/tron/common/application/ApplicationImpl.java b/framework/src/main/java/org/tron/common/application/ApplicationImpl.java index 28108adfa88..04711c1480d 100644 --- a/framework/src/main/java/org/tron/common/application/ApplicationImpl.java +++ b/framework/src/main/java/org/tron/common/application/ApplicationImpl.java @@ -4,6 +4,8 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.parameter.CommonParameter; import org.tron.core.ChainBaseManager; import org.tron.core.config.args.Args; @@ -82,8 +84,8 @@ public void startServices() { try { services.start(); } catch (Exception e) { - logger.error("Failed to start services", e); - System.exit(1); + ExitManager.getInstance().exit(ExitReason.INITIALIZATION_ERROR, + "Failed to start services", e); } } diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 84b2dd07fed..3aab95e9f7e 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -51,6 +51,8 @@ import org.tron.common.args.Witness; import org.tron.common.config.DbBackupConfig; import org.tron.common.crypto.SignInterface; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.logsfilter.EventPluginConfig; import org.tron.common.logsfilter.FilterQuery; import org.tron.common.logsfilter.TriggerConfig; @@ -377,7 +379,7 @@ public static void setParam(final String[] args, final Config config) { JCommander.newBuilder().addObject(PARAMETER).build().parse(args); if (PARAMETER.version) { printVersion(); - exit(0); + ExitManager.getInstance().exit(ExitReason.NORMAL_SHUTDOWN); } if (config.hasPath(Constant.NET_TYPE) @@ -436,9 +438,8 @@ public static void setParam(final String[] args, final Config config) { String prikey = ByteArray.toHexString(sign.getPrivateKey()); privateKeys.add(prikey); } catch (IOException | CipherException e) { - logger.error(e.getMessage()); - logger.error("Witness node start failed!"); - exit(-1); + ExitManager.getInstance().exit(ExitReason.INITIALIZATION_ERROR, + "Witness node start failed!", e); } } } diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index 5a3da6d4650..0dea320400e 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -53,6 +53,8 @@ import org.tron.common.args.GenesisBlock; import org.tron.common.bloom.Bloom; import org.tron.common.es.ExecutorServiceManager; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.logsfilter.EventPluginLoader; import org.tron.common.logsfilter.FilterQuery; import org.tron.common.logsfilter.capsule.BlockFilterCapsule; @@ -119,6 +121,7 @@ import org.tron.core.exception.ContractValidateException; import org.tron.core.exception.DupTransactionException; import org.tron.core.exception.EventBloomException; +import org.tron.core.exception.GenesisBlockException; import org.tron.core.exception.ItemNotFoundException; import org.tron.core.exception.NonCommonBlockException; import org.tron.core.exception.ReceiptCheckErrException; @@ -494,20 +497,19 @@ public void init() { this.khaosDb.start(chainBaseManager.getBlockById( getDynamicPropertiesStore().getLatestBlockHeaderHash())); } catch (ItemNotFoundException e) { - logger.error( - "Can not find Dynamic highest block from DB! \nnumber={} \nhash={}", + String info = String.format( + "Can not find Dynamic highest block from DB! \nnumber=%s \nhash=%s", getDynamicPropertiesStore().getLatestBlockHeaderNumber(), getDynamicPropertiesStore().getLatestBlockHeaderHash()); logger.error( "Please delete database directory({}) and restart", Args.getInstance().getOutputDirectory()); - System.exit(1); + ExitManager.getInstance().exit(ExitReason.DATABASE_ERROR, info, e); } catch (BadItemException e) { - logger.error("DB data broken {}.", e.getMessage()); logger.error( "Please delete database directory({}) and restart.", Args.getInstance().getOutputDirectory()); - System.exit(1); + ExitManager.getInstance().exit(ExitReason.DATABASE_ERROR, "DB data broken", e); } getChainBaseManager().getForkController().init(this.chainBaseManager); @@ -571,8 +573,7 @@ public void init() { try { initAutoStop(); } catch (IllegalArgumentException e) { - logger.error("Auto-stop params error: {}", e.getMessage()); - System.exit(1); + ExitManager.getInstance().exit(ExitReason.CONFIG_ERROR, "Auto-stop params", e); } maxFlushCount = CommonParameter.getInstance().getStorage().getMaxFlushCount(); @@ -589,10 +590,10 @@ public void initGenesis() { Args.getInstance().setChainId(genesisBlock.getBlockId().toString()); } else { if (chainBaseManager.hasBlocks()) { - logger.error( - "Genesis block modify, please delete database directory({}) and restart.", + String info = String.format( + "Genesis block modify, please delete database directory(%s) and restart.", Args.getInstance().getOutputDirectory()); - System.exit(1); + ExitManager.getInstance().exit(ExitReason.CONFIG_ERROR, new GenesisBlockException(info)); } else { logger.info("Create genesis block."); Args.getInstance().setChainId(genesisBlock.getBlockId().toString()); @@ -744,9 +745,9 @@ private void initAutoStop() { } if (exitHeight == headNum && (!Args.getInstance().isP2pDisable())) { - logger.info("Auto-stop hit: shutDownBlockHeight: {}, currentHeaderNum: {}, exit now", + String info = String.format("Auto-stop hit: shutDownBlockHeight: %d, currentHeaderNum: %d", exitHeight, headNum); - System.exit(0); + ExitManager.getInstance().exit(ExitReason.NORMAL_SHUTDOWN, info); } if (exitCount > 0) { @@ -1371,9 +1372,9 @@ void blockTrigger(final BlockCapsule block, long oldSolid, long newSolid) { // if event subscribe is enabled, post solidity trigger to queue postSolidityTrigger(oldSolid, newSolid); } catch (Exception e) { - logger.error("Block trigger failed. head: {}, oldSolid: {}, newSolid: {}", - block.getNum(), oldSolid, newSolid, e); - System.exit(1); + ExitManager.getInstance().exit(ExitReason.EVENT_ERROR, String.format( + "Block trigger failed. head: %d, oldSolid: %d, newSolid: %d", + block.getNum(), oldSolid, newSolid), e); } } diff --git a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java index 050f6df7af9..997272df60e 100644 --- a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java +++ b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java @@ -9,16 +9,14 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.LockSupport; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import lombok.Getter; -import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.tron.common.backup.socket.BackupServer; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.overlay.message.Message; import org.tron.common.prometheus.MetricKeys; import org.tron.common.prometheus.MetricLabels; @@ -91,14 +89,9 @@ public class TronNetDelegate { private long timeout = 1000; - @Getter // for test + @Getter private volatile boolean hitDown = false; - private Thread hitThread; - - @Setter - private volatile boolean exit = true; - private int maxUnsolidifiedBlocks = Args.getInstance().getMaxUnsolidifiedBlocks(); private boolean unsolidifiedBlockCheck @@ -108,30 +101,6 @@ public class TronNetDelegate { .maximumSize(blockIdCacheSize).expireAfterWrite(1, TimeUnit.HOURS) .recordStats().build(); - @PostConstruct - public void init() { - hitThread = new Thread(() -> { - LockSupport.park(); - // to Guarantee Some other thread invokes unpark with the current thread as the target - if (hitDown && exit) { - System.exit(0); - } - }); - hitThread.setName("hit-thread"); - hitThread.start(); - } - - @PreDestroy - public void close() { - try { - hitThread.interrupt(); - // help GC - hitThread = null; - } catch (Exception e) { - logger.warn("hitThread interrupt error", e); - } - } - public Collection getActivePeer() { return TronNetService.getPeers(); } @@ -229,10 +198,6 @@ public Message getData(Sha256Hash hash, InventoryType type) throws P2pException } } - public void unparkHitThread() { - LockSupport.unpark(hitThread); - } - public void markHitDown() { hitDown = true; } @@ -241,13 +206,12 @@ public void processBlock(BlockCapsule block, boolean isSync) throws P2pException if (!hitDown && dbManager.getLatestSolidityNumShutDown() > 0 && dbManager.getLatestSolidityNumShutDown() == dbManager.getDynamicPropertiesStore() .getLatestBlockHeaderNumberFromDB()) { - - logger.info("Begin shutdown, currentBlockNum:{}, DbBlockNum:{}, solidifiedBlockNum:{}", - dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(), - dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumberFromDB(), - dbManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); + String info = "Begin shutdown, currentBlockNum:" + dbManager.getDynamicPropertiesStore() + .getLatestBlockHeaderNumber() + ", DbBlockNum:" + dbManager.getDynamicPropertiesStore() + .getLatestBlockHeaderNumberFromDB() + ", solidifiedBlockNum:" + dbManager + .getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); markHitDown(); - unparkHitThread(); + ExitManager.getInstance().exit(ExitReason.NORMAL_SHUTDOWN, info); return; } if (hitDown) { diff --git a/framework/src/main/java/org/tron/core/services/SolidityService.java b/framework/src/main/java/org/tron/core/services/SolidityService.java index 641ffb3257c..d6dddb95246 100644 --- a/framework/src/main/java/org/tron/core/services/SolidityService.java +++ b/framework/src/main/java/org/tron/core/services/SolidityService.java @@ -11,6 +11,8 @@ import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.tron.common.client.DatabaseGrpcClient; +import org.tron.common.exit.ExitManager; +import org.tron.common.exit.ExitReason; import org.tron.common.parameter.CommonParameter; import org.tron.core.ChainBaseManager; import org.tron.core.capsule.BlockCapsule; @@ -74,9 +76,9 @@ private void start() { logger.info("Success to start solid node, ID: {}, remoteBlockNum: {}.", ID.get(), remoteBlockNum); } catch (Exception e) { - logger.error("Failed to start solid node, address: {}.", - CommonParameter.getInstance().getTrustNodeAddr()); - System.exit(0); + String info = "Failed to start solid node, address: " + CommonParameter.getInstance() + .getTrustNodeAddr(); + ExitManager.getInstance().exit(ExitReason.INITIALIZATION_ERROR, info, e); } } @@ -111,12 +113,12 @@ private void processBlock() { sleep(exceptionSleepTime); } } - logger.info("Begin shutdown, currentBlockNum:{}, DbBlockNum:{}, solidifiedBlockNum:{}", - dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(), - dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumberFromDB(), - dbManager.getDynamicPropertiesStore().getLatestSolidifiedBlockNum()); + String info = "Begin shutdown, currentBlockNum:" + dbManager.getDynamicPropertiesStore() + .getLatestBlockHeaderNumber() + ", DbBlockNum:" + dbManager.getDynamicPropertiesStore() + .getLatestBlockHeaderNumberFromDB() + ", solidifiedBlockNum:" + dbManager + .getDynamicPropertiesStore().getLatestSolidifiedBlockNum(); tronNetDelegate.markHitDown(); - tronNetDelegate.unparkHitThread(); + ExitManager.getInstance().exit(ExitReason.NORMAL_SHUTDOWN, info); } private void loopProcessBlock(Block block) { diff --git a/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java b/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java index 54bc02baf98..0123748940e 100644 --- a/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java +++ b/framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java @@ -46,10 +46,10 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.ExpectedSystemExit; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.rocksdb.RocksDB; +import org.tron.common.exit.TronExitException; import org.tron.common.parameter.CommonParameter; import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.rocksdb.RocksDbDataSourceImpl; @@ -83,9 +83,6 @@ public class LevelDbDataSourceImplTest { private byte[] key5 = "00000005aa".getBytes(); private byte[] key6 = "00000006aa".getBytes(); - @Rule - public final ExpectedSystemExit exit = ExpectedSystemExit.none(); - @Rule public final ExpectedException exception = ExpectedException.none(); @@ -395,7 +392,7 @@ public void prefixQueryTest() { @Test public void initDbTest() { - exit.expectSystemExitWithStatus(1); + exception.expect(TronExitException.class); makeExceptionDb("test_initDb"); LevelDbDataSourceImpl dataSource = new LevelDbDataSourceImpl( Args.getInstance().getOutputDirectory(), "test_initDb"); diff --git a/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java b/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java index da769262d09..e050455c766 100644 --- a/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java +++ b/framework/src/test/java/org/tron/common/storage/leveldb/RocksDbDataSourceImplTest.java @@ -28,12 +28,11 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.ExpectedSystemExit; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.rocksdb.RocksDBException; +import org.tron.common.exit.TronExitException; import org.tron.common.parameter.CommonParameter; -import org.tron.common.setting.RocksDbSettings; import org.tron.common.storage.WriteOptionsWrapper; import org.tron.common.storage.rocksdb.RocksDbDataSourceImpl; import org.tron.common.utils.ByteArray; @@ -64,9 +63,6 @@ public class RocksDbDataSourceImplTest { private byte[] key5 = "00000005aa".getBytes(); private byte[] key6 = "00000006aa".getBytes(); - @Rule - public final ExpectedSystemExit exit = ExpectedSystemExit.none(); - @Rule public final ExpectedException expectedException = ExpectedException.none(); @@ -431,7 +427,7 @@ public void prefixQueryTest() { @Test public void initDbTest() { - exit.expectSystemExitWithStatus(1); + expectedException.expect(TronExitException.class); makeExceptionDb("test_initDb"); RocksDbDataSourceImpl dataSource = new RocksDbDataSourceImpl( Args.getInstance().getOutputDirectory(), "test_initDb"); diff --git a/framework/src/test/java/org/tron/core/db/ManagerTest.java b/framework/src/test/java/org/tron/core/db/ManagerTest.java index 07440435f41..f6f2e548213 100755 --- a/framework/src/test/java/org/tron/core/db/ManagerTest.java +++ b/framework/src/test/java/org/tron/core/db/ManagerTest.java @@ -30,10 +30,11 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.ExpectedSystemExit; +import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.tron.common.application.TronApplicationContext; import org.tron.common.crypto.ECKey; +import org.tron.common.exit.TronExitException; import org.tron.common.runtime.RuntimeImpl; import org.tron.common.utils.ByteArray; import org.tron.common.utils.JsonUtil; @@ -92,7 +93,6 @@ import org.tron.protos.Protocol.Block; import org.tron.protos.Protocol.Transaction; import org.tron.protos.Protocol.Transaction.Contract.ContractType; -import org.tron.protos.Protocol.Transaction.raw; import org.tron.protos.contract.AccountContract; import org.tron.protos.contract.AssetIssueContractOuterClass; import org.tron.protos.contract.BalanceContract.TransferContract; @@ -112,7 +112,7 @@ public class ManagerTest extends BlockGenerate { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule - public final ExpectedSystemExit exit = ExpectedSystemExit.none(); + public final ExpectedException exception = ExpectedException.none(); private static AtomicInteger port = new AtomicInteger(0); private static String accountAddress = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc"; @@ -1160,7 +1160,7 @@ public void testTooBigTransaction() { @Test public void blockTrigger() { - exit.expectSystemExitWithStatus(1); + exception.expect(TronExitException.class); Manager manager = spy(new Manager()); doThrow(new RuntimeException("postBlockTrigger mock")).when(manager).postBlockTrigger(any()); manager.blockTrigger(new BlockCapsule(Block.newBuilder().build()), 1, 1); diff --git a/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java b/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java index 0082c8728da..9a9d3058e50 100644 --- a/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java +++ b/framework/src/test/java/org/tron/core/services/ComputeRewardTest.java @@ -17,11 +17,12 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.contrib.java.lang.system.ExpectedSystemExit; +import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.tron.common.application.TronApplicationContext; import org.tron.common.error.TronDBException; import org.tron.common.es.ExecutorServiceManager; +import org.tron.common.exit.TronExitException; import org.tron.common.utils.ByteArray; import org.tron.common.utils.ReflectUtils; import org.tron.core.Constant; @@ -115,7 +116,7 @@ public class ComputeRewardTest { public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Rule - public final ExpectedSystemExit exit = ExpectedSystemExit.none(); + public final ExpectedException exception = ExpectedException.none(); @After public void destroy() { @@ -263,7 +264,7 @@ private void setUp() { @Test public void query() { - exit.expectSystemExitWithStatus(1); + exception.expect(TronExitException.class); Assert.assertEquals(3189, mortgageService.queryReward(OWNER_ADDRESS)); // mock root is error rewardViStore.put("test".getBytes(), "test".getBytes()); diff --git a/framework/src/test/java/org/tron/core/services/stop/ConditionallyStopTest.java b/framework/src/test/java/org/tron/core/services/stop/ConditionallyStopTest.java index dc3d02e7ced..1ad55ca24d5 100644 --- a/framework/src/test/java/org/tron/core/services/stop/ConditionallyStopTest.java +++ b/framework/src/test/java/org/tron/core/services/stop/ConditionallyStopTest.java @@ -2,14 +2,11 @@ import com.google.common.collect.Maps; import com.google.protobuf.ByteString; -import java.io.File; import java.io.IOException; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -25,8 +22,6 @@ import org.tron.common.crypto.ECKey; import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; -import org.tron.common.utils.FileUtil; -import org.tron.common.utils.LocalWitnesses; import org.tron.common.utils.PublicMethod; import org.tron.common.utils.Sha256Hash; import org.tron.common.utils.Utils; @@ -95,7 +90,6 @@ public void init() throws Exception { consensusService.start(); chainManager = dbManager.getChainBaseManager(); tronNetDelegate = context.getBean(TronNetDelegate.class); - tronNetDelegate.setExit(false); currentHeader = dbManager.getDynamicPropertiesStore() .getLatestBlockHeaderNumberFromDB();