mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-19 16:16:48 +00:00
Use atomic open file reference counts
- Use relaxed increment under the map bucket lock when duplicating file handles. - Use acq_rel decrement when releasing and checking for final references. - Load moved ref_count with relaxed ordering during map insertion.
This commit is contained in:
committed by
trapexit
parent
b13727abde
commit
608cd00764
+10
-1
@@ -367,10 +367,19 @@ _open(const fuse_req_ctx_t *ctx_,
|
||||
|
||||
// The ref increment keeps fuse_release.cpp from erasing and
|
||||
// freeing the canonical entry while we duplicate its fd.
|
||||
//
|
||||
// memory_order_relaxed is sufficient for the increment. The
|
||||
// concurrent_flat_map bucket lock held inside visit() already
|
||||
// provides the happens-before relationship with other mutators
|
||||
// of the same key (the release() erase_if() callback and other
|
||||
// open() visitors.) The lock's release/acquire semantics
|
||||
// publish the ref_count update to subsequent observers of the
|
||||
// same entry, so we only need atomicity from the fetch_add
|
||||
// itself.
|
||||
of.visit(ctx_->nodeid,
|
||||
[&](auto &v_)
|
||||
{
|
||||
v_.second.ref_count++;
|
||||
v_.second.ref_count.fetch_add(1,std::memory_order_relaxed);
|
||||
fi = v_.second.fi;
|
||||
backing_id = v_.second.backing_id;
|
||||
});
|
||||
|
||||
+12
-2
@@ -81,11 +81,21 @@ FUSE::release(cu64 nodeid_,
|
||||
FileInfo *canonical_fi = nullptr;
|
||||
FileInfo *fh_fi_to_free = nullptr;
|
||||
|
||||
// memory_order_acq_rel on the decrement gives us the canonical
|
||||
// refcount-publication pattern:
|
||||
// - release: prior writes to the OpenFile by this thread are
|
||||
// visible to whichever thread observes the final 0.
|
||||
// - acquire: the thread that drops the last ref acquires every
|
||||
// prior ref holder's writes before tearing down the entry.
|
||||
// The concurrent_flat_map bucket lock already serializes concurrent
|
||||
// visitors of this key so the acq_rel is good for any observer that
|
||||
// might examine ref_count outside a visit().
|
||||
of.erase_if(nodeid_,
|
||||
[&](auto &v_)
|
||||
{
|
||||
v_.second.ref_count--;
|
||||
if(v_.second.ref_count > 0)
|
||||
const int prev =
|
||||
v_.second.ref_count.fetch_sub(1,std::memory_order_acq_rel);
|
||||
if(prev > 1)
|
||||
{
|
||||
if(fi_ != v_.second.fi)
|
||||
fh_fi_to_free = fi_;
|
||||
|
||||
+5
-1
@@ -103,8 +103,12 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
// Move constructor runs during initial insertion into the
|
||||
// concurrent_flat_map before the new entry is reachable by the
|
||||
// other threads. There is no concurrent observer of the moved
|
||||
// value at this point so relaxed load is sufficient.
|
||||
OpenFile(OpenFile &&o_) noexcept
|
||||
: ref_count(o_.ref_count.load()),
|
||||
: ref_count(o_.ref_count.load(std::memory_order_relaxed)),
|
||||
backing_id(o_.backing_id),
|
||||
fi(o_.fi)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user