#ifndef LIBPKG_DATA_STORAGE_GENERIC_H #define LIBPKG_DATA_STORAGE_GENERIC_H #include "../lmdb-safe/lmdb-reflective.hh" #include "../lmdb-safe/lmdb-safe.hh" #include "../lmdb-safe/lmdb-typed.hh" #include #include #include #include #include #include namespace LibPkg { using StorageID = std::uint32_t; template struct StorageCacheRef { using Storage = StorageType; explicit StorageCacheRef(const StorageType &relatedStorage, const std::shared_ptr &entry); explicit StorageCacheRef(const StorageType &relatedStorage, const std::string &entryName); bool operator==(const StorageCacheRef &other) const; const StorageType *relatedStorage = nullptr; const std::string *entryName; }; template inline StorageCacheRef::StorageCacheRef(const StorageType &relatedStorage, const std::shared_ptr &entry) : relatedStorage(&relatedStorage) , entryName(&entry->name) { } template inline StorageCacheRef::StorageCacheRef(const StorageType &relatedStorage, const std::string &entryName) : relatedStorage(&relatedStorage) , entryName(&entryName) { } template inline bool StorageCacheRef::operator==(const StorageCacheRef &other) const { return relatedStorage == other.relatedStorage && *entryName == *other.entryName; } template struct StorageCacheEntry { using Ref = StorageRefType; using Entry = EntryType; using Storage = typename Ref::Storage; explicit StorageCacheEntry(const StorageRefType &ref, StorageID id); StorageRefType ref; StorageID id; std::shared_ptr entry; }; template inline StorageCacheEntry::StorageCacheEntry(const StorageRefType &ref, StorageID id) : ref(ref) , id(id) { } template struct StorageEntryByID { struct result_type { StorageID id = 0; const typename StorageEntryType::Storage *storage = nullptr; bool operator==(const result_type &other) const { return id == other.id && storage == other.storage; } }; result_type operator()(const StorageEntryType &storageEntry) const { return result_type{ storageEntry.id, storageEntry.ref.relatedStorage }; } }; template class StorageCacheEntries { public: using Ref = typename StorageEntryType::Ref; using Entry = typename StorageEntryType::Entry; using Storage = typename StorageEntryType::Storage; using StorageEntry = StorageEntryType; using ByID = StorageEntryByID; using EntryList = boost::multi_index::multi_index_container, boost::multi_index::hashed_unique, ByID>, boost::multi_index::hashed_unique, BOOST_MULTI_INDEX_MEMBER(StorageEntryType, Ref, ref)>>>; using iterator = typename EntryList::iterator; explicit StorageCacheEntries(std::size_t limit = 1000); template StorageEntry *find(const IndexType &ref); StorageEntry &insert(StorageEntry &&entry); std::size_t erase(const Ref &ref); std::size_t clear(const Storage &storage); iterator begin(); iterator end(); void setLimit(std::size_t limit); std::size_t size() const; private: EntryList m_entries; std::size_t m_limit; }; template inline StorageCacheEntries::StorageCacheEntries(std::size_t limit) : m_limit(limit) { } template inline std::size_t StorageCacheEntries::erase(const Ref &ref) { return m_entries.template get().erase(ref); } template inline auto StorageCacheEntries::begin() -> iterator { return m_entries.begin(); } template inline auto StorageCacheEntries::end() -> iterator { return m_entries.end(); } template inline std::size_t StorageCacheEntries::size() const { return m_entries.size(); } template struct StorageCache { using Entries = StorageEntriesType; using Entry = typename Entries::Entry; using ROTxn = typename StorageType::ROTransaction; using RWTxn = typename StorageType::RWTransaction; using Storage = typename Entries::Storage; struct StoreResult { StorageID id = 0; bool updated = false; std::shared_ptr oldEntry; }; SpecType retrieve(Storage &storage, ROTxn *, StorageID storageID); SpecType retrieve(Storage &storage, StorageID storageID); SpecType retrieve(Storage &storage, RWTxn *, const std::string &entryName); SpecType retrieve(Storage &storage, const std::string &entryName); StoreResult store(Storage &storage, const std::shared_ptr &entry, bool force); StoreResult store(Storage &storage, RWTxn &txn, const std::shared_ptr &entry); bool invalidate(Storage &storage, const std::string &entryName); void clear(Storage &storage); void clearCacheOnly(Storage &storage); void setLimit(std::size_t limit); std::size_t size(); private: Entries m_entries; std::mutex m_mutex; }; template std::size_t StorageCache::size() { return m_entries.size(); } } // namespace LibPkg #endif // LIBPKG_DATA_STORAGE_GENERIC_H