#pragma once #include "../core/slang-crypto.h" #include "../core/slang-io.h" #include "../core/slang-string.h" #include "slang.h" #include namespace Slang { /// Implements a simple persistent cache on the filesystem for storing key/value pairs. /// Keys are SHA1 hashes and values are arbitrary blobs of data. /// The cache is save for concurrent access from multiple threads/processes by using /// a lock file within the cache directory. Furthermore, the cache implements a LRU /// eviction policy. class PersistentCache : public RefObject { public: struct Desc { // The root directory for the cache. const char* directory = nullptr; // The maximum number of entries stored in the cache. By default, there is no limit. Count maxEntryCount = 0; }; struct Stats { // Number of cache hits since last resetting the stats. Count hitCount; // Number of cache misses since last resetting the stats. Count missCount; // Current number of entries in the cache. Count entryCount; }; using Key = SHA1::Digest; PersistentCache(const Desc& desc); ~PersistentCache(); /// Clear the contents of the cache by removing the cache index and all entry files. SlangResult clear(); const Stats& getStats() const { return m_stats; } void resetStats(); /// Read an entry from the cache. /// Returns SLANG_OK if successful, SLANG_E_NOT_FOUND if the entry is not in the cache. SlangResult readEntry(const Key& key, ISlangBlob** outData); /// Write an entry to the cache. /// Returns SLANG_OK if successful. SlangResult writeEntry(const Key& key, ISlangBlob* data); private: struct CacheEntry { Key key; uint32_t age; }; using CacheIndex = List; SlangResult initialize(); String getEntryFileName(const Key& key); SlangResult readIndex(const String& fileName, CacheIndex& outIndex); SlangResult writeIndex(const String& fileName, const CacheIndex& index); String m_cacheDirectory; String m_lockFileName; String m_indexFileName; // For exclusive locking we need both a mutex (acquired first) // followed by a a file lock. The mutex is needed because on Linux // the file lock is only locking between processes, not threads. std::mutex m_mutex; Slang::LockFile m_lockFile; Count m_maxEntryCount; Stats m_stats; // Used for unit tests. friend struct PersistentCacheTest; }; } // namespace Slang