From d0d1a9c8b8e4aeeaa9462d27b0df91597649cf14 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Thu, 20 Oct 2016 22:00:05 +0100 Subject: [PATCH] refs #756 Fixed session cache concept: Each new session generates an ID identifying that session, and the .rev file annotates the ID associated with each cache value. This is needed to avoid reading a value from a previous session when loading for a continuing (non-new) session. The coarse- grained approach of distinguishing new sessions from non-new sessions was insufficient. --- src/blackmisc/datacache.cpp | 64 +++++++++++++++++++++++++------------ src/blackmisc/datacache.h | 7 ++-- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/blackmisc/datacache.cpp b/src/blackmisc/datacache.cpp index 97a7f769f..ab7b02331 100644 --- a/src/blackmisc/datacache.cpp +++ b/src/blackmisc/datacache.cpp @@ -335,10 +335,10 @@ namespace BlackMisc public: Session(const QString &filename) : m_filename(filename) {} void updateSession(); - bool isNewSession() const { return m_isNewSession; } + const QUuid &uuid() const { return m_uuid; } private: const QString m_filename; - bool m_isNewSession = false; + QUuid m_uuid; }; CDataCacheRevision::CDataCacheRevision(const QString &basename) : m_basename(basename), m_session(std::make_unique(m_basename + "/.session")) {} @@ -421,9 +421,11 @@ namespace BlackMisc } m_session->updateSession(); - if (isNewSession()) + auto sessionIds = sessionFromJson(json.value("session").toObject()); + for (auto it = sessionIds.cbegin(); it != sessionIds.cend(); ++it) { - for (const auto &key : fromJson(json.value("session").toArray())) { m_timestamps.remove(key); } + m_sessionValues[it.key()] = it.value(); + if (it.value() != m_session->uuid()) { m_timestamps.remove(it.key()); } } } else if (revisionFile.size() > 0) @@ -461,6 +463,11 @@ namespace BlackMisc } for (const auto &key : excludeKeys) { timestamps.remove(key); } + for (auto it = timestamps.cbegin(); it != timestamps.cend(); ++it) + { + if (m_sessionValues.contains(it.key())) { m_sessionValues[it.key()] = m_session->uuid(); } + } + QJsonObject json; json.insert("uuid", m_uuid.toString()); json.insert("timestamps", toJson(timestamps)); @@ -681,16 +688,7 @@ namespace BlackMisc QMutexLocker lock(&m_mutex); Q_ASSERT(! m_updateInProgress); - m_sessionValues.insert(key); - } - - bool CDataCacheRevision::isNewSession() const - { - QMutexLocker lock(&m_mutex); - - Q_ASSERT(m_updateInProgress); - Q_ASSERT(m_session); - return m_session->isNewSession(); + m_sessionValues[key]; // insert default-constructed value, unless key already present } QJsonObject CDataCacheRevision::toJson(const QMap ×tamps) @@ -733,6 +731,26 @@ namespace BlackMisc return result; } + QJsonObject CDataCacheRevision::toJson(const QMap ×tamps) + { + QJsonObject result; + for (auto it = timestamps.begin(); it != timestamps.end(); ++it) + { + result.insert(it.key(), it.value().toString()); + } + return result; + } + + QMap CDataCacheRevision::sessionFromJson(const QJsonObject &session) + { + QMap result; + for (auto it = session.begin(); it != session.end(); ++it) + { + result.insert(it.key(), QUuid(it.value().toString())); + } + return result; + } + void CDataCacheRevision::Session::updateSession() { CAtomicFile file(m_filename); @@ -740,19 +758,23 @@ namespace BlackMisc if (! ok) { CLogMessage(this).error("Failed to open session file %1: %2") << m_filename << file.errorString(); - m_isNewSession = true; return; } - CSequence session; - session.convertFromJson(file.readAll()); - session.removeIf([](const CProcessInfo &pi) { return ! pi.exists(); }); + auto json = QJsonDocument::fromJson(file.readAll()).object(); + QUuid uuid(json.value("uuid").toString()); + CSequence apps; + apps.convertFromJson(json.value("apps").toObject()); + apps.removeIf([](const CProcessInfo &pi) { return ! pi.exists(); }); - m_isNewSession = session.isEmpty(); + if (apps.isEmpty()) { uuid = CIdentifier().toUuid(); } + m_uuid = uuid; CProcessInfo currentProcess = CProcessInfo::currentProcess(); Q_ASSERT(currentProcess.exists()); - session.replaceOrAdd(currentProcess, currentProcess); - if (!(file.seek(0) && file.resize(0) && file.write(QJsonDocument(session.toJson()).toJson()) && file.checkedClose())) + apps.replaceOrAdd(currentProcess, currentProcess); + json.insert("apps", apps.toJson()); + json.insert("uuid", uuid.toString()); + if (!(file.seek(0) && file.resize(0) && file.write(QJsonDocument(json).toJson()) && file.checkedClose())) { CLogMessage(this).error("Failed to write to session file %1: %2") << m_filename << file.errorString(); } diff --git a/src/blackmisc/datacache.h b/src/blackmisc/datacache.h index 7036b2ebf..450010fc4 100644 --- a/src/blackmisc/datacache.h +++ b/src/blackmisc/datacache.h @@ -162,9 +162,6 @@ namespace BlackMisc //! Set the flag which will cause a value to be reset when starting a new session. void sessionValue(const QString &key); - //! True if the current update is the first of a new session. - bool isNewSession() const; - private: mutable QMutex m_mutex { QMutex::Recursive }; bool m_updateInProgress = false; @@ -180,7 +177,7 @@ namespace BlackMisc QSet m_deferredValues; QSet m_admittedValues; QSet m_admittedQueue; - QSet m_sessionValues; + QMap m_sessionValues; std::vector> m_promises; class Session; @@ -190,6 +187,8 @@ namespace BlackMisc static QMap fromJson(const QJsonObject ×tamps); static QJsonArray toJson(const QSet &pins); static QSet fromJson(const QJsonArray &pins); + static QJsonObject toJson(const QMap &session); + static QMap sessionFromJson(const QJsonObject &session); }; /*!