Skip to content

Commit 046eab5

Browse files
committed
feat(liteFullNodeTool): optimize liteFullNodeTool
1. disable light node data to split history data 2. disable history data splitted from light node data to merge 3. disable split if block is less than 65536 4. add latest 65536 blocks and related transactions into snapshot data 5. remove light node minimum dbs check
1 parent 7f3ed0a commit 046eab5

2 files changed

Lines changed: 165 additions & 168 deletions

File tree

framework/src/main/java/org/tron/tool/litefullnode/LiteFullNodeTool.java

Lines changed: 106 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.beust.jcommander.Parameter;
55
import com.beust.jcommander.ParameterException;
66
import com.beust.jcommander.internal.Lists;
7+
import com.google.common.annotations.VisibleForTesting;
78
import com.google.common.base.Strings;
89
import com.google.common.collect.Maps;
910
import com.google.common.primitives.Bytes;
@@ -16,9 +17,9 @@
1617
import java.nio.file.Paths;
1718
import java.util.Arrays;
1819
import java.util.List;
20+
import java.util.NoSuchElementException;
1921
import java.util.Objects;
2022
import java.util.Optional;
21-
import java.util.stream.LongStream;
2223
import lombok.extern.slf4j.Slf4j;
2324
import org.apache.commons.lang3.StringUtils;
2425
import org.rocksdb.RocksDBException;
@@ -47,50 +48,23 @@ public class LiteFullNodeTool {
4748
private static final String INFO_FILE_NAME = "info.properties";
4849
private static final String BACKUP_DIR_PREFIX = ".bak_";
4950
private static final String CHECKPOINT_DB = "tmp";
50-
private static final long VM_NEED_RECENT_BLKS = 256;
51+
private static long RECENT_BLKS = 65536;
5152

5253
private static final String BLOCK_DB_NAME = "block";
5354
private static final String BLOCK_INDEX_DB_NAME = "block-index";
54-
private static final String TRANS_CACHE_DB_NAME = "trans-cache";
55+
private static final String TRANS_DB_NAME = "trans";
5556
private static final String COMMON_DB_NAME = "common";
57+
private static final String TRANSACTION_RET_DB_NAME = "transactionRetStore";
58+
private static final String TRANSACTION_HISTORY_DB_NAME = "transactionHistoryStore";
5659

5760
private static final String DIR_FORMAT_STRING = "%s%s%s";
5861

5962
private static List<String> archiveDbs = Arrays.asList(
6063
BLOCK_DB_NAME,
6164
BLOCK_INDEX_DB_NAME,
62-
"trans",
63-
"transactionRetStore",
64-
"transactionHistoryStore");
65-
private static List<String> minimumDbsForLiteNode = Arrays.asList(
66-
"DelegatedResource",
67-
"DelegatedResourceAccountIndex",
68-
"IncrementalMerkleTree",
69-
"account",
70-
"account-index",
71-
"accountTrie",
72-
"accountid-index",
73-
"asset-issue",
74-
"asset-issue-v2",
75-
//"block_KDB",
76-
"code",
77-
//"common",
78-
"contract",
79-
"delegation",
80-
"exchange",
81-
"exchange-v2",
82-
//"nullifier",
83-
"properties",
84-
"proposal",
85-
"recent-block",
86-
//"recent-transaction",
87-
"storage-row",
88-
//TRANS_CACHE_DB_NAME,
89-
//"tree-block-index",
90-
"votes",
91-
"witness",
92-
"witness_schedule"
93-
);
65+
TRANS_DB_NAME,
66+
TRANSACTION_RET_DB_NAME,
67+
TRANSACTION_HISTORY_DB_NAME);
9468

