Skip to content

Commit 9f42782

Browse files
Merge pull request #6177 from halibobo1205/feat/exit_opt
feat(*): optimize system.exit usage
2 parents 791ee6c + a86d0ed commit 9f42782

File tree

16 files changed

+128
-57
lines changed

16 files changed

+128
-57
lines changed

chainbase/src/main/java/org/tron/common/storage/leveldb/LevelDbDataSourceImpl.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import org.tron.core.db.common.iterator.StoreIterator;
6060
import org.tron.core.db2.common.Instance;
6161
import org.tron.core.db2.common.WrappedByteArray;
62+
import org.tron.core.exception.TronError;
6263

6364
@Slf4j(topic = "DB")
6465
@NoArgsConstructor
@@ -157,7 +158,7 @@ private void openDatabase(Options dbOptions) throws IOException {
157158
} else {
158159
logger.error("Open Database {} failed", dataBaseName, e);
159160
}
160-
System.exit(1);
161+
throw new TronError(e, TronError.ErrCode.LEVELDB_INIT);
161162
}
162163
}
163164

chainbase/src/main/java/org/tron/common/storage/rocksdb/RocksDbDataSourceImpl.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.tron.core.db.common.iterator.RockStoreIterator;
4646
import org.tron.core.db2.common.Instance;
4747
import org.tron.core.db2.common.WrappedByteArray;
48+
import org.tron.core.exception.TronError;
4849

4950

5051
@Slf4j(topic = "DB")
@@ -272,7 +273,7 @@ protected void log(InfoLogLevel infoLogLevel, String logMsg) {
272273
} else {
273274
logger.error("Open Database {} failed", dataBaseName, e);
274275
}
275-
System.exit(1);
276+
throw new TronError(e, TronError.ErrCode.ROCKSDB_INIT);
276277
}
277278

278279
alive = true;

chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java

+9-26
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.util.concurrent.ScheduledExecutorService;
2121
import java.util.concurrent.TimeUnit;
2222
import java.util.concurrent.atomic.AtomicInteger;
23-
import java.util.concurrent.locks.LockSupport;
2423
import java.util.stream.Collectors;
2524
import javax.annotation.PostConstruct;
2625
import lombok.Getter;
@@ -42,6 +41,7 @@
4241
import org.tron.core.db2.common.Value;
4342
import org.tron.core.db2.common.WrappedByteArray;
4443
import org.tron.core.exception.RevokingStoreIllegalStateException;
44+
import org.tron.core.exception.TronError;
4545
import org.tron.core.store.CheckPointV2Store;
4646
import org.tron.core.store.CheckTmpStore;
4747

@@ -68,7 +68,6 @@ public class SnapshotManager implements RevokingDatabase {
6868

6969
private volatile int flushCount = 0;
7070

71-
private Thread exitThread;
7271
private volatile boolean hitDown;
7372

7473
private Map<String, ListeningExecutorService> flushServices = new HashMap<>();
@@ -105,15 +104,6 @@ public void init() {
105104
}
106105
}, 10000, 3600, TimeUnit.MILLISECONDS);
107106
}
108-
exitThread = new Thread(() -> {
109-
LockSupport.park();
110-
// to Guarantee Some other thread invokes unpark with the current thread as the target
111-
if (hitDown) {
112-
System.exit(1);
113-
}
114-
});
115-
exitThread.setName("exit-thread");
116-
exitThread.start();
117107
}
118108

119109
public static String simpleDecode(byte[] bytes) {
@@ -281,13 +271,6 @@ public void shutdown() {
281271
ExecutorServiceManager.shutdownAndAwaitTermination(pruneCheckpointThread, pruneName);
282272
flushServices.forEach((key, value) -> ExecutorServiceManager.shutdownAndAwaitTermination(value,
283273
"flush-service-" + key));
284-
try {
285-
exitThread.interrupt();
286-
// help GC
287-
exitThread = null;
288-
} catch (Exception e) {
289-
logger.warn("exitThread interrupt error", e);
290-
}
291274
}
292275

293276
public void updateSolidity(int hops) {
@@ -298,7 +281,7 @@ public void updateSolidity(int hops) {
298281
}
299282
}
300283

301-
private boolean shouldBeRefreshed() {
284+
public boolean shouldBeRefreshed() {
302285
return flushCount >= maxFlushCount;
303286
}
304287

@@ -367,12 +350,12 @@ public void flush() {
367350
} catch (TronDBException e) {
368351
logger.error(" Find fatal error, program will be exited soon.", e);
369352
hitDown = true;
370-
LockSupport.unpark(exitThread);
353+
throw new TronError(e, TronError.ErrCode.DB_FLUSH);
371354
}
372355
}
373356
}
374357

