6 #ifndef SWIFT_MISC_DATACACHE_H
7 #define SWIFT_MISC_DATACACHE_H
15 #include <QFileSystemWatcher>
17 #include <QJsonObject>
26 #include <QStringList>
67 CValuePage *m_page =
nullptr;
68 QList<std::pair<CValueCachePacket, QObject *>> m_queue;
167 mutable QRecursiveMutex m_mutex;
168 bool m_updateInProgress =
false;
169 bool m_found =
false;
170 bool m_pendingRead =
false;
171 bool m_pendingWrite =
false;
173 QLockFile m_lockFile { m_basename +
"/.lock" };
178 QSet<QString> m_pinnedValues;
179 QSet<QString> m_deferredValues;
180 QSet<QString> m_admittedValues;
181 QSet<QString> m_admittedQueue;
183 std::vector<std::promise<void>> m_promises;
186 std::unique_ptr<Session> m_session;
190 static QJsonArray toJson(
const QSet<QString> &pins);
191 static QSet<QString> fromJson(
const QJsonArray &pins);
221 bool pinsOnly =
false);
229 const QString &persistentStore()
const;
230 void applyDeferredChanges();
231 void deliverPromises(std::vector<std::promise<void>>);
235 const QString m_revisionFileName;
298 void loadFromStoreAsync();
300 virtual void connectPage(private_ns::CValuePage *page)
override;
302 QFileSystemWatcher m_watcher;
313 template <
typename Trait>
319 template <
typename T>
322 Trait::defaultValue(), owner)
326 this->onOwnerNameChanged([
this, owner] { private_ns::reconstruct(
this, owner); });
329 if (Trait::timeToLive() >= 0)
336 static_assert(!(Trait::isPinned() && Trait::isDeferred()),
"trait can not be both pinned and deferred");
343 template <
typename T,
typename F>
372 return Trait::timeToLive() >= 0 &&
373 this->
getTimestamp() + Trait::timeToLive() > QDateTime::currentMSecsSinceEpoch();
385 if (Trait::isDeferred())
402 auto *queue = this->m_page->template findChild<private_ns::CDataPageQueue *>();
405 const QString key(this->
getKey());
415 QPointer<QObject> myself(queue);
417 if (!myself) {
return; }
418 queue->setQueuedValueFromCache(key);
427 qint64 timestamp = 0) =
delete;
438 template <
typename Trait>
457 template <
typename T>
466 qFatal(
"Not implemented");
473 static const QString name;
479 static bool isValid(
const T &value, QString &reason)
490 static const T def {};
Provides access to one of the values stored in a CValueCache.
CStatusMessage setProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp=0)
Write a property of the value. Must be called from the thread in which the owner lives.
bool isInitialized() const
Can be false if key contains OwnerName% and owner's objectName was empty.
CStatusMessage set(const T &value, qint64 timestamp=0)
Write a new value. Must be called from the thread in which the owner lives.
const QString & getKey() const
Get the key string of this value.
void setNotifySlot(F slot)
Set a callback to be called when the value is changed by another source.
QDateTime getTimestamp() const
Return the time when this value was updated.
Base class for a long-lived worker object which lives in its own thread.
Singleton derived class of CValueCache, for core dynamic data.
static CDataCache * instance()
Return the singleton instance.
void sessionValue(const QString &key)
Method used for implementing session values.
static const QString & revisionFileName()
Revision file name.
virtual ~CDataCache()
Destructor.
void setTimeToLive(const QString &key, int ttl)
Method used for implementing TTL.
static const QString & persistentStore()
The directory where core data are stored.
void deferValue(const QString &key)
Method used for implementing deferring values.
bool synchronize(const QString &key)
Method used for implementing CData::synchronize.
qint64 getTimestampOnDisk(const QString &key)
Method used for implementing loading timestamp without value.
QStringList enumerateStore() const
Return all files where data may be stored.
static const QString & relativeFilePath()
Relative file path in application data directory.
void admitValue(const QString &key, bool triggerLoad)
Method used for implementing deferring values.
static QString filenameForKey(const QString &key)
Return the filename where the value with the given key may be stored.
void pinValue(const QString &key)
Method used for implementing pinning values.
void renewTimestamp(const QString &key, qint64 timestamp)
Method used for implementing timestamp renewal.
Encapsulates metastate about how the version of the cache in memory compares to the one on disk.
std::future< void > promiseLoadedValue(const QString &key, qint64 currentTimestamp)
Return a future which will be made ready when the value is loaded. Future is invalid if value is not ...
void setTimeToLive(const QString &key, int ttl)
Set TTL value that will be written to the revision file.
void admitValue(const QString &key)
Set the flag which will cause a deferred-load value to be loaded.
void writeNewRevision(const QMap< QString, qint64 > ×tamps, const QSet< QString > &excludeKeys={})
During update, writes a new revision file with new timestamps.
QSet< QString > keysWithNewerTimestamps() const
During update, returns keys which have on-disk timestamps newer than in-memory. Guaranteed not empty.
CDataCacheRevision & operator=(const CDataCacheRevision &)=delete
Non-copyable.
void pinValue(const QString &key)
Set the flag which will cause the value to be pre-loaded.
void breakPromises()
Abandon all promises.
LockGuard beginUpdate(const QMap< QString, qint64 > ×tamps, bool updateUuid=true, bool pinsOnly=false)
Get the state of the disk cache, and prepare to update any values which are out of date....
void overrideTimestamp(const QString &key, qint64 timestamp)
Causes the new timestamp to be written to the revision file.
bool isPendingRead() const
True if beginUpdate found some values with timestamps newer than in memory.
void regenerate(const CValueCachePacket &keys)
Write a new revision file with keys deduced from the available JSON files.
void finishUpdate(bool keepPromises=false)
Release the revision file lock and mark everything up-to-date (called by LockGuard destructor).
const QMap< QString, qint64 > & newerTimestamps() const
During update, returns timestamps which have on-disk timestamps newer than in-memory....
CDataCacheRevision(const CDataCacheRevision &)=delete
Non-copyable.
void notifyPendingWrite()
Call before beginUpdate if there is a write pending, so update will start even if there is nothing to...
bool isNewerValueAvailable(const QString &key, qint64 timestamp)
During update, returns true if the on-disk timestamp of this key is newer than in-memory.
CDataCacheRevision(const QString &basename)
Construct the single instance of the revision metastate.
void deferValue(const QString &key)
Set the flag which will cause the value to be deferred-loaded.
QString timestampsAsString() const
Keys with timestamps.
void sessionValue(const QString &key)
Set the flag which will cause a value to be reset when starting a new session.
bool isFound() const
Existing revision file was found.
qint64 getTimestampOnDisk(const QString &key)
Read the revision file to get a timestamp.
~CDataCacheRevision()
Destructor.
std::vector< std::promise< void > > loadedValuePromises()
Returns (by move) the container of promises to load values.
Worker which performs (de)serialization on behalf of CDataCache, in a separate thread so that the mai...
CDataCacheSerializer(CDataCache *owner, const QString &revisionFileName)
Constructor.
static const QStringList & getLogCategories()
Log categories.
void valuesLoadedFromStore(const swift::misc::CValueCachePacket &values, const swift::misc::CIdentifier &originator)
Signal back to the cache when values have been loaded.
CDataCacheRevision::LockGuard loadFromStore(const swift::misc::CValueCachePacket &baseline, bool defer=false, bool pinsOnly=false)
Load values from persistent store. Called once per second. Also called by saveToStore,...
void saveToStore(const swift::misc::CVariantMap &values, const swift::misc::CValueCachePacket &baseline)
Save values to persistent store. Called whenever a value is changed locally.
Class template for accessing a specific value in the CDataCache.
CStatusMessage setProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp=0)
Write a property of the value. Must be called from the thread in which the owner lives.
CStatusMessage set(const typename Trait::type &value, qint64 timestamp=0)
Write a new value. Must be called from the thread in which the owner lives.
QString getFilename() const
Return the file that is used for persistence for this value.
CStatusMessage setAndSave(const typename Trait::type &value, qint64 timestamp=0)=delete
Data cache doesn't support setAndSave (because set() already causes save anyway).
void admit()
If the value is load-deferred, trigger the deferred load (async).
CStatusMessage save()=delete
Data cache doesn't support save (because currently set value is saved already).
CStatusMessage setAndSaveProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp=0)=delete
Data cache doesn't support setAndSave (because set() already causes save anyway).
CData(T *owner)
Constructor.
void renewTimestamp(qint64 timestamp)
Don't change the value, but write a new timestamp, to extend the life of the value.
QDateTime getAvailableTimestamp() const
Get the timestamp of the value, or of the deferred value that is available to be loaded.
CData(T *owner, F slot)
Constructor.
bool isStale() const
True if the current timestamp is older than the TTL (time to live).
void synchronize()
If the value is currently being loaded, wait for it to finish loading, and call the notification slot...
CStatusMessage setDefault()
Reset the data to its default value.
Class template for read-only access to a specific value in the CDataCache.
CStatusMessage setProperty(CPropertyIndexRef index, const CVariant &value, qint64 timestamp=0)=delete
Deleted mutators.
CStatusMessage set(const typename Trait::type &value, qint64 timestamp=0)=delete
Deleted mutators.
void renewTimestamp(qint64 timestamp)=delete
Deleted mutators.
CStatusMessage setDefault()=delete
Deleted mutators.
Value object encapsulating information identifying a component of a modular distributed swift process...
Non-owning reference to a CPropertyIndex with a subset of its features.
Streamable status message, e.g.
static bool isInThisThread(const QObject *toBeTested)
Is the current thread the object's thread?
Manages a map of { QString, CVariant } pairs, which can be distributed among multiple processes.
Value class used for signalling changed values in the cache.
Wrapper around QVariant which provides transparent access to CValueObject methods of the contained ob...
Map of { QString, CVariant } pairs.
Decorator for CValuePage which allows incoming remote changes to be queued to allow for more flexibil...
void setQueuedValueFromCache(const QString &key)
Synchronize with one specific change in the queue, leave the rest for later.
void queueValuesFromCache(const swift::misc::CValueCachePacket &values, QObject *changedBy)
Add to the queue to synchronize with a change caused by another page.
CDataPageQueue(CValuePage *parent)
Constructor.
void setQueuedValuesFromCache()
Synchronize with changes queued by queueValuesFromCache.
Free functions in swift::misc.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
Base class for traits to be used as template argument to swift::misc::CData.
static const QString & humanReadable()
Optional human readable name.
TDataTrait(const TDataTrait &)=delete
Deleted copy constructor.
TDataTrait()=delete
Deleted default constructor.
static constexpr bool isSession()
If true, then upon starting an application, value will be overwritten with the default if there are n...
static constexpr bool isPinned()
If true, then value will be synchronously loaded when CDataCache is constructed. Good for small,...
static bool isValid(const T &value, QString &reason)
Validator function. Return true if the argument is valid, false otherwise. Default implementation jus...
static const T & defaultValue()
Return the value to use in case the supplied value does not satisfy the validator....
static int timeToLive()
Number of milliseconds after which cached value becomes stale. Default is -1 which means value never ...
TDataTrait & operator=(const TDataTrait &)=delete
Deleted copy assignment operator.
static constexpr bool isDeferred()
If true, then value will not be loaded until it is explicitly admitted. Good for large values the loa...
T type
Data type of the value.
static const char * key()
Key string of the value. Reimplemented in derived class.
#define SWIFT_MISC_EXPORT
Export a class or function from the library.