9569
/**
9670
* Create the snapshot dataset.
@@ -104,13 +78,12 @@ public void generateSnapshot(String sourceDir, String snapshotDir) {
10478
long start = System.currentTimeMillis();
10579
snapshotDir = Paths.get(snapshotDir, SNAPSHOT_DIR_NAME).toString();
10680
try {
81+
hasEnoughBlock(sourceDir);
10782
List<String> snapshotDbs = getSnapshotDbs(sourceDir);
10883
split(sourceDir, snapshotDir, snapshotDbs);
10984
mergeCheckpoint2Snapshot(sourceDir, snapshotDir);
110-
// write genesisBlock and latestBlock
111-
fillSnapshotBlockDb(sourceDir, snapshotDir);
112-
// create tran-cache if not exist, for compatible
113-
checkTranCacheStore(sourceDir, snapshotDir);
85+
// write genesisBlock , latest recent blocks and trans
86+
fillSnapshotBlockAndTransDb(sourceDir, snapshotDir);
11487
generateInfoProperties(Paths.get(snapshotDir, INFO_FILE_NAME).toString(), sourceDir);
11588
} catch (IOException | RocksDBException e) {
11689
logger.error("create snapshot failed, " + e.getMessage());
@@ -132,6 +105,11 @@ public void generateHistory(String sourceDir, String historyDir) {
132105
long start = System.currentTimeMillis();
133106
historyDir = Paths.get(historyDir, HISTORY_DIR_NAME).toString();
134107
try {
108+
if (isLite(sourceDir)) {
109+
throw new IllegalStateException(
110+
String.format("Unavailable sourceDir: %s is not fullNode data.", sourceDir));
111+
}
112+
hasEnoughBlock(sourceDir);
135113
split(sourceDir, historyDir, archiveDbs);
136114
mergeCheckpoint2History(sourceDir, historyDir);
137115
generateInfoProperties(Paths.get(historyDir, INFO_FILE_NAME).toString(), sourceDir);
@@ -155,6 +133,12 @@ public void completeHistoryData(String historyDir, String databaseDir) {
155133
long start = System.currentTimeMillis();
156134
BlockNumInfo blockNumInfo = null;
157135
try {
136+
// check historyDir is from lite data
137+
if (isLite(historyDir)) {
138+
throw new IllegalStateException(
139+
String.format("Unavailable history: %s is not generated by fullNode data.",
140+
historyDir));
141+
}
158142
// 1. check block number and genesis block are compatible,
159143
// and return the block numbers of snapshot and history
160144
blockNumInfo = checkAndGetBlockNumInfo(historyDir, databaseDir);
@@ -183,11 +167,6 @@ private List<String> getSnapshotDbs(String sourceDir) {
183167
.filter(File::isDirectory)
184168
.filter(dir -> !archiveDbs.contains(dir.getName()))
185169
.forEach(dir -> snapshotDbs.add(dir.getName()));
186-
for (String dir : minimumDbsForLiteNode) {
187-
if (!snapshotDbs.contains(dir)) {
188-
throw new RuntimeException("databaseDir does not contain all the necessary databases");
189-
}
190-
}
191170
return snapshotDbs;
192171
}
193172

@@ -270,88 +249,50 @@ private long getLatestBlockHeaderNum(String databaseDir) throws IOException, Roc
270249
}
271250

272251
/**
273-
* Syncing block from peer that needs latest block and genesis block,
274-
* also VM need recent blocks.
252+
* recent blocks, trans and genesis block.
275253
*/
276-
private void fillSnapshotBlockDb(String sourceDir, String snapshotDir)
254+
private void fillSnapshotBlockAndTransDb(String sourceDir, String snapshotDir)
277255
throws IOException, RocksDBException {
278-
logger.info("-- begin to fill latest block and genesis block to snapshot");
256+
logger.info("-- begin to fill {} block , genesis block and trans to snapshot", RECENT_BLKS);
279257
DBInterface sourceBlockIndexDb = DbTool.getDB(sourceDir, BLOCK_INDEX_DB_NAME);
280258
DBInterface sourceBlockDb = DbTool.getDB(sourceDir, BLOCK_DB_NAME);
281259
DBInterface destBlockDb = DbTool.getDB(snapshotDir, BLOCK_DB_NAME);
282260
DBInterface destBlockIndexDb = DbTool.getDB(snapshotDir, BLOCK_INDEX_DB_NAME);
261+
DBInterface destTransDb = DbTool.getDB(snapshotDir, TRANS_DB_NAME);
283262
// put genesis block and block-index into snapshot
284263
long genesisBlockNum = 0L;
285264
byte[] genesisBlockID = sourceBlockIndexDb.get(ByteArray.fromLong(genesisBlockNum));
286265
destBlockIndexDb.put(ByteArray.fromLong(genesisBlockNum), genesisBlockID);
287266
destBlockDb.put(genesisBlockID, sourceBlockDb.get(genesisBlockID));
288267

289268
long latestBlockNum = getLatestBlockHeaderNum(sourceDir);
290-
long startIndex = latestBlockNum > VM_NEED_RECENT_BLKS
291-
? latestBlockNum - VM_NEED_RECENT_BLKS : 0;
292-
// put the recent blocks in snapshot, VM needs recent 256 blocks.
293-
LongStream.rangeClosed(startIndex, latestBlockNum).forEach(
294-
blockNum -> {
295-
byte[] blockId = null;
296-
byte[] block = null;
297-
try {
298-
blockId = getDataFromSourceDB(sourceDir, BLOCK_INDEX_DB_NAME,
299-
Longs.toByteArray(blockNum));
300-
block = getDataFromSourceDB(sourceDir, BLOCK_DB_NAME, blockId);
301-
} catch (IOException | RocksDBException e) {
302-
throw new RuntimeException(e.getMessage());
303-
}
304-
// put recent blocks index into snapshot
305-
destBlockIndexDb.put(ByteArray.fromLong(blockNum), blockId);
306-
// put latest blocks into snapshot
307-
destBlockDb.put(blockId, block);
308-
});
269+
long startIndex = latestBlockNum - RECENT_BLKS + 1;
270+
// put the recent blocks and trans in snapshot
271+
for (long blockNum = startIndex; blockNum <= latestBlockNum; blockNum++) {
272+
try {
273+
byte[] blockId = getDataFromSourceDB(sourceDir, BLOCK_INDEX_DB_NAME,
274+
Longs.toByteArray(blockNum));
275+
byte[] block = getDataFromSourceDB(sourceDir, BLOCK_DB_NAME, blockId);
276+
// put block
277+
destBlockDb.put(blockId, block);
278+
// put block index
279+
destBlockIndexDb.put(ByteArray.fromLong(blockNum), blockId);
280+
// put trans
281+
long finalBlockNum = blockNum;
282+
new BlockCapsule(block).getTransactions().stream().map(
283+
tc -> tc.getTransactionId().getBytes())
284+
.map(bytes -> Maps.immutableEntry(bytes, Longs.toByteArray(finalBlockNum)))
285+
.forEach(e -> destTransDb.put(e.getKey(), e.getValue()));
286+
} catch (IOException | RocksDBException | BadItemException e) {
287+
throw new RuntimeException(e.getMessage());
288+
}
289+
}
309290

310291
DBInterface destCommonDb = DbTool.getDB(snapshotDir, COMMON_DB_NAME);
311292
destCommonDb.put(DB_KEY_NODE_TYPE, ByteArray.fromInt(Constant.NODE_TYPE_LIGHT_NODE));
312293
destCommonDb.put(DB_KEY_LOWEST_BLOCK_NUM, ByteArray.fromLong(startIndex));
313294
}
314295

