Improve startup performance, shutdown reliability, and Qt5 compatibility
- Defer SecureMsgStart and ReacceptWalletTransactions to background thread so GUI appears faster during startup - Add shutdown checks in wallet scan/reaccept to prevent hanging on exit - Smart wallet rescan: start from wallet birthday instead of genesis block - Raise default dbcache from 25 to 128 MB for better performance - Replace deprecated QDesktopServices with QStandardPaths (Qt5 compat) - Enforce Qt5+ requirement in build system, remove -fpermissive flag Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-2
@@ -79,7 +79,7 @@ bool CDBEnv::Open(fs::path pathEnv_)
|
||||
if (GetBoolArg("-privdb", true))
|
||||
nEnvFlags |= DB_PRIVATE;
|
||||
|
||||
int nDbCache = GetArg("-dbcache", 25);
|
||||
int nDbCache = GetArg("-dbcache", 128);
|
||||
dbenv.set_lg_dir(pathLogDir.string().c_str());
|
||||
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
|
||||
dbenv.set_lg_bsize(1048576);
|
||||
@@ -593,4 +593,3 @@ bool CAddrDB::Read(CAddrMan& addr)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+66
-10
@@ -38,6 +38,9 @@ unsigned int nDerivationMethodIndex;
|
||||
bool fUseFastIndex;
|
||||
enum Checkpoints::CPMode CheckpointsMode;
|
||||
|
||||
static CCriticalSection cs_DeferredStartup;
|
||||
static bool fDeferredStartupRunning = false;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Shutdown
|
||||
@@ -69,6 +72,46 @@ bool ShutdownRequested()
|
||||
return fRequestShutdown;
|
||||
}
|
||||
|
||||
void ThreadDeferredStartup(void* parg)
|
||||
{
|
||||
// Make this thread recognisable as the deferred startup worker.
|
||||
RenameThread("Triangles-postinit");
|
||||
|
||||
int64_t nTotalStart = GetTimeMillis();
|
||||
printf("Starting deferred startup tasks...\n");
|
||||
try
|
||||
{
|
||||
if (!fShutdown)
|
||||
{
|
||||
int64_t nStart = GetTimeMillis();
|
||||
SecureMsgStart(fNoSmsg, GetBoolArg("-smsgscanchain"));
|
||||
printf(" securemsg %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
if (!fShutdown && pwalletMain)
|
||||
{
|
||||
int64_t nStart = GetTimeMillis();
|
||||
pwalletMain->ReacceptWalletTransactions();
|
||||
printf(" reaccept %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
printf("Deferred startup tasks finished %"PRId64"ms\n", GetTimeMillis() - nTotalStart);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
PrintExceptionContinue(&e, "ThreadDeferredStartup()");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
PrintExceptionContinue(NULL, "ThreadDeferredStartup()");
|
||||
}
|
||||
|
||||
{
|
||||
LOCK(cs_DeferredStartup);
|
||||
fDeferredStartupRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Shutdown(void* parg)
|
||||
{
|
||||
static CCriticalSection cs_Shutdown;
|
||||
@@ -90,7 +133,19 @@ void Shutdown(void* parg)
|
||||
if (fFirstThread)
|
||||
{
|
||||
fShutdown = true;
|
||||
|
||||
int64_t nDeferredWaitStart = GetTimeMillis();
|
||||
while (true)
|
||||
{
|
||||
bool fDeferredRunning;
|
||||
{
|
||||
LOCK(cs_DeferredStartup);
|
||||
fDeferredRunning = fDeferredStartupRunning;
|
||||
}
|
||||
if (!fDeferredRunning || GetTimeMillis() - nDeferredWaitStart > 5000)
|
||||
break;
|
||||
MilliSleep(50);
|
||||
}
|
||||
|
||||
SecureMsgShutdown();
|
||||
|
||||
nTransactionsUpdated++;
|
||||
@@ -921,10 +976,6 @@ bool AppInit2()
|
||||
addrman.size(), GetTimeMillis() - nStart);
|
||||
|
||||
|
||||
// ********************************************************* Step 10.1: startup secure messaging
|
||||
|
||||
SecureMsgStart(fNoSmsg, GetBoolArg("-smsgscanchain"));
|
||||
|
||||
// ********************************************************* Step 11: start node
|
||||
|
||||
if (!CheckDiskSpace())
|
||||
@@ -945,6 +996,16 @@ bool AppInit2()
|
||||
if (fServer)
|
||||
NewThread(ThreadRPCServer, NULL);
|
||||
|
||||
{
|
||||
LOCK(cs_DeferredStartup);
|
||||
fDeferredStartupRunning = true;
|
||||
}
|
||||
if (!NewThread(ThreadDeferredStartup, NULL))
|
||||
{
|
||||
printf("Warning: deferred startup thread could not be started, running inline\n");
|
||||
ThreadDeferredStartup(NULL);
|
||||
}
|
||||
|
||||
// ********************************************************* Step 12: finished
|
||||
|
||||
uiInterface.InitMessage(_("Done loading"));
|
||||
@@ -953,9 +1014,6 @@ bool AppInit2()
|
||||
if (!strErrors.str().empty())
|
||||
return InitError(strErrors.str());
|
||||
|
||||
// Add wallet transactions that aren't already in a block to mapTransactions
|
||||
pwalletMain->ReacceptWalletTransactions();
|
||||
|
||||
#if !defined(QT_GUI)
|
||||
// Loop until process is exit()ed from shutdown() function,
|
||||
// called from ThreadRPCServer thread when a "stop" command is received.
|
||||
@@ -965,5 +1023,3 @@ bool AppInit2()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QStandardPaths>
|
||||
#include <QThread>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -172,7 +172,7 @@ QString getSaveFileName(QWidget *parent, const QString &caption,
|
||||
QString myDir;
|
||||
if(dir.isEmpty()) // Default to user documents location
|
||||
{
|
||||
myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
|
||||
myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QMovie>
|
||||
#include <QFileDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QStandardPaths>
|
||||
#include <QTimer>
|
||||
#include <QDragEnterEvent>
|
||||
#if QT_VERSION < 0x050000
|
||||
@@ -1368,7 +1368,7 @@ void TrianglesGUI::encryptWallet(bool status)
|
||||
|
||||
void TrianglesGUI::backupWallet()
|
||||
{
|
||||
QString saveDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
|
||||
QString saveDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
QString filename = QFileDialog::getSaveFileName(this, tr("Backup Wallet"), saveDir, tr("Wallet Data (*.dat)"));
|
||||
if(!filename.isEmpty()) {
|
||||
if(!walletModel->backupWallet(filename)) {
|
||||
|
||||
@@ -28,7 +28,7 @@ leveldb::DB *txdb; // global pointer for LevelDB object instance
|
||||
|
||||
static leveldb::Options GetOptions() {
|
||||
leveldb::Options options;
|
||||
int nCacheSizeMB = GetArg("-dbcache", 25);
|
||||
int nCacheSizeMB = GetArg("-dbcache", 128);
|
||||
options.block_cache = leveldb::NewLRUCache(nCacheSizeMB * 1048576);
|
||||
options.filter_policy = leveldb::NewBloomFilterPolicy(10);
|
||||
return options;
|
||||
|
||||
+79
-33
@@ -33,6 +33,36 @@ struct CompareValueOnly
|
||||
}
|
||||
};
|
||||
|
||||
static CBlockIndex* GetWalletRescanStart(const CWallet& wallet)
|
||||
{
|
||||
CBlockIndex* pindexStart = pindexGenesisBlock;
|
||||
|
||||
if (wallet.fFileBacked)
|
||||
{
|
||||
CWalletDB walletdb(wallet.strWalletFile);
|
||||
CBlockLocator locator;
|
||||
if (walletdb.ReadBestBlock(locator))
|
||||
{
|
||||
CBlockIndex* pindexLocator = locator.GetBlockIndex();
|
||||
if (pindexLocator)
|
||||
pindexStart = pindexLocator;
|
||||
}
|
||||
}
|
||||
|
||||
if (wallet.nTimeFirstKey > 1 && pindexBest)
|
||||
{
|
||||
int64_t nTimeWindowStart = wallet.nTimeFirstKey - 7200;
|
||||
CBlockIndex* pindexBirthday = pindexBest;
|
||||
while (pindexBirthday->pprev && pindexBirthday->GetBlockTime() > nTimeWindowStart)
|
||||
pindexBirthday = pindexBirthday->pprev;
|
||||
|
||||
if (!pindexStart || pindexBirthday->nHeight < pindexStart->nHeight)
|
||||
pindexStart = pindexBirthday;
|
||||
}
|
||||
|
||||
return pindexStart ? pindexStart : pindexGenesisBlock;
|
||||
}
|
||||
|
||||
CPubKey CWallet::GenerateNewKey()
|
||||
{
|
||||
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
|
||||
@@ -875,6 +905,9 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
||||
LOCK(cs_wallet);
|
||||
while (pindex)
|
||||
{
|
||||
if (fShutdown)
|
||||
break;
|
||||
|
||||
// no need to read and scan block, if block was created before
|
||||
// our wallet birthday (as adjusted for block time variability)
|
||||
if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) {
|
||||
@@ -910,54 +943,67 @@ void CWallet::ReacceptWalletTransactions()
|
||||
bool fRepeat = true;
|
||||
while (fRepeat)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
if (fShutdown)
|
||||
break;
|
||||
|
||||
fRepeat = false;
|
||||
vector<CDiskTxPos> vMissingTx;
|
||||
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
|
||||
{
|
||||
CWalletTx& wtx = item.second;
|
||||
if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1)))
|
||||
continue;
|
||||
|
||||
CTxIndex txindex;
|
||||
bool fUpdated = false;
|
||||
if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
|
||||
LOCK(cs_wallet);
|
||||
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
|
||||
{
|
||||
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
|
||||
if (txindex.vSpent.size() != wtx.vout.size())
|
||||
{
|
||||
printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %"PRIszu" != wtx.vout.size() %"PRIszu"\n", txindex.vSpent.size(), wtx.vout.size());
|
||||
if (fShutdown)
|
||||
break;
|
||||
|
||||
CWalletTx& wtx = item.second;
|
||||
if ((wtx.IsCoinBase() && wtx.IsSpent(0)) || (wtx.IsCoinStake() && wtx.IsSpent(1)))
|
||||
continue;
|
||||
}
|
||||
for (unsigned int i = 0; i < txindex.vSpent.size(); i++)
|
||||
|
||||
CTxIndex txindex;
|
||||
bool fUpdated = false;
|
||||
if (txdb.ReadTxIndex(wtx.GetHash(), txindex))
|
||||
{
|
||||
if (wtx.IsSpent(i))
|
||||
continue;
|
||||
if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
|
||||
// Update fSpent if a tx got spent somewhere else by a copy of wallet.dat
|
||||
if (txindex.vSpent.size() != wtx.vout.size())
|
||||
{
|
||||
wtx.MarkSpent(i);
|
||||
fUpdated = true;
|
||||
vMissingTx.push_back(txindex.vSpent[i]);
|
||||
printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %"PRIszu" != wtx.vout.size() %"PRIszu"\n", txindex.vSpent.size(), wtx.vout.size());
|
||||
continue;
|
||||
}
|
||||
for (unsigned int i = 0; i < txindex.vSpent.size(); i++)
|
||||
{
|
||||
if (wtx.IsSpent(i))
|
||||
continue;
|
||||
if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
|
||||
{
|
||||
wtx.MarkSpent(i);
|
||||
fUpdated = true;
|
||||
vMissingTx.push_back(txindex.vSpent[i]);
|
||||
}
|
||||
}
|
||||
if (fUpdated)
|
||||
{
|
||||
printf("ReacceptWalletTransactions found spent coin %s SUM %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
|
||||
wtx.MarkDirty();
|
||||
wtx.WriteToDisk();
|
||||
}
|
||||
}
|
||||
if (fUpdated)
|
||||
else
|
||||
{
|
||||
printf("ReacceptWalletTransactions found spent coin %s SUM %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
|
||||
wtx.MarkDirty();
|
||||
wtx.WriteToDisk();
|
||||
// Re-accept any txes of ours that aren't already in a block
|
||||
if (!(wtx.IsCoinBase() || wtx.IsCoinStake()))
|
||||
wtx.AcceptWalletTransaction(txdb);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Re-accept any txes of ours that aren't already in a block
|
||||
if (!(wtx.IsCoinBase() || wtx.IsCoinStake()))
|
||||
wtx.AcceptWalletTransaction(txdb);
|
||||
}
|
||||
}
|
||||
if (!vMissingTx.empty())
|
||||
{
|
||||
// TODO: optimize this to scan just part of the block chain?
|
||||
if (ScanForWalletTransactions(pindexGenesisBlock))
|
||||
if (fShutdown)
|
||||
break;
|
||||
|
||||
CBlockIndex* pindexStart = GetWalletRescanStart(*this);
|
||||
if (pindexStart)
|
||||
printf("ReacceptWalletTransactions rescanning from block %d\n", pindexStart->nHeight);
|
||||
if (ScanForWalletTransactions(pindexStart))
|
||||
fRepeat = true; // Found missing transactions: re-do re-accept.
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -7,13 +7,13 @@ DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE BOOST_THREAD_PROV
|
||||
CONFIG += no_include_pwd
|
||||
CONFIG += thread
|
||||
|
||||
QMAKE_CXXFLAGS = -fpermissive
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
QT += widgets
|
||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
|
||||
lessThan(QT_MAJOR_VERSION, 5) {
|
||||
error(Triangles Qt requires Qt 5 or newer)
|
||||
}
|
||||
|
||||
QT += widgets
|
||||
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
|
||||
|
||||
# UNCOMMENT THIS SECTION TO BUILD ON WINDOWS
|
||||
# MSYS2 MinGW64 paths
|
||||
win32 {
|
||||
|
||||
Reference in New Issue
Block a user