mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-06 01:45:38 +08:00
refs #687, further performance improvements
* avoid redundant reads by excluding entities which will be periodically updated * restart timers when data are received, avoid overlapping requests
This commit is contained in:
@@ -98,6 +98,15 @@ namespace BlackCore
|
||||
});
|
||||
}
|
||||
|
||||
void CThreadedReader::restartTimer(bool onlyWhenActive)
|
||||
{
|
||||
const int intervalMs(this->interval());
|
||||
if (!onlyWhenActive || this->isTimerActive())
|
||||
{
|
||||
this->setInterval(intervalMs);
|
||||
}
|
||||
}
|
||||
|
||||
bool CThreadedReader::didContentChange(const QString &content, int startPosition)
|
||||
{
|
||||
uint oldHash = 0;
|
||||
@@ -126,6 +135,12 @@ namespace BlackCore
|
||||
return this->m_updateTimer->interval();
|
||||
}
|
||||
|
||||
bool CThreadedReader::isTimerActive() const
|
||||
{
|
||||
QReadLocker rl(&this->m_lock);
|
||||
return this->m_updateTimer->isActive();
|
||||
}
|
||||
|
||||
void CThreadedReader::setIntervalFromSettingsAndStart()
|
||||
{
|
||||
this->setInitialTime();
|
||||
|
||||
@@ -59,6 +59,10 @@ namespace BlackCore
|
||||
//! \threadsafe
|
||||
int interval() const;
|
||||
|
||||
//! Is timer running
|
||||
//! \threadsafe
|
||||
bool isTimerActive() const;
|
||||
|
||||
//! Set inverval from settings and start
|
||||
void setIntervalFromSettingsAndStart();
|
||||
|
||||
@@ -68,7 +72,7 @@ namespace BlackCore
|
||||
void gracefulShutdown();
|
||||
|
||||
protected:
|
||||
QTimer *m_updateTimer = nullptr; //!< update timer
|
||||
QTimer *m_updateTimer = nullptr; //!< update timer
|
||||
mutable QReadWriteLock m_lock {QReadWriteLock::Recursive}; //!< lock which can be used from the derived classes
|
||||
|
||||
//! Constructor
|
||||
@@ -94,6 +98,10 @@ namespace BlackCore
|
||||
//! \threadsafe
|
||||
void setInterval(int updatePeriodMs);
|
||||
|
||||
//! Restart timer
|
||||
//! \threadsafe
|
||||
void restartTimer(bool onlyWhenActive = false);
|
||||
|
||||
//! Stores new content hash and returns if content changed (based on hash value
|
||||
//! \threadsafe
|
||||
bool didContentChange(const QString &content, int startPosition = -1);
|
||||
|
||||
@@ -68,10 +68,11 @@ namespace BlackCore
|
||||
void CVatsimBookingReader::ps_read()
|
||||
{
|
||||
this->threadAssertCheck();
|
||||
this->restartTimer(true); // when timer active, restart so we cause no undesired reads
|
||||
|
||||
Q_ASSERT_X(sApp, Q_FUNC_INFO, "No application");
|
||||
const QUrl url(sApp->getGlobalSetup().getVatsimBookingsUrl());
|
||||
if (url.isEmpty()) { return; }
|
||||
|
||||
sApp->getFromNetwork(url, { this, &CVatsimBookingReader::ps_parseBookings});
|
||||
}
|
||||
|
||||
@@ -114,10 +115,11 @@ namespace BlackCore
|
||||
if (this->getUpdateTimestamp() == updateTimestamp) return; // nothing to do
|
||||
|
||||
// save parsing and all follow up actions if nothing changed
|
||||
this->restartTimer(); // do not consider time for reading
|
||||
bool changed = this->didContentChange(xmlData, xmlData.indexOf("</timestamp>"));
|
||||
if (!changed)
|
||||
{
|
||||
CLogMessage(this).info("Bookings unchanged, skipped");
|
||||
CLogMessage(this).info("Read bookings unchanged, skipped");
|
||||
return; // stop, terminate straight away, ending thread
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,6 +187,7 @@ namespace BlackCore
|
||||
void CVatsimDataFileReader::ps_read()
|
||||
{
|
||||
this->threadAssertCheck();
|
||||
this->restartTimer(true); // when timer active, restart so we cause no undesired reads
|
||||
|
||||
// round robin for load balancing
|
||||
// remark: Don't use QThread to run network operations in the background
|
||||
@@ -196,7 +197,6 @@ namespace BlackCore
|
||||
const QUrl url(urls.obtainNextWorkingUrl(true));
|
||||
if (url.isEmpty()) { return; }
|
||||
sApp->getFromNetwork(url, { this, &CVatsimDataFileReader::ps_parseVatsimFile});
|
||||
|
||||
}
|
||||
|
||||
void CVatsimDataFileReader::ps_parseVatsimFile(QNetworkReply *nwReplyPtr)
|
||||
@@ -222,8 +222,8 @@ namespace BlackCore
|
||||
nwReply->close(); // close asap
|
||||
|
||||
if (dataFileData.isEmpty()) { return; }
|
||||
// Quick check by hash
|
||||
if (!this->didContentChange(dataFileData))
|
||||
this->restartTimer(); // do not consider time for reading
|
||||
if (!this->didContentChange(dataFileData)) // Quick check by hash
|
||||
{
|
||||
CLogMessage(this).info("VATSIM file has same content, skipped");
|
||||
return;
|
||||
|
||||
@@ -82,6 +82,8 @@ namespace BlackCore
|
||||
void CVatsimMetarReader::ps_readMetars()
|
||||
{
|
||||
this->threadAssertCheck();
|
||||
this->restartTimer(true); // when timer active, restart so we cause no undesired reads
|
||||
|
||||
CFailoverUrlList urls(sApp->getVatsimMetarUrls());
|
||||
const CUrl url(urls.obtainNextWorkingUrl(true));
|
||||
if (url.isEmpty()) { return; }
|
||||
@@ -110,8 +112,8 @@ namespace BlackCore
|
||||
QString metarData = nwReply->readAll();
|
||||
nwReply->close(); // close asap
|
||||
|
||||
// Quick check by hash
|
||||
if (!this->didContentChange(metarData))
|
||||
this->restartTimer(); // do not consider time for reading
|
||||
if (!this->didContentChange(metarData)) // Quick check by hash
|
||||
{
|
||||
CLogMessage(this).info("METAR file has same content, skipped");
|
||||
return;
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace BlackCore
|
||||
const bool readFromSwiftDb = dbReaderConfig.possiblyReadsFromSwiftDb(); // only cached?
|
||||
if (!readFromSwiftDb && readers.testFlag(CWebReaderFlags::InfoDataReader))
|
||||
{
|
||||
// will remove info reader becaue not needed
|
||||
// will remove info reader because not needed
|
||||
readers &= ~CWebReaderFlags::InfoDataReader;
|
||||
this->m_readers = readers;
|
||||
CLogMessage(this).info("Remove info object reader because not needed");
|
||||
@@ -72,7 +72,7 @@ namespace BlackCore
|
||||
if (entities.testFlag(CEntityFlags::InfoObjectEntity))
|
||||
{
|
||||
Q_ASSERT_X(readers.testFlag(CWebReaderFlags::InfoDataReader), Q_FUNC_INFO, "info object but no reader");
|
||||
CLogMessage(this).info("Using info objects for swift DB objects");
|
||||
CLogMessage(this).info("Using info objects for swift DB entities");
|
||||
}
|
||||
|
||||
this->initReaders(readers); // reads info object if required
|
||||
@@ -80,7 +80,9 @@ namespace BlackCore
|
||||
|
||||
// make sure this is called in event queue, so pending tasks cam be performed
|
||||
// important so info objects can be read
|
||||
entities &= ~CEntityFlags::InfoObjectEntity;
|
||||
entities &= ~CEntityFlags::InfoObjectEntity; // triggered in init readers
|
||||
entities &= ~CEntityFlags::VatsimStatusFile; // triggered in init readers
|
||||
entities &= ~this->m_entitiesPeriodicallyRead; // will be triggered by timers
|
||||
this->singleShotReadInBackground(entities, 1000);
|
||||
}
|
||||
|
||||
@@ -440,10 +442,9 @@ namespace BlackCore
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "ICAO info object signals");
|
||||
c = connect(this->m_infoDataReader, &CInfoDataReader::dataRead, this, &CWebDataServices::dataRead);
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "connect failed info data");
|
||||
this->m_infoDataReader->start(QThread::LowPriority);
|
||||
|
||||
// info data reader has a special role, it will not be triggered in triggerRead()
|
||||
this->m_infoDataReader->start(QThread::LowPriority);
|
||||
// directly call read
|
||||
QTimer::singleShot(0, [this]() { this->m_infoDataReader->read(CEntityFlags::InfoObjectEntity, QDateTime()); });
|
||||
}
|
||||
|
||||
@@ -466,6 +467,7 @@ namespace BlackCore
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "VATSIM booking reader signals");
|
||||
c = connect(this->m_vatsimBookingReader, &CVatsimBookingReader::dataRead, this, &CWebDataServices::dataRead);
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "connect failed bookings");
|
||||
this->m_entitiesPeriodicallyRead |= CEntityFlags::BookingEntity;
|
||||
this->m_vatsimBookingReader->start(QThread::LowPriority);
|
||||
this->m_vatsimBookingReader->setIntervalFromSettingsAndStart();
|
||||
}
|
||||
@@ -478,6 +480,7 @@ namespace BlackCore
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "VATSIM data reader signals");
|
||||
c = connect(this->m_vatsimDataFileReader, &CVatsimDataFileReader::dataRead, this, &CWebDataServices::dataRead);
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "connect failed VATSIM data file");
|
||||
this->m_entitiesPeriodicallyRead |= CEntityFlags::VatsimDataFile;
|
||||
this->m_vatsimDataFileReader->start(QThread::LowPriority);
|
||||
this->m_vatsimDataFileReader->setIntervalFromSettingsAndStart();
|
||||
}
|
||||
@@ -490,6 +493,7 @@ namespace BlackCore
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "VATSIM METAR reader signals");
|
||||
c = connect(this->m_vatsimMetarReader, &CVatsimMetarReader::dataRead, this, &CWebDataServices::dataRead);
|
||||
Q_ASSERT_X(c, Q_FUNC_INFO, "connect failed VATSIM METAR");
|
||||
this->m_entitiesPeriodicallyRead |= CEntityFlags::MetarEntity;
|
||||
this->m_vatsimMetarReader->start(QThread::LowPriority);
|
||||
this->m_vatsimMetarReader->setIntervalFromSettingsAndStart();
|
||||
}
|
||||
|
||||
@@ -325,6 +325,7 @@ namespace BlackCore
|
||||
|
||||
CWebReaderFlags::WebReader m_readers = CWebReaderFlags::WebReaderFlag::None; //!< which readers are available
|
||||
BlackCore::Db::CDatabaseReaderConfigList m_dbReaderConfig; //!< how to read DB data
|
||||
BlackMisc::Network::CEntityFlags::Entity m_entitiesPeriodicallyRead = BlackMisc::Network::CEntityFlags::NoEntity; //!< those entities which are permanently updated by timers
|
||||
bool m_initialRead = false; //!< Initial read started
|
||||
int m_infoObjectTrials = 0; //!< Tried to read info objects
|
||||
|
||||
|
||||
Reference in New Issue
Block a user