315-
private void checkTranCacheStore(String sourceDir, String snapshotDir)
316-
throws IOException, RocksDBException {
317-
logger.info("-- create trans-cache db if not exists.");
318-
if (FileUtil.isExists(String.format(DIR_FORMAT_STRING, snapshotDir,
319-
File.separator, TRANS_CACHE_DB_NAME))) {
320-
return;
321-
}
322-
// fullnode is old version, create trans-cache database
323-
DBInterface recentBlockDb = DbTool.getDB(snapshotDir, "recent-block");
324-
DBInterface transCacheDb = DbTool.getDB(snapshotDir, TRANS_CACHE_DB_NAME);
325-
long headNum = getLatestBlockHeaderNum(sourceDir);
326-
long recentBlockCount = recentBlockDb.size();
327-
328-
LongStream.rangeClosed(headNum - recentBlockCount + 1, headNum).forEach(
329-
blockNum -> {
330-
byte[] blockId = null;
331-
byte[] block = null;
332-
try {
333-
blockId = getDataFromSourceDB(sourceDir, BLOCK_INDEX_DB_NAME,
334-
Longs.toByteArray(blockNum));
335-
block = getDataFromSourceDB(sourceDir, BLOCK_DB_NAME, blockId);
336-
} catch (IOException | RocksDBException e) {
337-
throw new RuntimeException(e.getMessage());
338-
}
339-
BlockCapsule blockCapsule = null;
340-
try {
341-
blockCapsule = new BlockCapsule(block);
342-
} catch (BadItemException e) {
343-
throw new RuntimeException("construct block failed, num: " + blockNum);
344-
}
345-
if (blockCapsule.getTransactions().isEmpty()) {
346-
return;
347-
}
348-
blockCapsule.getTransactions().stream()
349-
.map(tc -> tc.getTransactionId().getBytes())
350-
.map(bytes -> Maps.immutableEntry(bytes, Longs.toByteArray(blockNum)))
351-
.forEach(e -> transCacheDb.put(e.getKey(), e.getValue()));
352-
});
353-
}
354-
355296
private byte[] getGenesisBlockHash(String parentDir) throws IOException, RocksDBException {
356297
long genesisBlockNum = 0L;
357298
DBInterface blockIndexDb = DbTool.getDB(parentDir, BLOCK_INDEX_DB_NAME);
@@ -424,8 +365,8 @@ private void trimHistory(String databaseDir, BlockNumInfo blockNumInfo)
424365
logger.info("-- begin to trim the history data.");
425366
DBInterface blockIndexDb = DbTool.getDB(databaseDir, BLOCK_INDEX_DB_NAME);
426367
DBInterface blockDb = DbTool.getDB(databaseDir, BLOCK_DB_NAME);
427-
DBInterface transDb = DbTool.getDB(databaseDir, "trans");
428-
DBInterface tranRetDb = DbTool.getDB(databaseDir, "transactionRetStore");
368+
DBInterface transDb = DbTool.getDB(databaseDir, TRANS_DB_NAME);
369+
DBInterface tranRetDb = DbTool.getDB(databaseDir, TRANSACTION_RET_DB_NAME);
429370
for (long n = blockNumInfo.getHistoryBlkNum(); n > blockNumInfo.getSnapshotBlkNum(); n--) {
430371
byte[] blockIdHash = blockIndexDb.get(ByteArray.fromLong(n));
431372
BlockCapsule block = new BlockCapsule(blockDb.get(blockIdHash));
@@ -460,12 +401,15 @@ private void mergeBak2Database(String databaseDir) throws IOException, RocksDBEx
460401
private byte[] getDataFromSourceDB(String sourceDir, String dbName, byte[] key)
461402
throws IOException, RocksDBException {
462403
DBInterface sourceDb = DbTool.getDB(sourceDir, dbName);
463-
DBInterface checkpointDb = DbTool.getDB(sourceDir, "tmp");
464-
byte[] value = sourceDb.get(key);
465-
if (isEmptyBytes(value)) {
466-
byte[] valueFromTmp = checkpointDb.get(Bytes.concat(simpleEncode(dbName), key));
404+
DBInterface checkpointDb = DbTool.getDB(sourceDir, CHECKPOINT_DB);
405+
// get data from tmp first.
406+
byte[] valueFromTmp = checkpointDb.get(Bytes.concat(simpleEncode(dbName), key));
407+
byte[] value;
408+
if (isEmptyBytes(valueFromTmp)) {
409+
value = sourceDb.get(key);
410+
} else {
467411
value = valueFromTmp.length == 1
468-
? null : Arrays.copyOfRange(valueFromTmp, 1, valueFromTmp.length);
412+
? null : Arrays.copyOfRange(valueFromTmp, 1, valueFromTmp.length);
469413
}
470414
if (isEmptyBytes(value)) {
471415
throw new RuntimeException(String.format("data not found in store, dbName: %s, key: %s",
@@ -489,8 +433,7 @@ private static boolean isEmptyBytes(byte[] b) {
489433
private void deleteSnapshotFlag(String databaseDir) throws IOException, RocksDBException {
490434
logger.info("-- delete the info file.");
491435
Files.delete(Paths.get(databaseDir, INFO_FILE_NAME));
492-
DBInterface destBlockIndexDb = DbTool.getDB(databaseDir, BLOCK_INDEX_DB_NAME);
493-
if (destBlockIndexDb.get(ByteArray.fromLong(1)) != null) {
436+
if (!isLite(databaseDir)) {
494437
DBInterface destCommonDb = DbTool.getDB(databaseDir, COMMON_DB_NAME);
495438
destCommonDb.delete(DB_KEY_NODE_TYPE);
496439
destCommonDb.delete(DB_KEY_LOWEST_BLOCK_NUM);
@@ -500,6 +443,53 @@ private void deleteSnapshotFlag(String databaseDir) throws IOException, RocksDBE
500443

501444
}
502445

446+
private void hasEnoughBlock(String sourceDir) throws RocksDBException, IOException {
447+
// check latest
448+
long latest = getLatestBlockHeaderNum(sourceDir);
449+
// check first, not 0;
450+
long first = 0;
451+
DBInterface sourceBlockIndexDb = DbTool.getDB(sourceDir, BLOCK_INDEX_DB_NAME);
452+
DBIterator iterator = sourceBlockIndexDb.iterator();
453+
iterator.seekToFirst();
454+
if (iterator.hasNext()) {
455+
iterator.next();
456+
if (iterator.hasNext()) {
457+
first = Longs.fromByteArray(iterator.getKey());
458+
}
459+
}
460+
461+
if (latest - first + 1 < RECENT_BLKS) {
462+
throw new NoSuchElementException(
463+
String.format("At least %d blocks in block store, actual latestBlock:%d, firstBlock:%d.",
464+
RECENT_BLKS, latest, first));
465+
}
466+
}
467+
468+
private boolean isLite(String databaseDir) throws RocksDBException, IOException {
469+
DBInterface sourceDb = DbTool.getDB(databaseDir, BLOCK_INDEX_DB_NAME);
470+
DBInterface checkpointDb = DbTool.getDB(databaseDir, CHECKPOINT_DB);
471+
byte[] key = ByteArray.fromLong(1);
472+
byte[] valueFromTmp = checkpointDb.get(Bytes.concat(simpleEncode(BLOCK_INDEX_DB_NAME), key));
473+
byte[] value;
474+
if (isEmptyBytes(valueFromTmp)) {
475+
value = sourceDb.get(key);
476+
} else {
477+
value = valueFromTmp.length == 1
478+
? null : Arrays.copyOfRange(valueFromTmp, 1, valueFromTmp.length);
479+
}
480+
return isEmptyBytes(value);
481+
}
482+
483+
@VisibleForTesting
484+
public static void setRecentBlks(long recentBlks) {
485+
RECENT_BLKS = recentBlks;
486+
}
487+
488+
@VisibleForTesting
489+
public static void reSetRecentBlks() {
490+
RECENT_BLKS = 65536;
491+
}
492+
503493
private void run(Args argv) {
504494
if (StringUtils.isBlank(argv.fnDataPath) || StringUtils.isBlank(argv.datasetPath)) {
505495
throw new ParameterException("fnDataPath or datasetPath can't be null");

0 commit comments

Comments
 (0)