From a44d17b19c5521ea4fa10e8e1ab1bd7ca5c71406 Mon Sep 17 00:00:00 2001 From: guoquanwu Date: Fri, 26 Jan 2024 14:36:28 +0800 Subject: [PATCH] fix(LiteTool): fix data inconsistency of snapshot generation in the crash scenario --- .../main/java/org/tron/plugins/DbLite.java | 68 ++++++++----------- 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/plugins/src/main/java/org/tron/plugins/DbLite.java b/plugins/src/main/java/org/tron/plugins/DbLite.java index 732d4913021..88571de02cb 100644 --- a/plugins/src/main/java/org/tron/plugins/DbLite.java +++ b/plugins/src/main/java/org/tron/plugins/DbLite.java @@ -13,6 +13,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; @@ -353,28 +354,12 @@ private void generateInfoProperties(String propertyfile, long num) } private long getLatestBlockHeaderNum(String databaseDir) throws IOException, RocksDBException { - // query latest_block_header_number from checkpoint first - final String latestBlockHeaderNumber = "latest_block_header_number"; - DBInterface checkpointDb = getCheckpointDb(databaseDir); - Long blockNumber = getLatestBlockHeaderNumFromCP(checkpointDb, - latestBlockHeaderNumber.getBytes()); - if (blockNumber != null) { - return blockNumber; - } - // query from propertiesDb if checkpoint not contains latest_block_header_number - DBInterface propertiesDb = DbTool.getDB(databaseDir, PROPERTIES_DB_NAME); - return Optional.ofNullable(propertiesDb.get(ByteArray.fromString(latestBlockHeaderNumber))) - .map(ByteArray::toLong) - .orElseThrow( - () -> new IllegalArgumentException("not found latest block header number")); - } - - private Long getLatestBlockHeaderNumFromCP(DBInterface db, byte[] key) { - byte[] value = db.get(Bytes.concat(simpleEncode(PROPERTIES_DB_NAME), key)); - if (value != null && value.length > 1) { - return ByteArray.toLong(Arrays.copyOfRange(value, 1, value.length)); - } - return null; + final byte[] latestBlockHeaderNumber = "latest_block_header_number".getBytes(); + byte[] value = getDataFromSourceDB(databaseDir, PROPERTIES_DB_NAME, latestBlockHeaderNumber); + return Optional.ofNullable(value) + .map(ByteArray::toLong) + .orElseThrow( + () -> new IllegalArgumentException("not found latest block header number")); } /** @@ -585,16 +570,30 @@ private void mergeBak2Database(String liteDir, BlockNumInfo blockNumInfo) throws private byte[] getDataFromSourceDB(String sourceDir, String dbName, byte[] key) throws IOException, RocksDBException { + byte[] keyInCp = Bytes.concat(simpleEncode(dbName), key); + byte[] valueInCp = null; DBInterface sourceDb = DbTool.getDB(sourceDir, dbName); - DBInterface checkpointDb = getCheckpointDb(sourceDir); - // get data from tmp first. - byte[] valueFromTmp = checkpointDb.get(Bytes.concat(simpleEncode(dbName), key)); + // get data from checkpoint first. + List cpList = getCheckpointV2List(sourceDir); + if (cpList.size() > 0) { + // reverse iteration + Collections.reverse(cpList); + for (String cp: cpList) { + valueInCp = DbTool.getDB( + sourceDir + "/" + DBUtils.CHECKPOINT_DB_V2, cp).get(keyInCp); + if (!isEmptyBytes(valueInCp)) { + break; + } + } + } else { + valueInCp = DbTool.getDB(sourceDir, CHECKPOINT_DB).get(keyInCp); + } byte[] value; - if (isEmptyBytes(valueFromTmp)) { + if (isEmptyBytes(valueInCp)) { value = sourceDb.get(key); } else { - value = valueFromTmp.length == 1 - ? null : Arrays.copyOfRange(valueFromTmp, 1, valueFromTmp.length); + value = DBUtils.Operator.DELETE.getValue() == valueInCp[0] + ? null : Arrays.copyOfRange(valueInCp, 1, valueInCp.length); } if (isEmptyBytes(value)) { throw new RuntimeException(String.format("data not found in store, dbName: %s, key: %s", @@ -664,19 +663,6 @@ private long getSecondBlock(String databaseDir) throws RocksDBException, IOExcep return num; } - private DBInterface getCheckpointDb(String sourceDir) throws IOException, RocksDBException { - List cpList = getCheckpointV2List(sourceDir); - DBInterface checkpointDb; - if (cpList.size() > 0) { - String latestCp = cpList.get(cpList.size() - 1); - checkpointDb = DbTool.getDB( - sourceDir + "/" + DBUtils.CHECKPOINT_DB_V2, latestCp); - } else { - checkpointDb = DbTool.getDB(sourceDir, CHECKPOINT_DB); - } - return checkpointDb; - } - @VisibleForTesting public static void setRecentBlks(long recentBlks) { RECENT_BLKS = recentBlks;