Implement helper functions for async global locks
This commit is contained in:
parent
e74f80a089
commit
8dfa948e03
|
@ -11,7 +11,9 @@ set(META_VERSION_MAJOR 0)
|
||||||
set(META_VERSION_MINOR 0)
|
set(META_VERSION_MINOR 0)
|
||||||
set(META_VERSION_PATCH 3)
|
set(META_VERSION_PATCH 3)
|
||||||
set(META_VERSION_EXACT_SONAME ON)
|
set(META_VERSION_EXACT_SONAME ON)
|
||||||
set(META_CXX_STANDARD 20)
|
#set(META_CXX_STANDARD 20)
|
||||||
|
set(META_CXX_STANDARD "any")
|
||||||
|
list(APPEND META_PUBLIC_COMPILE_OPTIONS "-std=c++2b")
|
||||||
|
|
||||||
project(${META_PROJECT_NAME})
|
project(${META_PROJECT_NAME})
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,12 @@ struct LogContext;
|
||||||
struct GlobalSharedMutex {
|
struct GlobalSharedMutex {
|
||||||
void lock();
|
void lock();
|
||||||
bool try_lock();
|
bool try_lock();
|
||||||
void lock_async(std::function<void()> &&callback);
|
void lock_async(std::move_only_function<void()> &&callback);
|
||||||
void unlock();
|
void unlock();
|
||||||
|
|
||||||
void lock_shared();
|
void lock_shared();
|
||||||
bool try_lock_shared();
|
bool try_lock_shared();
|
||||||
void lock_shared_async(std::function<void()> &&callback);
|
void lock_shared_async(std::move_only_function<void()> &&callback);
|
||||||
void unlock_shared();
|
void unlock_shared();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -33,8 +33,8 @@ private:
|
||||||
std::condition_variable m_cv;
|
std::condition_variable m_cv;
|
||||||
std::uint32_t m_sharedOwners = 0;
|
std::uint32_t m_sharedOwners = 0;
|
||||||
bool m_exclusivelyOwned = false;
|
bool m_exclusivelyOwned = false;
|
||||||
std::list<std::function<void()>> m_sharedCallbacks;
|
std::list<std::move_only_function<void()>> m_sharedCallbacks;
|
||||||
std::function<void()> m_exclusiveCallback;
|
std::move_only_function<void()> m_exclusiveCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void GlobalSharedMutex::lock()
|
inline void GlobalSharedMutex::lock()
|
||||||
|
@ -56,7 +56,7 @@ inline bool GlobalSharedMutex::try_lock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void GlobalSharedMutex::lock_async(std::function<void()> &&callback)
|
inline void GlobalSharedMutex::lock_async(std::move_only_function<void()> &&callback)
|
||||||
{
|
{
|
||||||
auto lock = std::unique_lock<std::mutex>(m_mutex);
|
auto lock = std::unique_lock<std::mutex>(m_mutex);
|
||||||
if (m_sharedOwners || m_exclusivelyOwned) {
|
if (m_sharedOwners || m_exclusivelyOwned) {
|
||||||
|
@ -94,7 +94,7 @@ inline bool GlobalSharedMutex::try_lock_shared()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void GlobalSharedMutex::lock_shared_async(std::function<void()> &&callback)
|
inline void GlobalSharedMutex::lock_shared_async(std::move_only_function<void()> &&callback)
|
||||||
{
|
{
|
||||||
auto lock = std::unique_lock<std::mutex>(m_mutex);
|
auto lock = std::unique_lock<std::mutex>(m_mutex);
|
||||||
if (m_exclusivelyOwned) {
|
if (m_exclusivelyOwned) {
|
||||||
|
@ -143,7 +143,9 @@ inline void GlobalSharedMutex::notify(std::unique_lock<std::mutex> &lock)
|
||||||
|
|
||||||
/// \brief A wrapper around a standard lock which logs acquisition/release.
|
/// \brief A wrapper around a standard lock which logs acquisition/release.
|
||||||
template <typename UnderlyingLockType> struct LoggingLock {
|
template <typename UnderlyingLockType> struct LoggingLock {
|
||||||
template <typename... Args> LoggingLock(LogContext &log, std::string &&name, Args &&...args);
|
using LockType = UnderlyingLockType;
|
||||||
|
explicit LoggingLock(LogContext &log, std::string &&name);
|
||||||
|
template <typename... Args> explicit LoggingLock(LogContext &log, std::string &&name, Args &&...args);
|
||||||
LoggingLock(LoggingLock &&) = default;
|
LoggingLock(LoggingLock &&) = default;
|
||||||
~LoggingLock();
|
~LoggingLock();
|
||||||
|
|
||||||
|
@ -171,6 +173,14 @@ constexpr std::string_view lockName(std::unique_lock<GlobalSharedMutex> &)
|
||||||
return "exclusive";
|
return "exclusive";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename UnderlyingLockType>
|
||||||
|
inline LoggingLock<UnderlyingLockType>::LoggingLock(LogContext &log, std::string &&name)
|
||||||
|
: m_log(log)
|
||||||
|
, m_name(std::move(name))
|
||||||
|
{
|
||||||
|
m_log("Acquiring ", lockName(m_lock), " lock \"", m_name, "\"\n");
|
||||||
|
}
|
||||||
|
|
||||||
template <typename UnderlyingLockType>
|
template <typename UnderlyingLockType>
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline LoggingLock<UnderlyingLockType>::LoggingLock(LogContext &log, std::string &&name, Args &&...args)
|
inline LoggingLock<UnderlyingLockType>::LoggingLock(LogContext &log, std::string &&name, Args &&...args)
|
||||||
|
@ -202,6 +212,8 @@ struct GlobalLockable {
|
||||||
[[nodiscard]] SharedLoggingLock tryLockToRead(LogContext &log, std::string &&name) const;
|
[[nodiscard]] SharedLoggingLock tryLockToRead(LogContext &log, std::string &&name) const;
|
||||||
[[nodiscard]] UniqueLoggingLock tryLockToWrite(LogContext &log, std::string &&name);
|
[[nodiscard]] UniqueLoggingLock tryLockToWrite(LogContext &log, std::string &&name);
|
||||||
[[nodiscard]] UniqueLoggingLock lockToWrite(LogContext &log, std::string &&name, SharedLoggingLock &readLock);
|
[[nodiscard]] UniqueLoggingLock lockToWrite(LogContext &log, std::string &&name, SharedLoggingLock &readLock);
|
||||||
|
void lockToRead(LogContext &log, std::string &&name, std::move_only_function<void(SharedLoggingLock &&lock)> &&callback) const;
|
||||||
|
void lockToWrite(LogContext &log, std::string &&name, std::move_only_function<void(UniqueLoggingLock &&lock)> &&callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable GlobalSharedMutex m_mutex;
|
mutable GlobalSharedMutex m_mutex;
|
||||||
|
@ -233,6 +245,24 @@ inline UniqueLoggingLock GlobalLockable::lockToWrite(LogContext &log, std::strin
|
||||||
return UniqueLoggingLock(log, std::move(name), m_mutex);
|
return UniqueLoggingLock(log, std::move(name), m_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void LibRepoMgr::GlobalLockable::lockToRead(
|
||||||
|
LogContext &log, std::string &&name, std::move_only_function<void(SharedLoggingLock &&)> &&callback) const
|
||||||
|
{
|
||||||
|
m_mutex.lock_shared_async([this, lock = SharedLoggingLock(log, std::move(name)), cb = std::move(callback)]() mutable {
|
||||||
|
lock.lock() = SharedLoggingLock::LockType(m_mutex, std::adopt_lock);
|
||||||
|
cb(std::move(lock));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void LibRepoMgr::GlobalLockable::lockToWrite(
|
||||||
|
LogContext &log, std::string &&name, std::move_only_function<void(UniqueLoggingLock &&)> &&callback)
|
||||||
|
{
|
||||||
|
m_mutex.lock_async([this, lock = UniqueLoggingLock(log, std::move(name)), cb = std::move(callback)]() mutable {
|
||||||
|
lock.lock() = UniqueLoggingLock::LockType(m_mutex, std::adopt_lock);
|
||||||
|
cb(std::move(lock));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace LibRepoMgr
|
} // namespace LibRepoMgr
|
||||||
|
|
||||||
#endif // LIBREPOMGR_GLOBAL_LOCK_H
|
#endif // LIBREPOMGR_GLOBAL_LOCK_H
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <boost/asio/ip/address.hpp>
|
#include <boost/asio/ip/address.hpp>
|
||||||
#include <boost/asio/ssl/context.hpp>
|
#include <boost/asio/ssl/context.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -178,6 +179,8 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable {
|
||||||
[[nodiscard]] SharedLoggingLock acquireToRead(LogContext &log, std::string &&lockName);
|
[[nodiscard]] SharedLoggingLock acquireToRead(LogContext &log, std::string &&lockName);
|
||||||
[[nodiscard]] UniqueLoggingLock acquireToWrite(LogContext &log, std::string &&lockName);
|
[[nodiscard]] UniqueLoggingLock acquireToWrite(LogContext &log, std::string &&lockName);
|
||||||
[[nodiscard]] std::pair<LockTable *, std::unique_lock<std::shared_mutex>> acquireLockTable();
|
[[nodiscard]] std::pair<LockTable *, std::unique_lock<std::shared_mutex>> acquireLockTable();
|
||||||
|
void acquireToRead(LogContext &log, std::string &&name, std::move_only_function<void(SharedLoggingLock &&lock)> &&callback);
|
||||||
|
void acquireToWrite(LogContext &log, std::string &&name, std::move_only_function<void(UniqueLoggingLock &&lock)> &&callback);
|
||||||
void clear();
|
void clear();
|
||||||
static std::string forDatabase(std::string_view dbName, std::string_view dbArch);
|
static std::string forDatabase(std::string_view dbName, std::string_view dbArch);
|
||||||
static std::string forDatabase(const LibPkg::Database &db);
|
static std::string forDatabase(const LibPkg::Database &db);
|
||||||
|
@ -217,6 +220,20 @@ inline UniqueLoggingLock ServiceSetup::Locks::acquireToWrite(LogContext &log, st
|
||||||
return namedLock(lockName).lockToWrite(log, std::move(lockName));
|
return namedLock(lockName).lockToWrite(log, std::move(lockName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void ServiceSetup::Locks::acquireToRead(
|
||||||
|
LogContext &log, std::string &&lockName, std::move_only_function<void(SharedLoggingLock &&lock)> &&callback)
|
||||||
|
{
|
||||||
|
const auto locktableLock = std::shared_lock(m_cleanupMutex);
|
||||||
|
namedLock(lockName).lockToRead(log, std::move(lockName), std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void ServiceSetup::Locks::acquireToWrite(
|
||||||
|
LogContext &log, std::string &&lockName, std::move_only_function<void(UniqueLoggingLock &&lock)> &&callback)
|
||||||
|
{
|
||||||
|
const auto locktableLock = std::shared_lock(m_cleanupMutex);
|
||||||
|
namedLock(lockName).lockToWrite(log, std::move(lockName), std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
inline std::pair<ServiceSetup::Locks::LockTable *, std::unique_lock<std::shared_mutex>> ServiceSetup::Locks::acquireLockTable()
|
inline std::pair<ServiceSetup::Locks::LockTable *, std::unique_lock<std::shared_mutex>> ServiceSetup::Locks::acquireLockTable()
|
||||||
{
|
{
|
||||||
return std::make_pair(&m_locksByName, std::unique_lock(m_cleanupMutex));
|
return std::make_pair(&m_locksByName, std::unique_lock(m_cleanupMutex));
|
||||||
|
|
Loading…
Reference in New Issue