mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-14 08:45:36 +08:00
refs #756 Allow to mark data cache traits with a session flag, so they are overwritten when starting a new session.
(Starting a new session means, that a swift application is started when no other swift application is running.)
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "blackmisc/directoryutils.h"
|
||||
#include "blackmisc/identifier.h"
|
||||
#include "blackmisc/logmessage.h"
|
||||
#include "blackmisc/processinfo.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDir>
|
||||
@@ -165,6 +166,11 @@ namespace BlackMisc
|
||||
if (triggerLoad) { loadFromStoreAsync(); }
|
||||
}
|
||||
|
||||
void CDataCache::sessionValue(const QString &key)
|
||||
{
|
||||
QTimer::singleShot(0, &m_serializer, [this, key] { m_revision.sessionValue(key); });
|
||||
}
|
||||
|
||||
QString lockFileError(const QLockFile &lock)
|
||||
{
|
||||
switch (lock.error())
|
||||
@@ -292,6 +298,7 @@ namespace BlackMisc
|
||||
|
||||
auto missingKeys = m_cache->m_revision.keysWithNewerTimestamps().subtract(newValues.keys());
|
||||
if (! missingKeys.isEmpty()) { m_cache->m_revision.writeNewRevision({}, missingKeys); }
|
||||
else if (m_cache->m_revision.isNewSession()) { m_cache->m_revision.writeNewRevision({}); }
|
||||
|
||||
msg.setCategories(this);
|
||||
CLogMessage::preformatted(msg);
|
||||
@@ -324,6 +331,21 @@ namespace BlackMisc
|
||||
});
|
||||
}
|
||||
|
||||
class BLACKMISC_EXPORT CDataCacheRevision::Session
|
||||
{
|
||||
public:
|
||||
Session(const QString &filename) : m_filename(filename) {}
|
||||
void updateSession();
|
||||
bool isNewSession() const { return m_isNewSession; }
|
||||
private:
|
||||
const QString m_filename;
|
||||
bool m_isNewSession = false;
|
||||
};
|
||||
|
||||
CDataCacheRevision::CDataCacheRevision(const QString &basename) : m_basename(basename) {}
|
||||
|
||||
CDataCacheRevision::~CDataCacheRevision() = default;
|
||||
|
||||
CDataCacheRevision::LockGuard CDataCacheRevision::beginUpdate(const QMap<QString, qint64> ×tamps, bool updateUuid, bool pinsOnly)
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
@@ -341,6 +363,7 @@ namespace BlackMisc
|
||||
|
||||
m_timestamps.clear();
|
||||
m_originalTimestamps.clear();
|
||||
if (! m_session) { m_session = std::make_unique<Session>(m_basename + "/.session"); }
|
||||
|
||||
QFile revisionFile(m_basename + "/.rev");
|
||||
if (revisionFile.exists())
|
||||
@@ -398,6 +421,12 @@ namespace BlackMisc
|
||||
{
|
||||
if (deferrals.contains(key) && ! m_admittedValues.contains(key)) { m_timestamps.remove(key); }
|
||||
}
|
||||
|
||||
m_session->updateSession();
|
||||
if (isNewSession())
|
||||
{
|
||||
for (const auto &key : fromJson(json.value("session").toArray())) { m_timestamps.remove(key); }
|
||||
}
|
||||
}
|
||||
else if (revisionFile.size() > 0)
|
||||
{
|
||||
@@ -440,6 +469,7 @@ namespace BlackMisc
|
||||
json.insert("ttl", toJson(m_timesToLive));
|
||||
json.insert("pins", toJson(m_pinnedValues));
|
||||
json.insert("deferrals", toJson(m_deferredValues));
|
||||
json.insert("session", toJson(m_sessionValues));
|
||||
revisionFile.write(QJsonDocument(json).toJson());
|
||||
|
||||
if (! revisionFile.checkedClose())
|
||||
@@ -648,6 +678,23 @@ namespace BlackMisc
|
||||
m_admittedQueue.insert(key);
|
||||
}
|
||||
|
||||
void CDataCacheRevision::sessionValue(const QString &key)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
QJsonObject CDataCacheRevision::toJson(const QMap<QString, qint64> ×tamps)
|
||||
{
|
||||
QJsonObject result;
|
||||
@@ -687,6 +734,32 @@ namespace BlackMisc
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CDataCacheRevision::Session::updateSession()
|
||||
{
|
||||
CAtomicFile file(m_filename);
|
||||
bool ok = file.open(QIODevice::ReadWrite | QFile::Text);
|
||||
if (! ok)
|
||||
{
|
||||
CLogMessage(this).error("Failed to open session file %1: %2") << m_filename << file.errorString();
|
||||
m_isNewSession = true;
|
||||
return;
|
||||
}
|
||||
CSequence<CProcessInfo> session;
|
||||
session.convertFromJson(file.readAll());
|
||||
session.removeIf([](const CProcessInfo &pi) { return ! pi.exists(); });
|
||||
|
||||
m_isNewSession = session.isEmpty();
|
||||
|
||||
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()))
|
||||
{
|
||||
CLogMessage(this).error("Failed to write to session file %1: %2") << m_filename << file.errorString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//! \endcond
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <QtDebug>
|
||||
#include <QtGlobal>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -85,7 +86,10 @@ namespace BlackMisc
|
||||
{
|
||||
public:
|
||||
//! Construct the single instance of the revision metastate.
|
||||
CDataCacheRevision(const QString &basename) : m_basename(basename) {}
|
||||
CDataCacheRevision(const QString &basename);
|
||||
|
||||
//! Destructor.
|
||||
~CDataCacheRevision();
|
||||
|
||||
//! Non-copyable.
|
||||
//! @{
|
||||
@@ -155,6 +159,12 @@ namespace BlackMisc
|
||||
//! Set the flag which will cause a deferred-load value to be loaded.
|
||||
void admitValue(const QString &key);
|
||||
|
||||
//! 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;
|
||||
@@ -170,8 +180,12 @@ namespace BlackMisc
|
||||
QSet<QString> m_deferredValues;
|
||||
QSet<QString> m_admittedValues;
|
||||
QSet<QString> m_admittedQueue;
|
||||
QSet<QString> m_sessionValues;
|
||||
std::vector<std::promise<void>> m_promises;
|
||||
|
||||
class Session;
|
||||
std::unique_ptr<Session> m_session;
|
||||
|
||||
static QJsonObject toJson(const QMap<QString, qint64> ×tamps);
|
||||
static QMap<QString, qint64> fromJson(const QJsonObject ×tamps);
|
||||
static QJsonArray toJson(const QSet<QString> &pins);
|
||||
@@ -262,6 +276,9 @@ namespace BlackMisc
|
||||
//! Method used for implementing deferring values.
|
||||
void admitValue(const QString &key, bool triggerLoad);
|
||||
|
||||
//! Method used for implementing session values.
|
||||
void sessionValue(const QString &key);
|
||||
|
||||
private:
|
||||
CDataCache();
|
||||
|
||||
@@ -295,6 +312,7 @@ namespace BlackMisc
|
||||
if (Trait::timeToLive() >= 0) { CDataCache::instance()->setTimeToLive(this->getKey(), Trait::timeToLive()); }
|
||||
if (Trait::isPinned()) { CDataCache::instance()->pinValue(this->getKey()); }
|
||||
if (Trait::isDeferred()) { CDataCache::instance()->deferValue(this->getKey()); }
|
||||
if (Trait::isSession()) { CDataCache::instance()->sessionValue(this->getKey()); }
|
||||
static_assert(! (Trait::isPinned() && Trait::isDeferred()), "trait can not be both pinned and deferred");
|
||||
}
|
||||
|
||||
@@ -420,6 +438,11 @@ namespace BlackMisc
|
||||
//! Good for large values the loading of which might depend on some other condition.
|
||||
static constexpr bool isDeferred() { return false; }
|
||||
|
||||
//! If true, then upon starting an application, value will be overwritten with the default
|
||||
//! if there are no other applications currently using the cache. In effect, the value
|
||||
//! is retained only while there are applications using the cache.
|
||||
static constexpr bool isSession() { return false; }
|
||||
|
||||
//! Deleted default constructor.
|
||||
TDataTrait() = delete;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user