Only reserialize hosts if a serializable attribute changed

This commit is contained in:
Cameron Gutman 2023-10-01 17:28:06 -05:00
parent facd6e4e56
commit 0976bc39b3
4 changed files with 64 additions and 9 deletions

View File

@ -167,6 +167,7 @@ ComputerManager::ComputerManager(QObject *parent)
settings.setArrayIndex(i); settings.setArrayIndex(i);
NvComputer* computer = new NvComputer(settings); NvComputer* computer = new NvComputer(settings);
m_KnownHosts[computer->uuid] = computer; m_KnownHosts[computer->uuid] = computer;
m_LastSerializedHosts[computer->uuid] = *computer;
} }
settings.endArray(); settings.endArray();
@ -250,6 +251,14 @@ void DelayedFlushThread::run() {
// Reset the delayed flush flag to ensure any racing saveHosts() call will set it again // Reset the delayed flush flag to ensure any racing saveHosts() call will set it again
m_ComputerManager->m_NeedsDelayedFlush = false; m_ComputerManager->m_NeedsDelayedFlush = false;
// Update the last serialized hosts map under the delayed flush mutex
m_ComputerManager->m_LastSerializedHosts.clear();
for (const NvComputer* computer : m_ComputerManager->m_KnownHosts) {
// Copy the current state of the NvComputer to allow us to check later if we need
// to serialize it again when attribute updates occur.
m_ComputerManager->m_LastSerializedHosts[computer->uuid] = *computer;
}
} }
// Perform the flush // Perform the flush
@ -433,6 +442,17 @@ void ComputerManager::handleMdnsServiceResolved(MdnsPendingComputer* computer,
computer->deleteLater(); computer->deleteLater();
} }
void ComputerManager::saveHost(NvComputer *computer)
{
// If no serializable properties changed, don't bother saving hosts
QMutexLocker lock(&m_DelayedFlushMutex);
if (!m_LastSerializedHosts.value(computer->uuid).isEqualSerialized(*computer)) {
// Queue a request for a delayed flush to QSettings outside of the lock
lock.unlock();
saveHosts();
}
}
void ComputerManager::handleComputerStateChanged(NvComputer* computer) void ComputerManager::handleComputerStateChanged(NvComputer* computer)
{ {
emit computerStateChanged(computer); emit computerStateChanged(computer);
@ -442,8 +462,8 @@ void ComputerManager::handleComputerStateChanged(NvComputer* computer)
emit quitAppCompleted(QVariant()); emit quitAppCompleted(QVariant());
} }
// Save updated hosts to QSettings // Save updates to this host
saveHosts(); saveHost(computer);
} }
QVector<NvComputer*> ComputerManager::getComputers() QVector<NvComputer*> ComputerManager::getComputers()
@ -479,7 +499,7 @@ public:
m_ComputerManager->m_KnownHosts.remove(m_Computer->uuid); m_ComputerManager->m_KnownHosts.remove(m_Computer->uuid);
} }
// Persist the new host list // Persist the new host list with this computer deleted
m_ComputerManager->saveHosts(); m_ComputerManager->saveHosts();
// Delete the polling entry first. This will stop all polling threads too. // Delete the polling entry first. This will stop all polling threads too.
@ -520,9 +540,6 @@ void ComputerManager::renameHost(NvComputer* computer, QString name)
void ComputerManager::clientSideAttributeUpdated(NvComputer* computer) void ComputerManager::clientSideAttributeUpdated(NvComputer* computer)
{ {
// Persist the change
saveHosts();
// Notify the UI of the state change // Notify the UI of the state change
handleComputerStateChanged(computer); handleComputerStateChanged(computer);
} }
@ -580,7 +597,7 @@ private:
break; break;
case NvPairingManager::PairState::PAIRED: case NvPairingManager::PairState::PAIRED:
// Persist the newly pinned server certificate for this host // Persist the newly pinned server certificate for this host
m_ComputerManager->saveHosts(); m_ComputerManager->saveHost(m_Computer);
emit pairingCompleted(m_Computer, nullptr); emit pairingCompleted(m_Computer, nullptr);
break; break;

View File

