lmdb: Generalize caching to be able to use it for other types than packages
This commit is contained in:
parent
a8afccf081
commit
231571f2d1
|
@ -365,8 +365,8 @@ StorageID Database::updatePackage(const std::shared_ptr<Package> &package)
|
||||||
if (!res.updated) {
|
if (!res.updated) {
|
||||||
return res.id;
|
return res.id;
|
||||||
}
|
}
|
||||||
if (res.oldPackage) {
|
if (res.oldEntry) {
|
||||||
removePackageDependencies(res.id, res.oldPackage);
|
removePackageDependencies(res.id, res.oldEntry);
|
||||||
}
|
}
|
||||||
addPackageDependencies(res.id, package);
|
addPackageDependencies(res.id, package);
|
||||||
return res.id;
|
return res.id;
|
||||||
|
@ -375,8 +375,8 @@ StorageID Database::updatePackage(const std::shared_ptr<Package> &package)
|
||||||
StorageID Database::forceUpdatePackage(const std::shared_ptr<Package> &package)
|
StorageID Database::forceUpdatePackage(const std::shared_ptr<Package> &package)
|
||||||
{
|
{
|
||||||
const auto res = m_storage->packageCache.store(*m_storage, package, true);
|
const auto res = m_storage->packageCache.store(*m_storage, package, true);
|
||||||
if (res.oldPackage) {
|
if (res.oldEntry) {
|
||||||
removePackageDependencies(res.id, res.oldPackage);
|
removePackageDependencies(res.id, res.oldEntry);
|
||||||
}
|
}
|
||||||
addPackageDependencies(res.id, package);
|
addPackageDependencies(res.id, package);
|
||||||
return res.id;
|
return res.id;
|
||||||
|
@ -628,8 +628,8 @@ PackageUpdaterPrivate::PackageUpdaterPrivate(DatabaseStorage &storage)
|
||||||
void PackageUpdaterPrivate::update(const PackageCache::StoreResult &res, const std::shared_ptr<Package> &package)
|
void PackageUpdaterPrivate::update(const PackageCache::StoreResult &res, const std::shared_ptr<Package> &package)
|
||||||
{
|
{
|
||||||
update(res.id, false, package);
|
update(res.id, false, package);
|
||||||
if (res.oldPackage) {
|
if (res.oldEntry) {
|
||||||
update(res.id, true, res.oldPackage);
|
update(res.id, true, res.oldEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,102 +6,132 @@ using namespace CppUtilities;
|
||||||
|
|
||||||
namespace LibPkg {
|
namespace LibPkg {
|
||||||
|
|
||||||
StorageDistribution::StorageDistribution(const char *path, std::uint32_t maxDbs)
|
template <typename StorageEntryType> auto StorageCacheEntries<StorageEntryType>::findOrCreate(const Ref &ref) -> StorageEntry &
|
||||||
{
|
{
|
||||||
m_env = LMDBSafe::getMDBEnv(path, MDB_NOSUBDIR, 0600, maxDbs);
|
const auto &index = m_entries.template get<Ref>();
|
||||||
|
if (auto i = index.find(ref); i != index.end()) {
|
||||||
|
m_entries.relocate(m_entries.begin(), m_entries.template project<0>(i));
|
||||||
|
return i.get_node()->value();
|
||||||
|
}
|
||||||
|
const auto [i, newItem] = m_entries.emplace_front(ref);
|
||||||
|
if (!newItem) {
|
||||||
|
m_entries.relocate(m_entries.begin(), i);
|
||||||
|
} else if (m_entries.size() > m_limit) {
|
||||||
|
m_entries.pop_back();
|
||||||
|
}
|
||||||
|
return i.get_node()->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageSpec PackageCache::retrieve(DatabaseStorage &databaseStorage, const std::string &packageName)
|
template <typename StorageEntryType> std::size_t StorageCacheEntries<StorageEntryType>::clear(const Storage &storage)
|
||||||
|
{
|
||||||
|
auto count = std::size_t();
|
||||||
|
for (auto i = m_entries.begin(); i != m_entries.end();) {
|
||||||
|
if (i->ref.relatedStorage == &storage) {
|
||||||
|
i = m_entries.erase(i);
|
||||||
|
++count;
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename StorageEntriesType, typename TransactionType, typename SpecType>
|
||||||
|
auto StorageCache<StorageEntriesType, TransactionType, SpecType>::retrieve(Storage &storage, const std::string &entryName) -> SpecType
|
||||||
{
|
{
|
||||||
// check for package in cache
|
// check for package in cache
|
||||||
const auto ref = PackageCacheRef(databaseStorage, packageName);
|
const auto ref = typename Entries::Ref(storage, entryName);
|
||||||
const auto lock = std::unique_lock(m_mutex);
|
const auto lock = std::unique_lock(m_mutex);
|
||||||
auto &cacheEntry = m_packages.findOrCreate(ref);
|
auto &cacheEntry = m_entries.findOrCreate(ref);
|
||||||
if (cacheEntry.package) {
|
if (cacheEntry.entry) {
|
||||||
return PackageSpec(cacheEntry.id, cacheEntry.package);
|
return PackageSpec(cacheEntry.id, cacheEntry.entry);
|
||||||
}
|
}
|
||||||
// check for package in storage, populate cache entry
|
// check for package in storage, populate cache entry
|
||||||
cacheEntry.package = std::make_unique<Package>();
|
cacheEntry.entry = std::make_shared<Entry>();
|
||||||
auto txn = databaseStorage.packages.getROTransaction();
|
auto txn = storage.packages.getROTransaction();
|
||||||
if ((cacheEntry.id = txn.get<0>(packageName, *cacheEntry.package))) {
|
if ((cacheEntry.id = txn.template get<0>(entryName, *cacheEntry.entry))) {
|
||||||
cacheEntry.ref.packageName = &cacheEntry.package->name;
|
cacheEntry.ref.entryName = &cacheEntry.entry->name;
|
||||||
return PackageSpec(cacheEntry.id, cacheEntry.package);
|
return PackageSpec(cacheEntry.id, cacheEntry.entry);
|
||||||
}
|
}
|
||||||
m_packages.undo();
|
m_entries.undo();
|
||||||
return PackageSpec(0, std::shared_ptr<Package>());
|
return PackageSpec(0, std::shared_ptr<Entry>());
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageCache::StoreResult PackageCache::store(DatabaseStorage &databaseStorage, const std::shared_ptr<Package> &package, bool force)
|
template <typename StorageEntriesType, typename TransactionType, typename SpecType>
|
||||||
|
auto StorageCache<StorageEntriesType, TransactionType, SpecType>::store(Storage &storage, const std::shared_ptr<Entry> &entry, bool force)
|
||||||
|
-> StoreResult
|
||||||
{
|
{
|
||||||
// check for package in cache
|
// check for package in cache
|
||||||
const auto ref = PackageCacheRef(databaseStorage, package->name);
|
const auto ref = typename Entries::Ref(storage, entry->name);
|
||||||
auto res = PackageCache::StoreResult();
|
auto res = StorageCache::StoreResult();
|
||||||
auto lock = std::unique_lock(m_mutex);
|
auto lock = std::unique_lock(m_mutex);
|
||||||
auto &cacheEntry = m_packages.findOrCreate(ref);
|
auto &cacheEntry = m_entries.findOrCreate(ref);
|
||||||
if (cacheEntry.package == package && !force) {
|
if (cacheEntry.entry == entry && !force) {
|
||||||
// do nothing if cached package is the same as specified one
|
// do nothing if cached package is the same as specified one
|
||||||
res.id = cacheEntry.id;
|
res.id = cacheEntry.id;
|
||||||
return res;
|
return res;
|
||||||
} else if (cacheEntry.package) {
|
} else if (cacheEntry.entry) {
|
||||||
// retain certain information obtained from package contents if this is actually the same package as before
|
// retain certain information obtained from package contents if this is actually the same package as before
|
||||||
package->addDepsAndProvidesFromOtherPackage(*(res.oldPackage = cacheEntry.package));
|
entry->addDepsAndProvidesFromOtherPackage(*(res.oldEntry = cacheEntry.entry));
|
||||||
} else {
|
} else {
|
||||||
cacheEntry.package = std::make_shared<Package>();
|
cacheEntry.entry = std::make_shared<Entry>();
|
||||||
}
|
}
|
||||||
// check for package in storage
|
// check for package in storage
|
||||||
auto txn = databaseStorage.packages.getRWTransaction();
|
auto txn = storage.packages.getRWTransaction();
|
||||||
if (!res.oldPackage && (cacheEntry.id = txn.get<0>(package->name, *cacheEntry.package))) {
|
if (!res.oldEntry && (cacheEntry.id = txn.template get<0>(entry->name, *cacheEntry.entry))) {
|
||||||
package->addDepsAndProvidesFromOtherPackage(*(res.oldPackage = cacheEntry.package));
|
entry->addDepsAndProvidesFromOtherPackage(*(res.oldEntry = cacheEntry.entry));
|
||||||
}
|
}
|
||||||
// update cache entry
|
// update cache entry
|
||||||
cacheEntry.ref.packageName = &package->name;
|
cacheEntry.ref.entryName = &entry->name;
|
||||||
cacheEntry.package = package;
|
cacheEntry.entry = entry;
|
||||||
// update package in storage
|
// update package in storage
|
||||||
cacheEntry.id = txn.put(*package, cacheEntry.id);
|
cacheEntry.id = txn.put(*entry, cacheEntry.id);
|
||||||
txn.commit();
|
txn.commit();
|
||||||
res.id = cacheEntry.id;
|
res.id = cacheEntry.id;
|
||||||
res.updated = true;
|
res.updated = true;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageCache::StoreResult PackageCache::store(
|
template <typename StorageEntriesType, typename TransactionType, typename SpecType>
|
||||||
DatabaseStorage &databaseStorage, PackageStorage::RWTransaction &txn, const std::shared_ptr<Package> &package)
|
auto StorageCache<StorageEntriesType, TransactionType, SpecType>::store(Storage &storage, Txn &txn, const std::shared_ptr<Entry> &entry)
|
||||||
|
-> StoreResult
|
||||||
{
|
{
|
||||||
// check for package in cache
|
// check for package in cache
|
||||||
const auto ref = PackageCacheRef(databaseStorage, package->name);
|
const auto ref = typename Entries::Ref(storage, entry->name);
|
||||||
auto res = PackageCache::StoreResult();
|
auto res = StorageCache::StoreResult();
|
||||||
auto lock = std::unique_lock(m_mutex);
|
auto lock = std::unique_lock(m_mutex);
|
||||||
auto &cacheEntry = m_packages.findOrCreate(ref);
|
auto &cacheEntry = m_entries.findOrCreate(ref);
|
||||||
if (cacheEntry.package) {
|
if (cacheEntry.entry) {
|
||||||
// retain certain information obtained from package contents if this is actually the same package as before
|
// retain certain information obtained from package contents if this is actually the same package as before
|
||||||
res.id = cacheEntry.id;
|
res.id = cacheEntry.id;
|
||||||
package->addDepsAndProvidesFromOtherPackage(*(res.oldPackage = cacheEntry.package));
|
entry->addDepsAndProvidesFromOtherPackage(*(res.oldEntry = cacheEntry.entry));
|
||||||
} else {
|
} else {
|
||||||
// check for package in storage
|
// check for package in storage
|
||||||
cacheEntry.package = std::make_shared<Package>();
|
cacheEntry.entry = std::make_shared<Entry>();
|
||||||
if ((cacheEntry.id = txn.get<0>(package->name, *cacheEntry.package))) {
|
if ((cacheEntry.id = txn.template get<0>(entry->name, *cacheEntry.entry))) {
|
||||||
package->addDepsAndProvidesFromOtherPackage(*(res.oldPackage = cacheEntry.package));
|
entry->addDepsAndProvidesFromOtherPackage(*(res.oldEntry = cacheEntry.entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// update cache entry
|
// update cache entry
|
||||||
cacheEntry.ref.packageName = &package->name;
|
cacheEntry.ref.entryName = &entry->name;
|
||||||
cacheEntry.package = package;
|
cacheEntry.entry = entry;
|
||||||
// update package in storage
|
// update package in storage
|
||||||
res.id = cacheEntry.id = txn.put(*package, cacheEntry.id);
|
res.id = cacheEntry.id = txn.put(*entry, cacheEntry.id);
|
||||||
res.updated = true;
|
res.updated = true;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PackageCache::invalidate(DatabaseStorage &databaseStorage, const std::string &packageName)
|
template <typename StorageEntriesType, typename TransactionType, typename SpecType>
|
||||||
|
bool StorageCache<StorageEntriesType, TransactionType, SpecType>::invalidate(Storage &storage, const std::string &entryName)
|
||||||
{
|
{
|
||||||
// remove package from cache
|
// remove package from cache
|
||||||
const auto ref = PackageCacheRef(databaseStorage, packageName);
|
const auto ref = typename Entries::Ref(storage, entryName);
|
||||||
auto lock = std::unique_lock(m_mutex);
|
auto lock = std::unique_lock(m_mutex);
|
||||||
m_packages.erase(ref);
|
m_entries.erase(ref);
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
// remove package from storage
|
// remove package from storage
|
||||||
auto txn = databaseStorage.packages.getRWTransaction();
|
auto txn = storage.packages.getRWTransaction();
|
||||||
if (auto i = txn.find<0>(packageName); i != txn.end()) {
|
if (auto i = txn.template find<0>(entryName); i != txn.end()) {
|
||||||
i.del();
|
i.del();
|
||||||
txn.commit();
|
txn.commit();
|
||||||
return true;
|
return true;
|
||||||
|
@ -109,30 +139,42 @@ bool PackageCache::invalidate(DatabaseStorage &databaseStorage, const std::strin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackageCache::clear(DatabaseStorage &databaseStorage)
|
template <typename StorageEntriesType, typename TransactionType, typename SpecType>
|
||||||
|
void StorageCache<StorageEntriesType, TransactionType, SpecType>::clear(Storage &storage)
|
||||||
{
|
{
|
||||||
clearCacheOnly(databaseStorage);
|
clearCacheOnly(storage);
|
||||||
auto packagesTxn = databaseStorage.packages.getRWTransaction();
|
auto packagesTxn = storage.packages.getRWTransaction();
|
||||||
packagesTxn.clear();
|
packagesTxn.clear();
|
||||||
packagesTxn.commit();
|
packagesTxn.commit();
|
||||||
auto providedDepsTxn = databaseStorage.providedDeps.getRWTransaction();
|
auto providedDepsTxn = storage.providedDeps.getRWTransaction();
|
||||||
providedDepsTxn.clear();
|
providedDepsTxn.clear();
|
||||||
providedDepsTxn.commit();
|
providedDepsTxn.commit();
|
||||||
auto requiredDepsTxn = databaseStorage.requiredDeps.getRWTransaction();
|
auto requiredDepsTxn = storage.requiredDeps.getRWTransaction();
|
||||||
requiredDepsTxn.clear();
|
requiredDepsTxn.clear();
|
||||||
requiredDepsTxn.commit();
|
requiredDepsTxn.commit();
|
||||||
auto providedLibsTxn = databaseStorage.providedLibs.getRWTransaction();
|
auto providedLibsTxn = storage.providedLibs.getRWTransaction();
|
||||||
providedLibsTxn.clear();
|
providedLibsTxn.clear();
|
||||||
providedLibsTxn.commit();
|
providedLibsTxn.commit();
|
||||||
auto requiredLibsTxn = databaseStorage.requiredLibs.getRWTransaction();
|
auto requiredLibsTxn = storage.requiredLibs.getRWTransaction();
|
||||||
requiredLibsTxn.clear();
|
requiredLibsTxn.clear();
|
||||||
requiredLibsTxn.commit();
|
requiredLibsTxn.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackageCache::clearCacheOnly(DatabaseStorage &databaseStorage)
|
template <typename StorageEntriesType, typename TransactionType, typename SpecType>
|
||||||
|
void StorageCache<StorageEntriesType, TransactionType, SpecType>::clearCacheOnly(Storage &storage)
|
||||||
{
|
{
|
||||||
const auto lock = std::unique_lock(m_mutex);
|
const auto lock = std::unique_lock(m_mutex);
|
||||||
m_packages.clear(databaseStorage);
|
m_entries.clear(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
template struct StorageCacheRef<DatabaseStorage, Package>;
|
||||||
|
template struct StorageCacheEntry<PackageCacheRef, Package>;
|
||||||
|
template class StorageCacheEntries<PackageCacheEntry>;
|
||||||
|
template struct StorageCache<PackageCacheEntries, PackageStorage::RWTransaction, PackageSpec>;
|
||||||
|
|
||||||
|
StorageDistribution::StorageDistribution(const char *path, std::uint32_t maxDbs)
|
||||||
|
{
|
||||||
|
m_env = LMDBSafe::getMDBEnv(path, MDB_NOSUBDIR, 0600, maxDbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseStorage::DatabaseStorage(const std::shared_ptr<LMDBSafe::MDBEnv> &env, PackageCache &packageCache, std::string_view uniqueDatabaseName)
|
DatabaseStorage::DatabaseStorage(const std::shared_ptr<LMDBSafe::MDBEnv> &env, PackageCache &packageCache, std::string_view uniqueDatabaseName)
|
||||||
|
@ -150,37 +192,7 @@ std::size_t hash_value(const PackageCacheRef &ref)
|
||||||
{
|
{
|
||||||
const auto hasher1 = boost::hash<const LibPkg::DatabaseStorage *>();
|
const auto hasher1 = boost::hash<const LibPkg::DatabaseStorage *>();
|
||||||
const auto hasher2 = boost::hash<std::string>();
|
const auto hasher2 = boost::hash<std::string>();
|
||||||
return ((hasher1(ref.databaseStorage) ^ (hasher2(*ref.packageName) << 1)) >> 1);
|
return ((hasher1(ref.relatedStorage) ^ (hasher2(*ref.entryName) << 1)) >> 1);
|
||||||
}
|
|
||||||
|
|
||||||
PackageCacheEntry &RecentlyUsedPackages::findOrCreate(const PackageCacheRef &ref)
|
|
||||||
{
|
|
||||||
const auto &index = m_packages.get<PackageCacheRef>();
|
|
||||||
if (auto i = index.find(ref); i != index.end()) {
|
|
||||||
m_packages.relocate(m_packages.begin(), m_packages.project<0>(i));
|
|
||||||
return i.get_node()->value();
|
|
||||||
}
|
|
||||||
const auto [i, newItem] = m_packages.emplace_front(ref);
|
|
||||||
if (!newItem) {
|
|
||||||
m_packages.relocate(m_packages.begin(), i);
|
|
||||||
} else if (m_packages.size() > m_limit) {
|
|
||||||
m_packages.pop_back();
|
|
||||||
}
|
|
||||||
return i.get_node()->value();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t RecentlyUsedPackages::clear(const DatabaseStorage &databaseStorage)
|
|
||||||
{
|
|
||||||
auto count = std::size_t();
|
|
||||||
for (auto i = m_packages.begin(); i != m_packages.end();) {
|
|
||||||
if (i->ref.databaseStorage == &databaseStorage) {
|
|
||||||
i = m_packages.erase(i);
|
|
||||||
++count;
|
|
||||||
} else {
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace LibPkg
|
} // namespace LibPkg
|
||||||
|
|
|
@ -18,132 +18,141 @@
|
||||||
namespace LibPkg {
|
namespace LibPkg {
|
||||||
|
|
||||||
using StorageID = std::uint32_t;
|
using StorageID = std::uint32_t;
|
||||||
using PackageStorage = LMDBSafe::TypedDBI<Package, LMDBSafe::index_on<Package, std::string, &Package::name>>;
|
|
||||||
using DependencyStorage = LMDBSafe::TypedDBI<DatabaseDependency, LMDBSafe::index_on<Dependency, std::string, &DatabaseDependency::name>>;
|
|
||||||
using LibraryDependencyStorage
|
|
||||||
= LMDBSafe::TypedDBI<DatabaseLibraryDependency, LMDBSafe::index_on<DatabaseLibraryDependency, std::string, &DatabaseLibraryDependency::name>>;
|
|
||||||
|
|
||||||
struct PackageCache;
|
template <typename StorageType, typename EntryType> struct StorageCacheRef {
|
||||||
|
using Storage = StorageType;
|
||||||
struct DatabaseStorage {
|
explicit StorageCacheRef(const StorageType &relatedStorage, const std::shared_ptr<EntryType> &entry);
|
||||||
explicit DatabaseStorage(const std::shared_ptr<LMDBSafe::MDBEnv> &env, PackageCache &packageCache, std::string_view uniqueDatabaseName);
|
explicit StorageCacheRef(const StorageType &relatedStorage, const std::string &entryName);
|
||||||
PackageCache &packageCache;
|
bool operator==(const StorageCacheRef &other) const;
|
||||||
PackageStorage packages;
|
const StorageType *relatedStorage = nullptr;
|
||||||
DependencyStorage providedDeps;
|
const std::string *entryName;
|
||||||
DependencyStorage requiredDeps;
|
|
||||||
LibraryDependencyStorage providedLibs;
|
|
||||||
LibraryDependencyStorage requiredLibs;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<LMDBSafe::MDBEnv> m_env;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PackageCacheRef {
|
template <typename StorageType, typename EntryType>
|
||||||
explicit PackageCacheRef(const DatabaseStorage &databaseStorage, const std::shared_ptr<Package> &package);
|
inline StorageCacheRef<StorageType, EntryType>::StorageCacheRef(const StorageType &relatedStorage, const std::shared_ptr<EntryType> &entry)
|
||||||
explicit PackageCacheRef(const DatabaseStorage &databaseStorage, const std::string &packageName);
|
: relatedStorage(&relatedStorage)
|
||||||
bool operator==(const PackageCacheRef &other) const;
|
, entryName(&entry->name)
|
||||||
const DatabaseStorage *databaseStorage = nullptr;
|
|
||||||
const std::string *packageName;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline PackageCacheRef::PackageCacheRef(const DatabaseStorage &databaseStorage, const std::shared_ptr<Package> &package)
|
|
||||||
: databaseStorage(&databaseStorage)
|
|
||||||
, packageName(&package->name)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PackageCacheRef::PackageCacheRef(const DatabaseStorage &databaseStorage, const std::string &packageName)
|
template <typename StorageType, typename EntryType>
|
||||||
: databaseStorage(&databaseStorage)
|
inline StorageCacheRef<StorageType, EntryType>::StorageCacheRef(const StorageType &relatedStorage, const std::string &entryName)
|
||||||
, packageName(&packageName)
|
: relatedStorage(&relatedStorage)
|
||||||
|
, entryName(&entryName)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool PackageCacheRef::operator==(const PackageCacheRef &other) const
|
template <typename StorageType, typename EntryType>
|
||||||
|
inline bool StorageCacheRef<StorageType, EntryType>::operator==(const StorageCacheRef<StorageType, EntryType> &other) const
|
||||||
{
|
{
|
||||||
return databaseStorage == other.databaseStorage && *packageName == *other.packageName;
|
return relatedStorage == other.relatedStorage && *entryName == *other.entryName;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t hash_value(const PackageCacheRef &ref);
|
template <typename StorageRefType, typename EntryType> struct StorageCacheEntry {
|
||||||
|
using Ref = StorageRefType;
|
||||||
struct PackageCacheEntry {
|
using Entry = EntryType;
|
||||||
explicit PackageCacheEntry(const PackageCacheRef &ref);
|
using Storage = typename Ref::Storage;
|
||||||
PackageCacheRef ref;
|
explicit StorageCacheEntry(const StorageRefType &ref);
|
||||||
|
StorageRefType ref;
|
||||||
StorageID id;
|
StorageID id;
|
||||||
std::shared_ptr<Package> package;
|
std::shared_ptr<EntryType> entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline PackageCacheEntry::PackageCacheEntry(const PackageCacheRef &ref)
|
template <typename StorageRefType, typename EntryType>
|
||||||
|
inline StorageCacheEntry<StorageRefType, EntryType>::StorageCacheEntry(const StorageRefType &ref)
|
||||||
: ref(ref)
|
: ref(ref)
|
||||||
, id(0)
|
, id(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
class RecentlyUsedPackages {
|
template <typename StorageEntryType> class StorageCacheEntries {
|
||||||
using PackageList = boost::multi_index::multi_index_container<PackageCacheEntry,
|
|
||||||
boost::multi_index::indexed_by<boost::multi_index::sequenced<>,
|
|
||||||
boost::multi_index::hashed_unique<boost::multi_index::tag<PackageCacheRef>,
|
|
||||||
BOOST_MULTI_INDEX_MEMBER(PackageCacheEntry, PackageCacheRef, ref)>>>;
|
|
||||||
using iterator = PackageList::iterator;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RecentlyUsedPackages(std::size_t limit = 1000);
|
using Ref = typename StorageEntryType::Ref;
|
||||||
|
using Entry = typename StorageEntryType::Entry;
|
||||||
|
using Storage = typename StorageEntryType::Storage;
|
||||||
|
using StorageEntry = StorageEntryType;
|
||||||
|
using EntryList = boost::multi_index::multi_index_container<StorageEntry,
|
||||||
|
boost::multi_index::indexed_by<boost::multi_index::sequenced<>,
|
||||||
|
boost::multi_index::hashed_unique<boost::multi_index::tag<Ref>, BOOST_MULTI_INDEX_MEMBER(StorageEntryType, Ref, ref)>>>;
|
||||||
|
using iterator = typename EntryList::iterator;
|
||||||
|
|
||||||
PackageCacheEntry &findOrCreate(const PackageCacheRef &ref);
|
explicit StorageCacheEntries(std::size_t limit = 1000);
|
||||||
|
|
||||||
|
StorageEntry &findOrCreate(const Ref &ref);
|
||||||
void undo();
|
void undo();
|
||||||
std::size_t erase(const PackageCacheRef &ref);
|
std::size_t erase(const Ref &ref);
|
||||||
std::size_t clear(const DatabaseStorage &databaseStorage);
|
std::size_t clear(const Storage &storage);
|
||||||
iterator begin();
|
iterator begin();
|
||||||
iterator end();
|
iterator end();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PackageList m_packages;
|
EntryList m_entries;
|
||||||
std::size_t m_limit;
|
std::size_t m_limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline RecentlyUsedPackages::RecentlyUsedPackages(std::size_t limit)
|
template <typename StorageEntryType>
|
||||||
|
inline StorageCacheEntries<StorageEntryType>::StorageCacheEntries(std::size_t limit)
|
||||||
: m_limit(limit)
|
: m_limit(limit)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void RecentlyUsedPackages::undo()
|
template <typename StorageEntryType> inline void StorageCacheEntries<StorageEntryType>::undo()
|
||||||
{
|
{
|
||||||
m_packages.pop_front();
|
m_entries.pop_front();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::size_t RecentlyUsedPackages::erase(const PackageCacheRef &ref)
|
template <typename StorageEntryType> inline std::size_t StorageCacheEntries<StorageEntryType>::erase(const Ref &ref)
|
||||||
{
|
{
|
||||||
return m_packages.get<PackageCacheRef>().erase(ref);
|
return m_entries.template get<typename StorageEntryType::Ref>().erase(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RecentlyUsedPackages::iterator RecentlyUsedPackages::begin()
|
template <typename StorageEntryType> inline auto StorageCacheEntries<StorageEntryType>::begin() -> iterator
|
||||||
{
|
{
|
||||||
return m_packages.begin();
|
return m_entries.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline RecentlyUsedPackages::iterator RecentlyUsedPackages::end()
|
template <typename StorageEntryType> inline auto StorageCacheEntries<StorageEntryType>::end() -> iterator
|
||||||
{
|
{
|
||||||
return m_packages.end();
|
return m_entries.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PackageCache {
|
template <typename StorageEntriesType, typename TransactionType, typename SpecType> struct StorageCache {
|
||||||
|
using Entries = StorageEntriesType;
|
||||||
|
using Entry = typename Entries::Entry;
|
||||||
|
using Txn = TransactionType;
|
||||||
|
using Storage = typename Entries::Storage;
|
||||||
struct StoreResult {
|
struct StoreResult {
|
||||||
StorageID id = 0;
|
StorageID id = 0;
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
std::shared_ptr<Package> oldPackage;
|
std::shared_ptr<typename Entries::Entry> oldEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
PackageSpec retrieve(DatabaseStorage &databaseStorage, const std::string &packageName);
|
SpecType retrieve(Storage &storage, const std::string &entryName);
|
||||||
StoreResult store(DatabaseStorage &databaseStorage, const std::shared_ptr<Package> &package, bool force);
|
StoreResult store(Storage &storage, const std::shared_ptr<Entry> &entry, bool force);
|
||||||
StoreResult store(DatabaseStorage &databaseStorage, PackageStorage::RWTransaction &txn, const std::shared_ptr<Package> &package);
|
StoreResult store(Storage &storage, Txn &txn, const std::shared_ptr<Entry> &entry);
|
||||||
bool invalidate(DatabaseStorage &databaseStorage, const std::string &packageName);
|
bool invalidate(Storage &storage, const std::string &entryName);
|
||||||
void clear(DatabaseStorage &databaseStorage);
|
void clear(Storage &storage);
|
||||||
void clearCacheOnly(DatabaseStorage &databaseStorage);
|
void clearCacheOnly(Storage &storage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RecentlyUsedPackages m_packages;
|
Entries m_entries;
|
||||||
std::mutex m_mutex;
|
std::mutex m_mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PackageStorage = LMDBSafe::TypedDBI<Package, LMDBSafe::index_on<Package, std::string, &Package::name>>;
|
||||||
|
using DependencyStorage = LMDBSafe::TypedDBI<DatabaseDependency, LMDBSafe::index_on<Dependency, std::string, &DatabaseDependency::name>>;
|
||||||
|
using LibraryDependencyStorage
|
||||||
|
= LMDBSafe::TypedDBI<DatabaseLibraryDependency, LMDBSafe::index_on<DatabaseLibraryDependency, std::string, &DatabaseLibraryDependency::name>>;
|
||||||
|
using PackageCacheRef = StorageCacheRef<DatabaseStorage, Package>;
|
||||||
|
using PackageCacheEntry = StorageCacheEntry<PackageCacheRef, Package>;
|
||||||
|
using PackageCacheEntries = StorageCacheEntries<PackageCacheEntry>;
|
||||||
|
using PackageCache = StorageCache<PackageCacheEntries, PackageStorage::RWTransaction, PackageSpec>;
|
||||||
|
|
||||||
|
extern template struct StorageCacheRef<DatabaseStorage, Package>;
|
||||||
|
extern template struct StorageCacheEntry<PackageCacheRef, Package>;
|
||||||
|
extern template class StorageCacheEntries<PackageCacheEntry>;
|
||||||
|
extern template struct StorageCache<PackageCacheEntries, PackageStorage::RWTransaction, PackageSpec>;
|
||||||
|
|
||||||
struct StorageDistribution {
|
struct StorageDistribution {
|
||||||
explicit StorageDistribution(const char *path, std::uint32_t maxDbs);
|
explicit StorageDistribution(const char *path, std::uint32_t maxDbs);
|
||||||
|
|
||||||
|
@ -159,6 +168,21 @@ inline std::unique_ptr<DatabaseStorage> StorageDistribution::forDatabase(std::st
|
||||||
return std::make_unique<DatabaseStorage>(m_env, m_packageCache, uniqueDatabaseName);
|
return std::make_unique<DatabaseStorage>(m_env, m_packageCache, uniqueDatabaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DatabaseStorage {
|
||||||
|
explicit DatabaseStorage(const std::shared_ptr<LMDBSafe::MDBEnv> &env, PackageCache &packageCache, std::string_view uniqueDatabaseName);
|
||||||
|
PackageCache &packageCache;
|
||||||
|
PackageStorage packages;
|
||||||
|
DependencyStorage providedDeps;
|
||||||
|
DependencyStorage requiredDeps;
|
||||||
|
LibraryDependencyStorage providedLibs;
|
||||||
|
LibraryDependencyStorage requiredLibs;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<LMDBSafe::MDBEnv> m_env;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t hash_value(const PackageCacheRef &ref);
|
||||||
|
|
||||||
} // namespace LibPkg
|
} // namespace LibPkg
|
||||||
|
|
||||||
#endif // LIBPKG_DATA_STORAGE_PRIVATE_H
|
#endif // LIBPKG_DATA_STORAGE_PRIVATE_H
|
||||||
|
|
Loading…
Reference in New Issue