Merge pull request #8364 from Icinga/bugfix/configsyncstagelock-unlock-owner-213

Make ApiListener::m_ConfigSyncStageLock a SpinLock
This commit is contained in:
Alexander Aleksandrovič Klimov 2020-10-14 16:01:00 +02:00 committed by GitHub
commit 4bb6f4c910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 5 deletions

View File

@ -64,6 +64,7 @@ set(base_SOURCES
shared-object.hpp
singleton.hpp
socket.cpp socket.hpp
spinlock.cpp spinlock.hpp
stacktrace.cpp stacktrace.hpp
statsfunction.hpp
stdiostream.cpp stdiostream.hpp

22
lib/base/spinlock.cpp Normal file
View File

@ -0,0 +1,22 @@
/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */
#include "base/spinlock.hpp"
#include <atomic>
using namespace icinga;
void SpinLock::lock()
{
while (m_Locked.test_and_set(std::memory_order_acquire)) {
}
}
bool SpinLock::try_lock()
{
return !m_Locked.test_and_set(std::memory_order_acquire);
}
void SpinLock::unlock()
{
m_Locked.clear(std::memory_order_release);
}

35
lib/base/spinlock.hpp Normal file
View File

@ -0,0 +1,35 @@
/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */
#ifndef SPINLOCK_H
#define SPINLOCK_H
#include <atomic>
namespace icinga
{
/**
* A spin lock.
*
* @ingroup base
*/
class SpinLock
{
public:
SpinLock() = default;
SpinLock(const SpinLock&) = delete;
SpinLock& operator=(const SpinLock&) = delete;
SpinLock(SpinLock&&) = delete;
SpinLock& operator=(SpinLock&&) = delete;
void lock();
bool try_lock();
void unlock();
private:
std::atomic_flag m_Locked = ATOMIC_FLAG_INIT;
};
}
#endif /* SPINLOCK_H */

View File

@ -20,7 +20,7 @@ using namespace icinga;
REGISTER_APIFUNCTION(Update, config, &ApiListener::ConfigUpdateHandler);
boost::mutex ApiListener::m_ConfigSyncStageLock;
SpinLock ApiListener::m_ConfigSyncStageLock;
/**
* Entrypoint for updating all authoritative configs from /etc/zones.d, packages, etc.
@ -330,7 +330,7 @@ void ApiListener::HandleConfigUpdate(const MessageOrigin::Ptr& origin, const Dic
/* Only one transaction is allowed, concurrent message handlers need to wait.
* This affects two parent endpoints sending the config in the same moment.
*/
auto lock (Shared<boost::mutex::scoped_lock>::Make(m_ConfigSyncStageLock));
auto lock (Shared<std::unique_lock<SpinLock>>::Make(m_ConfigSyncStageLock));
String apiZonesStageDir = GetApiZonesStageDir();
String fromEndpointName = origin->FromClient->GetEndpoint()->GetName();
@ -627,7 +627,7 @@ void ApiListener::TryActivateZonesStageCallback(const ProcessResult& pr,
*
* @param relativePaths Required for later file operations in the callback. Provides the zone name plus path in a list.
*/
void ApiListener::AsyncTryActivateZonesStage(const std::vector<String>& relativePaths, const Shared<boost::mutex::scoped_lock>::Ptr& lock)
void ApiListener::AsyncTryActivateZonesStage(const std::vector<String>& relativePaths, const Shared<std::unique_lock<SpinLock>>::Ptr& lock)
{
VERIFY(Application::GetArgC() >= 1);

View File

@ -11,6 +11,7 @@
#include "base/configobject.hpp"
#include "base/process.hpp"
#include "base/shared.hpp"
#include "base/spinlock.hpp"
#include "base/timer.hpp"
#include "base/workqueue.hpp"
#include "base/tcpsocket.hpp"
@ -21,6 +22,7 @@
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/ssl/context.hpp>
#include <mutex>
#include <set>
namespace icinga
@ -186,7 +188,7 @@ private:
void RemoveStatusFile();
/* filesync */
static boost::mutex m_ConfigSyncStageLock;
static SpinLock m_ConfigSyncStageLock;
void SyncLocalZoneDirs() const;
void SyncLocalZoneDir(const Zone::Ptr& zone) const;
@ -200,7 +202,7 @@ private:
static void TryActivateZonesStageCallback(const ProcessResult& pr,
const std::vector<String>& relativePaths);
static void AsyncTryActivateZonesStage(const std::vector<String>& relativePaths, const Shared<boost::mutex::scoped_lock>::Ptr& lock);
static void AsyncTryActivateZonesStage(const std::vector<String>& relativePaths, const Shared<std::unique_lock<SpinLock>>::Ptr& lock);
static String GetChecksum(const String& content);
static bool CheckConfigChange(const ConfigDirInformation& oldConfig, const ConfigDirInformation& newConfig);