mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-19 16:16:48 +00:00
Guard branch snapshots with shared_mutex
Important changes: - Replace atomic shared_ptr operations with shared_mutex-protected snapshots. - Retry copy-on-write branch updates when another writer publishes first. - Keep long-running parsing and read-only filesystem checks outside branch locks.
This commit is contained in:
committed by
trapexit
parent
608cd00764
commit
8734847968
+68
-28
@@ -28,8 +28,10 @@
|
||||
#include "str.hpp"
|
||||
#include "syslog.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
@@ -437,24 +439,44 @@ Branches::from_string(const std::string_view str_)
|
||||
Branches::Ptr impl;
|
||||
Branches::Ptr new_impl;
|
||||
|
||||
impl = std::atomic_load(&_impl);
|
||||
|
||||
new_impl = std::make_shared<Branches::Impl>(&minfreespace);
|
||||
*new_impl = *impl;
|
||||
|
||||
rv = new_impl->from_string(str_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
for(;;)
|
||||
{
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lk(_mutex);
|
||||
impl = _impl;
|
||||
}
|
||||
|
||||
std::atomic_store(&_impl,new_impl);
|
||||
*new_impl = *impl;
|
||||
|
||||
return 0;
|
||||
rv = new_impl->from_string(str_);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lk(_mutex);
|
||||
if(impl != _impl)
|
||||
continue;
|
||||
|
||||
_impl = std::move(new_impl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Branches::to_string(void) const
|
||||
{
|
||||
return std::atomic_load(&_impl)->to_string();
|
||||
Branches::Ptr impl;
|
||||
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lk(_mutex);
|
||||
impl = _impl;
|
||||
}
|
||||
|
||||
return impl->to_string();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -462,32 +484,50 @@ Branches::find_and_set_mode_ro()
|
||||
{
|
||||
Branches::Ptr impl;
|
||||
Branches::Ptr new_impl;
|
||||
std::vector<fs::path> ro_paths;
|
||||
|
||||
impl = std::atomic_load(&_impl);
|
||||
new_impl = std::make_shared<Branches::Impl>(&minfreespace);
|
||||
|
||||
*new_impl = *impl;
|
||||
|
||||
bool changed = false;
|
||||
for(auto &branch : *new_impl)
|
||||
for(;;)
|
||||
{
|
||||
if(branch.mode != Branch::Mode::RW)
|
||||
continue;
|
||||
ro_paths.clear();
|
||||
|
||||
if(!fs::is_rofs_but_not_mounted_ro(branch.path))
|
||||
continue;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lk(_mutex);
|
||||
impl = _impl;
|
||||
}
|
||||
|
||||
SysLog::warning("branch `{}` found to be readonly - setting its mode=RO",
|
||||
branch.path.string());
|
||||
*new_impl = *impl;
|
||||
|
||||
branch.mode = Branch::Mode::RO;
|
||||
changed = true;
|
||||
for(auto &branch : *new_impl)
|
||||
{
|
||||
if(branch.mode != Branch::Mode::RW)
|
||||
continue;
|
||||
|
||||
if(!fs::is_rofs_but_not_mounted_ro(branch.path))
|
||||
continue;
|
||||
|
||||
branch.mode = Branch::Mode::RO;
|
||||
ro_paths.emplace_back(branch.path);
|
||||
}
|
||||
|
||||
if(ro_paths.empty())
|
||||
return;
|
||||
|
||||
{
|
||||
std::unique_lock<std::shared_mutex> lk(_mutex);
|
||||
if(impl != _impl)
|
||||
continue;
|
||||
|
||||
_impl = std::move(new_impl);
|
||||
}
|
||||
|
||||
for(const auto &path : ro_paths)
|
||||
SysLog::warning("branch `{}` found to be readonly - setting its mode=RO",
|
||||
path.string());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(not changed)
|
||||
return;
|
||||
|
||||
std::atomic_store(&_impl,new_impl);
|
||||
}
|
||||
|
||||
SrcMounts::SrcMounts(Branches &b_)
|
||||
|
||||
+14
-4
@@ -23,9 +23,9 @@
|
||||
#include "strvec.hpp"
|
||||
#include "tofrom_string.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -69,7 +69,8 @@ public:
|
||||
u64 minfreespace = MINFREESPACE_DEFAULT;
|
||||
|
||||
private:
|
||||
mutable std::shared_ptr<Impl> _impl;
|
||||
Branches::Ptr _impl;
|
||||
mutable std::shared_mutex _mutex;
|
||||
|
||||
public:
|
||||
Branches()
|
||||
@@ -82,8 +83,17 @@ public:
|
||||
std::string to_string(void) const final;
|
||||
|
||||
public:
|
||||
operator Ptr() const { return std::atomic_load(&_impl); }
|
||||
Ptr operator->() const { return std::atomic_load(&_impl); }
|
||||
operator Ptr() const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lk(_mutex);
|
||||
return _impl;
|
||||
}
|
||||
|
||||
Ptr operator->() const
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lk(_mutex);
|
||||
return _impl;
|
||||
}
|
||||
|
||||
public:
|
||||
void find_and_set_mode_ro();
|
||||
|
||||
Reference in New Issue
Block a user