Warrior_EA/Database/DatabaseManager.mqh
AnimateDread 78c8c76563 refactor(db): stop wrapping CDatabaseVersionManager's retry in a second retry loop
ReadStoredDbVersion() already retries the FileOpen 5x with a 1s sleep
internally (OpenVersionFileWithRetry, b8f936f) before returning the
"ERROR" sentinel. Init()'s outer while(attempts<5){Sleep;retry} wrapped
that whole sequence again, so sustained lock contention could block
OnInit for ~25-30s across two stacked retry loops that read as one.
Treat a single exhausted ERROR as a hard Init() failure instead.
2026-08-24 02:26:56 -04:00

203 lines
7.4 KiB
MQL5

//+------------------------------------------------------------------+
//| Warrior_EA |
//| AnimateDread |
//| |
//+------------------------------------------------------------------+
#include "DatabaseConnectionManager.mqh"
#include "DatabaseOperationsManager.mqh"
#include "DatabaseFileSystemManager.mqh"
#include "DatabaseVersionManager.mqh"
class CDatabaseManager
{
private:
string m_dbPath;
int m_databaseHandle;
bool m_isDatabaseOpen; // Tracks if the database is currently open
CDatabaseConnectionManager m_dbConnectionManager;
CDatabaseVersionManager m_dbVersionManager;
CDatabaseFileSystemManager m_dbFileSystemManager;
CDatabaseOperationsManager m_dbOperationsManager;
public:
CDatabaseManager()
{
m_isDatabaseOpen = false;
}
~CDatabaseManager()
{
CloseDatabase();
}
bool Init(const string& dbVersion, string& dirStructureArray[], const string& dbName)
{
string currentPath;
// Build the database folder path
for(int i = 0; i < ArraySize(dirStructureArray); ++i)
{
currentPath += (i == 0) ? dirStructureArray[i] : "\\" + dirStructureArray[i];
}
string dbFolderPath = currentPath;
string versionFilePath = dbFolderPath + "\\" + "DatabaseVersion";
m_dbPath = dbFolderPath + "\\" + dbName;
string storedDbVersion = m_dbVersionManager.ReadStoredDbVersion(versionFilePath);
// Handling when the stored database version is "NA"
if(storedDbVersion == "NA")
{
if(!m_dbFileSystemManager.CreateDirectory(dbFolderPath))
{
return false;
}
m_dbFileSystemManager.CleanDirectory(dbFolderPath);
m_dbVersionManager.UpdateStoredDbVersion(versionFilePath, dbVersion);
}
else
if(storedDbVersion == "ERROR")
{
// ReadStoredDbVersion() already retried the FileOpen 5x internally (1s sleep each) -
// a second wrapper loop here would just re-run that whole sequence again for no
// meaningfully better odds. Treat one exhausted "ERROR" as a hard Init() failure.
return false;
}
// If current version doesn't match the stored version (and it's not "NA" or "ERROR")
if(storedDbVersion != dbVersion && storedDbVersion != "")
{
m_dbFileSystemManager.CleanDirectory(dbFolderPath);
m_dbVersionManager.UpdateStoredDbVersion(versionFilePath, dbVersion);
}
// Attempt to initialize the database connection
if(!m_dbConnectionManager.Init(m_dbPath))
{
return false;
}
return true;
}
bool Deinit()
{
m_dbConnectionManager.TransactionCommit();
m_dbConnectionManager.CloseDatabase();
return(true);
}
bool OpenDatabase()
{
// Check if the database is already open
if(m_isDatabaseOpen)
{
// Database is already open, no need to open it again
PrintVerbose("Database already open.");
return true;
}
if(m_dbConnectionManager.OpenDatabase())
{
m_databaseHandle = m_dbConnectionManager.GetDatabaseHandle();
m_dbOperationsManager.SetDatabaseHandle(m_databaseHandle);
m_isDatabaseOpen = true; // Update the state to reflect that the database is now open
return true;
}
else
return false;
}
bool CloseDatabase()
{
if(m_dbConnectionManager.CloseDatabase())
{
m_databaseHandle = 0; // Reset database handle
m_dbOperationsManager.SetDatabaseHandle(m_databaseHandle);
m_isDatabaseOpen = false; // Update the state to reflect that the database is now closed
return true;
}
else
return false;
}
bool BeginTransaction()
{
if(!m_isDatabaseOpen)
{
if(!OpenDatabase())
return false;
}
return m_dbConnectionManager.TransactionBegin();
}
bool CommitTransaction()
{
return m_dbConnectionManager.TransactionCommit();
}
bool RollbackTransaction()
{
return m_dbConnectionManager.TransactionRollback();
}
bool CreateTable(string tableName, string tableSchema)
{
return m_dbOperationsManager.CreateTable(tableName, tableSchema);
}
bool DeleteTable(string tableName)
{
return m_dbOperationsManager.DeleteTable(tableName);
}
bool InsertTradeRecord(string tableName, const string &columns[], const string &values[])
{
return m_dbOperationsManager.InsertTradeRecord(tableName, columns, values);
}
template <typename T>
bool FetchTradeRecords(string tableName, T &tradeRecordStructure, T &tradeRecords[])
{
return m_dbOperationsManager.FetchTradeRecords(tableName, tradeRecordStructure, tradeRecords);
}
bool FetchRecordCount(string tableName, int &count)
{
return m_dbOperationsManager.FetchRecordCount(tableName, count);
}
bool FetchOpenTradeEntry(string tableName, string pattern, string direction, double &entryPrice, bool &found)
{
return m_dbOperationsManager.FetchOpenTradeEntry(tableName, pattern, direction, entryPrice, found);
}
bool FetchNewestTimeKey(string tableName, long &key, bool &found, const bool quiet = false)
{
return m_dbOperationsManager.FetchNewestTimeKey(tableName, key, found, quiet);
}
bool FetchWinLossCounts(string tableName, long beforeKey, int &wins, int &losses)
{
return m_dbOperationsManager.FetchWinLossCounts(tableName, beforeKey, wins, losses);
}
bool UpdateTradeRecord(string tableName, const string &columns[], const string &values[], string pattern, string direction)
{
return m_dbOperationsManager.UpdateTradeRecord(tableName, columns, values, pattern, direction);
}
bool DeleteOldestEntry(string tableName)
{
return m_dbOperationsManager.DeleteOldestEntry(tableName);
}
//--- Panel "Reset" button equivalent for the pattern-confidence DB (was previously only reachable
//--- headless via the trainingMode input at Init() time). Closes the connection if open, deletes the
//--- DB file, and reopens - the next UpdateSignalsWeights() pass recreates tables lazily (CreateTable
//--- is IF-NOT-EXISTS), so no explicit re-init is needed here.
bool ResetDatabase()
{
bool wasOpen = m_isDatabaseOpen;
if(wasOpen)
CloseDatabase();
ResetLastError();
if(!m_dbFileSystemManager.DeleteFile(m_dbPath) && GetLastError() != 5002) // 5002: file does not exist
Print(__FUNCTION__ + ": failed to delete " + m_dbPath + ", error " + IntegerToString(GetLastError()));
return wasOpen ? OpenDatabase() : true;
}
};
//+------------------------------------------------------------------+