@ -251,6 +251,8 @@ private slots:
private: private:
void saveHosts(); void saveHosts();
void saveHost(NvComputer* computer);
QHostAddress getBestGlobalAddressV6(QVector<QHostAddress>& addresses); QHostAddress getBestGlobalAddressV6(QVector<QHostAddress>& addresses);
void startPollingComputer(NvComputer* computer); void startPollingComputer(NvComputer* computer);
@ -259,6 +261,7 @@ private:
QReadWriteLock m_Lock; QReadWriteLock m_Lock;
QMap<QString, NvComputer*> m_KnownHosts; QMap<QString, NvComputer*> m_KnownHosts;
QMap<QString, ComputerPollingEntry*> m_PollEntries; QMap<QString, ComputerPollingEntry*> m_PollEntries;
QHash<QString, NvComputer> m_LastSerializedHosts; // Protected by m_DelayedFlushMutex
QSharedPointer<QMdnsEngine::Server> m_MdnsServer; QSharedPointer<QMdnsEngine::Server> m_MdnsServer;
QMdnsEngine::Browser* m_MdnsBrowser; QMdnsEngine::Browser* m_MdnsBrowser;
QVector<MdnsPendingComputer*> m_PendingResolution; QVector<MdnsPendingComputer*> m_PendingResolution;

View File

@ -94,7 +94,7 @@ void NvComputer::serialize(QSettings& settings, bool serializeApps) const
settings.setValue(SER_NVIDIASOFTWARE, isNvidiaServerSoftware); settings.setValue(SER_NVIDIASOFTWARE, isNvidiaServerSoftware);
// Avoid deleting an existing applist if we couldn't get one // Avoid deleting an existing applist if we couldn't get one
if (!appList.isEmpty()) { if (!appList.isEmpty() && serializeApps) {
settings.remove(SER_APPLIST); settings.remove(SER_APPLIST);
settings.beginWriteArray(SER_APPLIST); settings.beginWriteArray(SER_APPLIST);
for (int i = 0; i < appList.count(); i++) { for (int i = 0; i < appList.count(); i++) {
@ -105,6 +105,21 @@ void NvComputer::serialize(QSettings& settings, bool serializeApps) const
} }
} }
bool NvComputer::isEqualSerialized(const NvComputer &that) const
{
return this->name == that.name &&
this->hasCustomName == that.hasCustomName &&
this->uuid == that.uuid &&
this->macAddress == that.macAddress &&
this->localAddress == that.localAddress &&
this->remoteAddress == that.remoteAddress &&
this->ipv6Address == that.ipv6Address &&
this->manualAddress == that.manualAddress &&
this->serverCert == that.serverCert &&
this->isNvidiaServerSoftware == that.isNvidiaServerSoftware &&
this->appList == that.appList;
}
void NvComputer::sortAppList() void NvComputer::sortAppList()
{ {
std::stable_sort(appList.begin(), appList.end(), [](const NvApp& app1, const NvApp& app2) { std::stable_sort(appList.begin(), appList.end(), [](const NvApp& app1, const NvApp& app2) {

View File

@ -8,6 +8,16 @@
#include <QSettings> #include <QSettings>
#include <QRunnable> #include <QRunnable>
class CopySafeReadWriteLock : public QReadWriteLock
{
public:
CopySafeReadWriteLock() = default;
// Don't actually copy the QReadWriteLock
CopySafeReadWriteLock(const CopySafeReadWriteLock&) {}
CopySafeReadWriteLock& operator=(const CopySafeReadWriteLock &) { return *this; }
};
class NvComputer class NvComputer
{ {
friend class PcMonitorThread; friend class PcMonitorThread;
@ -22,6 +32,12 @@ private:
bool pendingQuit; bool pendingQuit;
public: public:
NvComputer() = default;
NvComputer(const NvComputer& other) = default;
NvComputer& operator=(const NvComputer &) = default;
explicit NvComputer(NvHTTP& http, QString serverInfo); explicit NvComputer(NvHTTP& http, QString serverInfo);
explicit NvComputer(QSettings& settings); explicit NvComputer(QSettings& settings);
@ -51,6 +67,9 @@ public:
void void
serialize(QSettings& settings, bool serializeApps) const; serialize(QSettings& settings, bool serializeApps) const;
bool
isEqualSerialized(const NvComputer& that) const;
enum PairState enum PairState
{ {
PS_UNKNOWN, PS_UNKNOWN,
@ -91,9 +110,10 @@ public:
QSslCertificate serverCert; QSslCertificate serverCert;
QVector<NvApp> appList; QVector<NvApp> appList;
bool isNvidiaServerSoftware; bool isNvidiaServerSoftware;
// Remember to update isEqualSerialized() when adding fields here!
// Synchronization // Synchronization
mutable QReadWriteLock lock; mutable CopySafeReadWriteLock lock;
private: private:
uint16_t externalPort; uint16_t externalPort;