Skip to content

Commit

Permalink
State Object Registry: added Purge method
Browse files Browse the repository at this point in the history
  • Loading branch information
TheMostDiligent committed Sep 1, 2023
1 parent dd31824 commit de4c62d
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 8 deletions.
66 changes: 60 additions & 6 deletions Common/interface/ObjectsRegistry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <mutex>
#include <memory>
#include <algorithm>
#include <atomic>

#include "../../../DiligentCore/Platforms/Basic/interface/DebugUtilities.hpp"
#include "RefCntAutoPtr.hpp"
Expand Down Expand Up @@ -57,6 +58,19 @@ auto _LockWeakPtr(std::weak_ptr<T>& pWeakPtr)
return pWeakPtr.lock();
}


template <typename T>
auto _IsWeakPtrExpired(RefCntWeakPtr<T>& pWeakPtr)
{
return !pWeakPtr.IsValid();
}

template <typename T>
auto _IsWeakPtrExpired(std::weak_ptr<T>& pWeakPtr)
{
return pWeakPtr.expired();
}

/// A thread-safe and exception-safe object registry that works with std::shared_ptr or RefCntAutoPtr.
/// The registry keeps weak pointers to the objects and returns strong pointers if the requested object exits.
/// An application should keep strong pointers to the objects to keep them alive.
Expand Down Expand Up @@ -102,7 +116,8 @@ class ObjectsRegistry
public:
using WeakPtrType = typename _StrongPtrHelper<StrongPtrType>::WeakPtrType;

ObjectsRegistry() noexcept
explicit ObjectsRegistry(Uint32 NumRequestsToPurge = 1024) noexcept :
m_NumRequestsToPurge{NumRequestsToPurge}
{}

/// Finds the object in the registry and returns strong pointer to it (std::shared_ptr or RefCntAutoPtr).
Expand All @@ -129,7 +144,7 @@ class ObjectsRegistry
// while we keep one, even if it is popped from the registry by another thread.
std::shared_ptr<ObjectWrapper> pObjectWrpr;
{
std::lock_guard<std::mutex> Lock{m_CacheMtx};
std::lock_guard<std::mutex> Guard{m_CacheMtx};

auto it = m_Cache.find(Key);
if (it == m_Cache.end())
Expand All @@ -146,7 +161,7 @@ class ObjectsRegistry
}
catch (...)
{
std::lock_guard<std::mutex> Lock{m_CacheMtx};
std::lock_guard<std::mutex> Guard{m_CacheMtx};

auto it = m_Cache.find(Key);
if (it != m_Cache.end())
Expand All @@ -167,7 +182,7 @@ class ObjectsRegistry
}

{
std::lock_guard<std::mutex> Lock{m_CacheMtx};
std::lock_guard<std::mutex> Guard{m_CacheMtx};

auto it = m_Cache.find(Key);
if (pObject)
Expand All @@ -189,6 +204,9 @@ class ObjectsRegistry
m_Cache.erase(it);
}
}

if (m_NumRequestsSinceLastPurge.fetch_add(1) + 1 >= m_NumRequestsToPurge)
PurgeUnguarded();
}

return pObject;
Expand All @@ -203,7 +221,10 @@ class ObjectsRegistry
/// or empty pointer otherwise.
StrongPtrType Get(const KeyType& Key)
{
std::lock_guard<std::mutex> Lock{m_CacheMtx};
std::lock_guard<std::mutex> Guard{m_CacheMtx};

if (m_NumRequestsSinceLastPurge.fetch_add(1) + 1 >= m_NumRequestsToPurge)
PurgeUnguarded();

auto it = m_Cache.find(Key);
if (it != m_Cache.end())
Expand All @@ -222,6 +243,13 @@ class ObjectsRegistry
return {};
}

/// Removes all expired pointers from the cache
void Purge()
{
std::lock_guard<std::mutex> Guard{m_CacheMtx};
PurgeUnguarded();
}

private:
class ObjectWrapper
{
Expand All @@ -231,7 +259,7 @@ class ObjectsRegistry
{
StrongPtrType pObject;

std::lock_guard<std::mutex> Lock{m_CreateObjectMtx};
std::lock_guard<std::mutex> Guard{m_CreateObjectMtx};
pObject = _LockWeakPtr(m_wpObject);
if (!pObject)
{
Expand All @@ -247,14 +275,40 @@ class ObjectsRegistry
return _LockWeakPtr(m_wpObject);
}

bool IsExpired()
{
return _IsWeakPtrExpired(m_wpObject);
}

private:
std::mutex m_CreateObjectMtx;
WeakPtrType m_wpObject;
};

void PurgeUnguarded()
{
for (auto it = m_Cache.begin(); it != m_Cache.end();)
{
if (it->second->IsExpired())
{
it = m_Cache.erase(it);
}
else
{
++it;
}
}

m_NumRequestsSinceLastPurge.store(0);
}

private:
using CacheType = std::unordered_map<KeyType, std::shared_ptr<ObjectWrapper>, KeyHasher, KeyEqual>;

const Uint32 m_NumRequestsToPurge;

std::atomic<Uint32> m_NumRequestsSinceLastPurge{0};

std::mutex m_CacheMtx;
CacheType m_Cache;
};
Expand Down
4 changes: 2 additions & 2 deletions Tests/DiligentCoreTest/src/Common/ObjectsRegistryTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ TEST(Common_ObjectsRegistry, Get_RefCntAutoPtr)
template <template <typename T> class StrongPtrType, typename DataType>
void TestObjectRegistryCreateDestroyRace()
{
ObjectsRegistry<int, StrongPtrType<DataType>> Registry;
ObjectsRegistry<int, StrongPtrType<DataType>> Registry{64};

constexpr Uint32 NumThreads = 16;
std::vector<std::thread> Threads(NumThreads);
Expand Down Expand Up @@ -172,7 +172,7 @@ TEST(Common_ObjectsRegistry, CreateDestroyRace_RefCntAutoPtr)
template <template <typename T> class StrongPtrType, typename DataType>
void TestObjectRegistryExceptions()
{
ObjectsRegistry<int, StrongPtrType<DataType>> Registry;
ObjectsRegistry<int, StrongPtrType<DataType>> Registry{128};

constexpr Uint32 NumThreads = 15; // Use odd number
std::vector<std::thread> Threads(NumThreads);
Expand Down

0 comments on commit de4c62d

Please sign in to comment.