Skip to content

fix(db/trans-cache): avoid recovering a wrong cached data #5505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.tron.core.capsule.BytesCapsule;
import org.tron.core.db2.common.TxCacheDB;
import org.tron.core.store.DynamicPropertiesStore;

@Slf4j
@Component
public class TransactionCache extends TronStoreWithRevoking<BytesCapsule> {

@Autowired
public TransactionCache(@Value("trans-cache") String dbName,
RecentTransactionStore recentTransactionStore) {
super(new TxCacheDB(dbName, recentTransactionStore));
@Autowired RecentTransactionStore recentTransactionStore,
@Autowired DynamicPropertiesStore dynamicPropertiesStore) {
super(new TxCacheDB(dbName, recentTransactionStore, dynamicPropertiesStore));
}

public void initCache() {
Expand Down
20 changes: 15 additions & 5 deletions chainbase/src/main/java/org/tron/core/db2/common/TxCacheDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.tron.core.db.RecentTransactionItem;
import org.tron.core.db.RecentTransactionStore;
import org.tron.core.db.common.iterator.DBIterator;
import org.tron.core.store.DynamicPropertiesStore;

@Slf4j(topic = "DB")
public class TxCacheDB implements DB<byte[], byte[]>, Flusher {
Expand All @@ -59,7 +60,6 @@ public class TxCacheDB implements DB<byte[], byte[]>, Flusher {
private BloomFilter<byte[]>[] bloomFilters = new BloomFilter[2];
// filterStartBlock record the start block of the active filter
private volatile long filterStartBlock = INVALID_BLOCK;
private volatile long currentBlockNum = INVALID_BLOCK;
// currentFilterIndex records the index of the active filter
private volatile int currentFilterIndex = 0;

Expand All @@ -75,6 +75,8 @@ public class TxCacheDB implements DB<byte[], byte[]>, Flusher {
// replace persistentStore and optimizes startup performance
private RecentTransactionStore recentTransactionStore;

private DynamicPropertiesStore dynamicPropertiesStore;

private final Path cacheFile0;
private final Path cacheFile1;
private final Path cacheProperties;
Expand All @@ -85,11 +87,13 @@ public class TxCacheDB implements DB<byte[], byte[]>, Flusher {
@Setter
private volatile boolean alive;

public TxCacheDB(String name, RecentTransactionStore recentTransactionStore) {
public TxCacheDB(String name, RecentTransactionStore recentTransactionStore,
DynamicPropertiesStore dynamicPropertiesStore) {
this.name = name;
this.TRANSACTION_COUNT =
CommonParameter.getInstance().getStorage().getEstimatedBlockTransactions();
this.recentTransactionStore = recentTransactionStore;
this.dynamicPropertiesStore = dynamicPropertiesStore;
String dbEngine = CommonParameter.getInstance().getStorage().getDbEngine();
if ("LEVELDB".equals(dbEngine.toUpperCase())) {
this.persistentStore = new LevelDB(
Expand Down Expand Up @@ -211,7 +215,6 @@ public void put(byte[] key, byte[] value) {
MAX_BLOCK_SIZE * TRANSACTION_COUNT);
}
bloomFilters[currentFilterIndex].put(key);
currentBlockNum = blockNum;
if (lastMetricBlock != blockNum) {
lastMetricBlock = blockNum;
Metrics.gaugeSet(MetricKeys.Gauge.TX_CACHE,
Expand Down Expand Up @@ -356,8 +359,14 @@ private boolean loadProperties() {
Properties properties = new Properties();
properties.load(r);
filterStartBlock = Long.parseLong(properties.getProperty("filterStartBlock"));
currentBlockNum = Long.parseLong(properties.getProperty("currentBlockNum"));
long currentBlockNum = Long.parseLong(properties.getProperty("currentBlockNum"));
long currentBlockNumFromDB = dynamicPropertiesStore.getLatestBlockHeaderNumberFromDB();
currentFilterIndex = Integer.parseInt(properties.getProperty("currentFilterIndex"));
if (currentBlockNum != currentBlockNumFromDB) {
throw new IllegalStateException(
String.format("currentBlockNum not match. filter: %d, db: %d",
currentBlockNum, currentBlockNumFromDB));
}
logger.info("filterStartBlock: {}, currentBlockNum: {}, currentFilterIndex: {}, load done.",
filterStartBlock, currentBlockNum, currentFilterIndex);
return true;
Expand All @@ -369,6 +378,7 @@ private boolean loadProperties() {
private void writeProperties() {
try (Writer w = Files.newBufferedWriter(this.cacheProperties, StandardCharsets.UTF_8)) {
Properties properties = new Properties();
long currentBlockNum = dynamicPropertiesStore.getLatestBlockHeaderNumberFromDB();
properties.setProperty("filterStartBlock", String.valueOf(filterStartBlock));
properties.setProperty("currentBlockNum", String.valueOf(currentBlockNum));
properties.setProperty("currentFilterIndex", String.valueOf(currentFilterIndex));
Expand All @@ -382,7 +392,7 @@ private void writeProperties() {

@Override
public TxCacheDB newInstance() {
return new TxCacheDB(name, recentTransactionStore);
return new TxCacheDB(name, recentTransactionStore, dynamicPropertiesStore);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@
import org.springframework.context.annotation.Import;
import org.tron.common.utils.StorageUtils;
import org.tron.core.config.args.Args;
import org.tron.core.db.RecentTransactionStore;
import org.tron.core.db.RevokingDatabase;
import org.tron.core.db.TransactionCache;
import org.tron.core.db.backup.BackupRocksDBAspect;
import org.tron.core.db.backup.NeedBeanCondition;
import org.tron.core.db2.core.SnapshotManager;
Expand Down Expand Up @@ -93,11 +91,6 @@ public HttpApiOnPBFTService getHttpApiOnPBFTService() {
return null;
}

@Bean
public TransactionCache transactionCache() {
return new TransactionCache("trans-cache", appCtx.getBean(RecentTransactionStore.class));
}

@Bean
@Conditional(NeedBeanCondition.class)
public BackupRocksDBAspect backupRocksDBAspect() {
Expand Down
2 changes: 1 addition & 1 deletion framework/src/main/java/org/tron/core/db/Manager.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ public class Manager {
@Setter
public boolean eventPluginLoaded = false;
private int maxTransactionPendingSize = Args.getInstance().getMaxTransactionPendingSize();
@Autowired(required = false)
@Getter
@Autowired
private TransactionCache transactionCache;
@Autowired
private KhaosDatabase khaosDb;
Expand Down
20 changes: 16 additions & 4 deletions framework/src/test/java/org/tron/core/db/TxCacheDBInitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.tron.core.capsule.BytesCapsule;
import org.tron.core.config.DefaultConfig;
import org.tron.core.config.args.Args;
import org.tron.core.store.DynamicPropertiesStore;
import org.tron.keystore.Wallet;

@Slf4j
Expand Down Expand Up @@ -53,11 +54,22 @@ public void reload() {
queryTransaction();
db.close();
defaultListableBeanFactory.destroySingleton("transactionCache");
TransactionCache transactionCache = new TransactionCache("transactionCache",
context.getBean(RecentTransactionStore.class));
transactionCache.initCache();
defaultListableBeanFactory.registerSingleton("transactionCache",transactionCache);
db = new TransactionCache("transactionCache",
context.getBean(RecentTransactionStore.class),
context.getBean(DynamicPropertiesStore.class));
db.initCache();
defaultListableBeanFactory.registerSingleton("transactionCache",db);
queryTransaction();
db.close();
defaultListableBeanFactory.destroySingleton("transactionCache");
db = new TransactionCache("transactionCache",
context.getBean(RecentTransactionStore.class),
context.getBean(DynamicPropertiesStore.class));
DynamicPropertiesStore dynamicPropertiesStore = context.getBean(DynamicPropertiesStore.class);
dynamicPropertiesStore.saveLatestBlockHeaderNumber(1);
defaultListableBeanFactory.registerSingleton("transactionCache",db);
db.initCache();
Assert.assertFalse(db.has(hash[65538]));
}

private void putTransaction() {
Expand Down