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.
This commit is contained in:
Mathew Sutcliffe
2016-10-20 22:00:05 +01:00
committed by Klaus Basan
parent 937cdbcc55
commit d0d1a9c8b8
2 changed files with 46 additions and 25 deletions

View File

@@ -335,10 +335,10 @@ namespace BlackMisc
public: public:
Session(const QString &filename) : m_filename(filename) {} Session(const QString &filename) : m_filename(filename) {}
void updateSession(); void updateSession();
bool isNewSession() const { return m_isNewSession; } const QUuid &uuid() const { return m_uuid; }
private: private:
const QString m_filename; const QString m_filename;
bool m_isNewSession = false; QUuid m_uuid;
}; };
CDataCacheRevision::CDataCacheRevision(const QString &basename) : m_basename(basename), m_session(std::make_unique<Session>(m_basename + "/.session")) {} CDataCacheRevision::CDataCacheRevision(const QString &basename) : m_basename(basename), m_session(std::make_unique<Session>(m_basename + "/.session")) {}
@@ -421,9 +421,11 @@ namespace BlackMisc
} }
m_session->updateSession(); 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) else if (revisionFile.size() > 0)
@@ -461,6 +463,11 @@ namespace BlackMisc
} }
for (const auto &key : excludeKeys) { timestamps.remove(key); } 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; QJsonObject json;
json.insert("uuid", m_uuid.toString()); json.insert("uuid", m_uuid.toString());
json.insert("timestamps", toJson(timestamps)); json.insert("timestamps", toJson(timestamps));
@@ -681,16 +688,7 @@ namespace BlackMisc
QMutexLocker lock(&m_mutex); QMutexLocker lock(&m_mutex);
Q_ASSERT(! m_updateInProgress); Q_ASSERT(! m_updateInProgress);
m_sessionValues.insert(key); m_sessionValues[key]; // insert default-constructed value, unless key already present
}
bool CDataCacheRevision::isNewSession() const
{
QMutexLocker lock(&m_mutex);
Q_ASSERT(m_updateInProgress);
Q_ASSERT(m_session);
return m_session->isNewSession();
} }
QJsonObject CDataCacheRevision::toJson(const QMap<QString, qint64> &timestamps) QJsonObject CDataCacheRevision::toJson(const QMap<QString, qint64> &timestamps)
@@ -733,6 +731,26 @@ namespace BlackMisc
return result; return result;
} }
QJsonObject CDataCacheRevision::toJson(const QMap<QString, QUuid> &timestamps)
{
QJsonObject result;
for (auto it = timestamps.begin(); it != timestamps.end(); ++it)
{
result.insert(it.key(), it.value().toString());
}
return result;
}
QMap<QString, QUuid> CDataCacheRevision::sessionFromJson(const QJsonObject &session)
{
QMap<QString, QUuid> result;
for (auto it = session.begin(); it != session.end(); ++it)
{
result.insert(it.key(), QUuid(it.value().toString()));
}
return result;
}
void CDataCacheRevision::Session::updateSession() void CDataCacheRevision::Session::updateSession()
{ {
CAtomicFile file(m_filename); CAtomicFile file(m_filename);
@@ -740,19 +758,23 @@ namespace BlackMisc
if (! ok) if (! ok)
{ {
CLogMessage(this).error("Failed to open session file %1: %2") << m_filename << file.errorString(); CLogMessage(this).error("Failed to open session file %1: %2") << m_filename << file.errorString();
m_isNewSession = true;
return; return;
} }
CSequence<CProcessInfo> session; auto json = QJsonDocument::fromJson(file.readAll()).object();
session.convertFromJson(file.readAll()); QUuid uuid(json.value("uuid").toString());
session.removeIf([](const CProcessInfo &pi) { return ! pi.exists(); }); CSequence<CProcessInfo> 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(); CProcessInfo currentProcess = CProcessInfo::currentProcess();
Q_ASSERT(currentProcess.exists()); Q_ASSERT(currentProcess.exists());
session.replaceOrAdd(currentProcess, currentProcess); apps.replaceOrAdd(currentProcess, currentProcess);
if (!(file.seek(0) && file.resize(0) && file.write(QJsonDocument(session.toJson()).toJson()) && file.checkedClose())) 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(); CLogMessage(this).error("Failed to write to session file %1: %2") << m_filename << file.errorString();
} }

View File

@@ -162,9 +162,6 @@ namespace BlackMisc
//! Set the flag which will cause a value to be reset when starting a new session. //! Set the flag which will cause a value to be reset when starting a new session.
void sessionValue(const QString &key); void sessionValue(const QString &key);
//! True if the current update is the first of a new session.
bool isNewSession() const;
private: private:
mutable QMutex m_mutex { QMutex::Recursive }; mutable QMutex m_mutex { QMutex::Recursive };
bool m_updateInProgress = false; bool m_updateInProgress = false;
@@ -180,7 +177,7 @@ namespace BlackMisc
QSet<QString> m_deferredValues; QSet<QString> m_deferredValues;
QSet<QString> m_admittedValues; QSet<QString> m_admittedValues;
QSet<QString> m_admittedQueue; QSet<QString> m_admittedQueue;
QSet<QString> m_sessionValues; QMap<QString, QUuid> m_sessionValues;
std::vector<std::promise<void>> m_promises; std::vector<std::promise<void>> m_promises;
class Session; class Session;
@@ -190,6 +187,8 @@ namespace BlackMisc
static QMap<QString, qint64> fromJson(const QJsonObject &timestamps); static QMap<QString, qint64> fromJson(const QJsonObject &timestamps);
static QJsonArray toJson(const QSet<QString> &pins); static QJsonArray toJson(const QSet<QString> &pins);
static QSet<QString> fromJson(const QJsonArray &pins); static QSet<QString> fromJson(const QJsonArray &pins);
static QJsonObject toJson(const QMap<QString, QUuid> &session);
static QMap<QString, QUuid> sessionFromJson(const QJsonObject &session);
}; };
/*! /*!