375-
private void createCheckpoint() {
358+
public void createCheckpoint() {
376359
TronDatabase<byte[]> checkPointStore = null;
377360
boolean syncFlag;
378361
try {
@@ -430,7 +413,7 @@ private TronDatabase<byte[]> getCheckpointDB(String dbName) {
430413
return new CheckPointV2Store(CHECKPOINT_V2_DIR+"/"+dbName);
431414
}
432415

433-
private List<String> getCheckpointList() {
416+
public List<String> getCheckpointList() {
434417
String dbPath = Paths.get(StorageUtils.getOutputDirectoryByDbName(CHECKPOINT_V2_DIR),
435418
CommonParameter.getInstance().getStorage().getDbDirectory()).toString();
436419
File file = new File(Paths.get(dbPath, CHECKPOINT_V2_DIR).toString());
@@ -490,10 +473,10 @@ public void check() {
490473
if (!isV2Open()) {
491474
List<String> cpList = getCheckpointList();
492475
if (cpList != null && cpList.size() != 0) {
493-
logger.error("checkpoint check failed, the checkpoint version of database not match your " +
494-
"config file, please set storage.checkpoint.version = 2 in your config file " +
495-
"and restart the node.");
496-
System.exit(-1);
476+
String msg = "checkpoint check failed, the checkpoint version of database not match your "
477+
+ "config file, please set storage.checkpoint.version = 2 in your config file "
478+
+ "and restart the node.";
479+
throw new TronError(msg, TronError.ErrCode.CHECKPOINT_VERSION);
497480
}
498481
checkV1();
499482
} else {

chainbase/src/main/java/org/tron/core/service/RewardViCalService.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.tron.common.utils.Sha256Hash;
3131
import org.tron.core.db.common.iterator.DBIterator;
3232
import org.tron.core.db2.common.DB;
33+
import org.tron.core.exception.TronError;
3334
import org.tron.core.store.DelegationStore;
3435
import org.tron.core.store.DynamicPropertiesStore;
3536
import org.tron.core.store.RewardViStore;
@@ -121,7 +122,7 @@ private void maybeRun() {
121122
}
122123
} catch (Exception e) {
123124
logger.error(" Find fatal error, program will be exited soon.", e);
124-
System.exit(1);
125+
throw new TronError(e, TronError.ErrCode.REWARD_VI_CALCULATOR);
125126
}
126127
}
127128

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package org.tron.common.exit;
2+
3+
import java.util.HashSet;
4+
import java.util.Optional;
5+
import java.util.Set;
6+
import java.util.concurrent.ThreadFactory;
7+
import lombok.extern.slf4j.Slf4j;
8+
import org.tron.core.exception.TronError;
9+
10+
@Slf4j(topic = "Exit")
11+
public class ExitManager {
12+
13+
private static final ThreadFactory exitThreadFactory = r -> {
14+
Thread thread = new Thread(r, "System-Exit-Thread");
15+
thread.setDaemon(true);
16+
return thread;
17+
};
18+
19+
private ExitManager() {
20+
21+
}
22+
23+
public static void initExceptionHandler() {
24+
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
25+
findTronError(e).ifPresent(ExitManager::logAndExit);
26+
logger.error("Uncaught exception", e);
27+
});
28+
}
29+
30+
public static Optional<TronError> findTronError(Throwable e) {
31+
if (e == null) {
32+
return Optional.empty();
33+
}
34+
35+
Set<Throwable> seen = new HashSet<>();
36+
37+
while (e != null && !seen.contains(e)) {
38+
if (e instanceof TronError) {
39+
return Optional.of((TronError) e);
40+
}
41+
seen.add(e);
42+
e = e.getCause();
43+
}
44+
return Optional.empty();
45+
}
46+
47+
private static void logAndExit(TronError exit) {
48+
final int code = exit.getErrCode().getCode();
49+
logger.error("Shutting down with code: {}.", exit.getErrCode(), exit);
50+
Thread exitThread = exitThreadFactory.newThread(() -> System.exit(code));
51+
exitThread.start();
52+
}
53+
}

framework/build.gradle

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ dependencies {
3939
implementation fileTree(dir: 'libs', include: '*.jar')
4040
// end local libraries
4141
testImplementation group: 'org.hamcrest', name: 'hamcrest-junit', version: '1.0.0.1'
42-
testImplementation group: 'com.github.stefanbirkner', name: 'system-rules', version: '1.16.0'
4342

4443
implementation group: 'com.google.inject', name: 'guice', version: '4.1.0'
4544
implementation group: 'io.dropwizard.metrics', name: 'metrics-core', version: '3.1.2'

framework/src/main/java/org/tron/core/config/DefaultConfig.java

-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ public class DefaultConfig {
3737
public CommonConfig commonConfig;
3838

3939
public DefaultConfig() {
40-
Thread.setDefaultUncaughtExceptionHandler((t, e) -> logger.error("Uncaught exception", e));
4140
}
4241

4342
@Bean(destroyMethod = "")

framework/src/main/java/org/tron/core/config/args/Args.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.tron.core.config.Parameter.NetConstants;
6767
import org.tron.core.config.Parameter.NodeConstant;
6868
import org.tron.core.exception.CipherException;
69+
import org.tron.core.exception.TronError;
6970
import org.tron.core.store.AccountStore;
7071
import org.tron.keystore.Credentials;
7172
import org.tron.keystore.WalletUtils;
@@ -433,9 +434,8 @@ public static void setParam(final Config config) {
433434
String prikey = ByteArray.toHexString(sign.getPrivateKey());
434435
privateKeys.add(prikey);
435436
} catch (IOException | CipherException e) {
436-
logger.error(e.getMessage());
437437
logger.error("Witness node start failed!");
438-
exit(-1);
438+
throw new TronError(e, TronError.ErrCode.WITNESS_KEYSTORE_LOAD);
439439
}
440440
}
441441
}

framework/src/main/java/org/tron/core/db/Manager.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
import org.tron.core.exception.TooBigTransactionException;
124124
import org.tron.core.exception.TooBigTransactionResultException;
125125
import org.tron.core.exception.TransactionExpirationException;
126+
import org.tron.core.exception.TronError;
126127
import org.tron.core.exception.UnLinkedBlockException;
127128
import org.tron.core.exception.VMIllegalException;
128129
import org.tron.core.exception.ValidateScheduleException;
@@ -498,13 +499,13 @@ public void init() {
498499
logger.error(
499500
"Please delete database directory({}) and restart",
500501
Args.getInstance().getOutputDirectory());
501-
System.exit(1);
502+
throw new TronError(e, TronError.ErrCode.KHAOS_DB_INIT);
502503
} catch (BadItemException e) {
503504
logger.error("DB data broken {}.", e.getMessage());
504505
logger.error(
505506
"Please delete database directory({}) and restart.",
506507
Args.getInstance().getOutputDirectory());
507-
System.exit(1);
508+
throw new TronError(e, TronError.ErrCode.KHAOS_DB_INIT);
508509
}
509510
getChainBaseManager().getForkController().init(this.chainBaseManager);
510511

@@ -569,7 +570,7 @@ public void init() {
569570
initAutoStop();
570571
} catch (IllegalArgumentException e) {
571572
logger.error("Auto-stop params error: {}", e.getMessage());
572-
System.exit(1);
573+
throw new TronError(e, TronError.ErrCode.AUTO_STOP_PARAMS);
573574
}
574575

575576
maxFlushCount = CommonParameter.getInstance().getStorage().getMaxFlushCount();
@@ -586,10 +587,9 @@ public void initGenesis() {
586587
Args.getInstance().setChainId(genesisBlock.getBlockId().toString());
587588
} else {
588589
if (chainBaseManager.hasBlocks()) {
589-
logger.error(
590-
"Genesis block modify, please delete database directory({}) and restart.",
591-
Args.getInstance().getOutputDirectory());
592-
System.exit(1);
590+
String msg = String.format("Genesis block modify, please delete database directory(%s) and "
591+
+ "restart.", Args.getInstance().getOutputDirectory());
592+
throw new TronError(msg, TronError.ErrCode.GENESIS_BLOCK_INIT);
593593
} else {
594594
logger.info("Create genesis block.");
595595
Args.getInstance().setChainId(genesisBlock.getBlockId().toString());
@@ -1370,7 +1370,7 @@ void blockTrigger(final BlockCapsule block, long oldSolid, long newSolid) {
13701370
} catch (Exception e) {
13711371
logger.error("Block trigger failed. head: {}, oldSolid: {}, newSolid: {}",
13721372
block.getNum(), oldSolid, newSolid, e);
1373-
System.exit(1);
1373+
throw new TronError(e, TronError.ErrCode.EVENT_SUBSCRIBE_ERROR);
13741374
}
13751375
}
13761376

framework/src/main/java/org/tron/program/FullNode.java

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.tron.common.application.Application;
1111
import org.tron.common.application.ApplicationFactory;
1212
import org.tron.common.application.TronApplicationContext;
13+
import org.tron.common.exit.ExitManager;
1314
import org.tron.common.parameter.CommonParameter;
1415
import org.tron.common.prometheus.Metrics;
1516
import org.tron.core.Constant;
@@ -40,6 +41,7 @@ public static void load(String path) {
4041
* Start the FullNode.
4142
*/
4243
public static void main(String[] args) {
44+
ExitManager.initExceptionHandler();
4345
logger.info("Full node running.");
4446
Args.setParam(args, Constant.TESTNET_CONF);
4547
CommonParameter parameter = Args.getInstance();

framework/src/main/java/org/tron/program/SolidityNode.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.tron.common.application.ApplicationFactory;
1313
import org.tron.common.application.TronApplicationContext;
1414
import org.tron.common.client.DatabaseGrpcClient;
15+
import org.tron.common.exit.ExitManager;
1516
import org.tron.common.parameter.CommonParameter;
1617
import org.tron.common.prometheus.Metrics;
1718
import org.tron.core.ChainBaseManager;
@@ -20,6 +21,7 @@
2021
import org.tron.core.config.DefaultConfig;
2122
import org.tron.core.config.args.Args;
2223
import org.tron.core.db.Manager;
24+
import org.tron.core.exception.TronError;
2325
import org.tron.protos.Protocol.Block;
2426

2527
@Slf4j(topic = "app")
@@ -54,6 +56,7 @@ public SolidityNode(Manager dbManager) {
5456
* Start the SolidityNode.
5557
*/
5658
public static void main(String[] args) {
59+
ExitManager.initExceptionHandler();
5760
logger.info("Solidity node is running.");
5861
Args.setParam(args, Constant.TESTNET_CONF);
5962
CommonParameter parameter = CommonParameter.getInstance();
@@ -98,7 +101,7 @@ private void start() {
98101
} catch (Exception e) {
99102
logger.error("Failed to start solid node, address: {}.",
100103
CommonParameter.getInstance().getTrustNodeAddr());
101-
System.exit(0);
104+
throw new TronError(e, TronError.ErrCode.SOLID_NODE_INIT);
102105
}
103106
}
104107

framework/src/test/java/org/tron/common/storage/leveldb/LevelDbDataSourceImplTest.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,15 @@
4343
import org.junit.ClassRule;
4444
import org.junit.Rule;
4545
import org.junit.Test;
46-
import org.junit.contrib.java.lang.system.ExpectedSystemExit;
46+
import org.junit.rules.ExpectedException;
4747
import org.junit.rules.TemporaryFolder;
4848
import org.tron.common.utils.ByteArray;
4949
import org.tron.common.utils.FileUtil;
5050
import org.tron.common.utils.PublicMethod;
5151
import org.tron.core.Constant;
5252
import org.tron.core.config.args.Args;
5353
import org.tron.core.db2.common.WrappedByteArray;
54+
import org.tron.core.exception.TronError;
5455

5556
@Slf4j
5657
public class LevelDbDataSourceImplTest {
@@ -74,7 +75,7 @@ public class LevelDbDataSourceImplTest {
7475
private byte[] key6 = "00000006aa".getBytes();
7576

7677
@Rule
77-
public final ExpectedSystemExit exit = ExpectedSystemExit.none();
78+
public final ExpectedException exception = ExpectedException.none();
7879

7980
/**
8081
* Release resources.
@@ -350,7 +351,7 @@ public void prefixQueryTest() {
350351

351352
@Test
352353
public void initDbTest() {
353-
exit.expectSystemExitWithStatus(1);
354+
exception.expect(TronError.class);
354355
makeExceptionDb("test_initDb");
355356
LevelDbDataSourceImpl dataSource = new LevelDbDataSourceImpl(
356357
Args.getInstance().getOutputDirectory(), "test_initDb");

0 commit comments

Comments
 (0)