Optimized transaction importing by using a temporary cache of unconfirmed transactions.

This commit is contained in:
CalDescent 2023-08-12 11:14:21 +01:00
parent d9147b3af3
commit 897c44ffe8
2 changed files with 17 additions and 1 deletions

View File

@ -47,6 +47,9 @@ public class TransactionImporter extends Thread {
/** Map of recent invalid unconfirmed transactions. Key is base58 transaction signature, value is do-not-request expiry timestamp. */ /** Map of recent invalid unconfirmed transactions. Key is base58 transaction signature, value is do-not-request expiry timestamp. */
private final Map<String, Long> invalidUnconfirmedTransactions = Collections.synchronizedMap(new HashMap<>()); private final Map<String, Long> invalidUnconfirmedTransactions = Collections.synchronizedMap(new HashMap<>());
/** Cached list of unconfirmed transactions, used when counting per creator. This is replaced regularly */
public static List<TransactionData> unconfirmedTransactionsCache = null;
public static synchronized TransactionImporter getInstance() { public static synchronized TransactionImporter getInstance() {
if (instance == null) { if (instance == null) {
@ -254,6 +257,12 @@ public class TransactionImporter extends Thread {
int processedCount = 0; int processedCount = 0;
try (final Repository repository = RepositoryManager.getRepository()) { try (final Repository repository = RepositoryManager.getRepository()) {
// Use a single copy of the unconfirmed transactions list for each cycle, to speed up constant lookups
// when counting unconfirmed transactions by creator.
List<TransactionData> unconfirmedTransactions = repository.getTransactionRepository().getUnconfirmedTransactions();
unconfirmedTransactions.removeIf(t -> t.getType() == Transaction.TransactionType.CHAT);
unconfirmedTransactionsCache = unconfirmedTransactions;
// Import transactions with valid signatures // Import transactions with valid signatures
try { try {
for (int i = 0; i < sigValidTransactions.size(); ++i) { for (int i = 0; i < sigValidTransactions.size(); ++i) {
@ -317,6 +326,9 @@ public class TransactionImporter extends Thread {
} finally { } finally {
LOGGER.debug("Finished importing {} incoming transaction{}", processedCount, (processedCount == 1 ? "" : "s")); LOGGER.debug("Finished importing {} incoming transaction{}", processedCount, (processedCount == 1 ? "" : "s"));
blockchainLock.unlock(); blockchainLock.unlock();
// Clear the unconfirmed transaction cache so new data can be populated in the next cycle
unconfirmedTransactionsCache = null;
} }
} catch (DataException e) { } catch (DataException e) {
LOGGER.error("Repository issue while importing incoming transactions", e); LOGGER.error("Repository issue while importing incoming transactions", e);

View File

@ -13,6 +13,7 @@ import org.qortal.account.PublicKeyAccount;
import org.qortal.asset.Asset; import org.qortal.asset.Asset;
import org.qortal.block.BlockChain; import org.qortal.block.BlockChain;
import org.qortal.controller.Controller; import org.qortal.controller.Controller;
import org.qortal.controller.TransactionImporter;
import org.qortal.crypto.Crypto; import org.qortal.crypto.Crypto;
import org.qortal.data.block.BlockData; import org.qortal.data.block.BlockData;
import org.qortal.data.group.GroupApprovalData; import org.qortal.data.group.GroupApprovalData;
@ -617,7 +618,10 @@ public abstract class Transaction {
} }
private int countUnconfirmedByCreator(PublicKeyAccount creator) throws DataException { private int countUnconfirmedByCreator(PublicKeyAccount creator) throws DataException {
List<TransactionData> unconfirmedTransactions = repository.getTransactionRepository().getUnconfirmedTransactions(); List<TransactionData> unconfirmedTransactions = TransactionImporter.getInstance().unconfirmedTransactionsCache;
if (unconfirmedTransactions == null) {
unconfirmedTransactions = repository.getTransactionRepository().getUnconfirmedTransactions();
}
// We exclude CHAT transactions as they never get included into blocks and // We exclude CHAT transactions as they never get included into blocks and
// have spam/DoS prevention by requiring proof of work // have spam/DoS prevention by requiring proof of work