Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix blocked DB::open on multiprocess access on exFAT filesystem #6959

Merged
merged 9 commits into from
Oct 20, 2023
Prev Previous commit
Next Next commit
Fix build
kiburtse committed Oct 19, 2023
commit d69e8ae78b435b9605655d80fc0c577add126d18
3 changes: 0 additions & 3 deletions src/realm/util/interprocess_mutex.hpp
Original file line number Diff line number Diff line change
@@ -82,9 +82,6 @@ class InterprocessMutex {
InterprocessMutex(const InterprocessMutex&) = delete;
InterprocessMutex& operator=(const InterprocessMutex&) = delete;

InterprocessMutex(InterprocessMutex&&) = default;
InterprocessMutex& operator=(InterprocessMutex&&) = default;

#if REALM_ROBUST_MUTEX_EMULATION || defined(_WIN32)
struct SharedPart {
};
34 changes: 19 additions & 15 deletions test/test_shared.cpp
Original file line number Diff line number Diff line change
@@ -4354,19 +4354,23 @@ NONCONCURRENT_TEST_IF(Shared_LockFileConcurrentInit, testing_supports_spawn_proc
test_dir.do_remove = SpawnedProcess::is_parent();
auto lock_prefix = std::string(path) + "/lock";

struct Mutex : InterprocessMutex {
SharedPart sp;
struct Lock {
std::unique_ptr<InterprocessMutex> mutex;
std::unique_ptr<InterprocessMutex::SharedPart> sp;

Mutex(Mutex&&) = default;
Mutex& operator=(Mutex&&) = default;

Mutex(const std::string& name, const std::string& lock_prefix_path)
Lock(const std::string& name, const std::string& lock_prefix_path)
: mutex(std::make_unique<InterprocessMutex>())
, sp(std::make_unique<InterprocessMutex::SharedPart>())
{
set_shared_part(sp, lock_prefix_path, name);
mutex->set_shared_part(*sp, lock_prefix_path, name);
}
~Mutex()

Lock(Lock&&) = default;
Lock& operator=(Lock&&) = default;

~Lock()
{
release_shared_part();
mutex->release_shared_part();
}
};

@@ -4379,21 +4383,21 @@ NONCONCURRENT_TEST_IF(Shared_LockFileConcurrentInit, testing_supports_spawn_proc
test_util::spawn_process(test_context.test_details.test_name, util::format("child [%1]", i)));

if (spawned.back()->is_child()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it timing dependent what spawned.back() refers to when it executes in a child while the parent is still spawning other children?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't test_util::spawn_process essentially no-op in child process? It checks if REALM_CHILD_IDENT is present in env for a process and returns uninitialized SpawnedProcess. So first iteration in child process should get it, check the same thing again, execute and quit. That's the pattern in other test from what i can tell. May be i don't understand something here, but how parent process would influence this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I just (mis)read the spawn_process as a fork() system call...

std::vector<Mutex> locks;
std::vector<Lock> locks;

// mimic the same impl detail as in DB and hope it'd trigger some assertions
for (auto tag : {"write", "control", "versions"}) {
locks.emplace_back(tag, lock_prefix);
CHECK(locks.back().is_valid());
CHECK(locks.back().mutex->is_valid());
}

// if somehow initialization is scrambled or there is an issues with
// underlying files then it should hang here
for (int k = 0; k < 3; ++k) {
for (auto&& mutex : locks)
mutex.lock();
for (auto&& mutex : locks)
mutex.unlock();
for (auto&& lock : locks)
lock.mutex->lock();
for (auto&& lock : locks)
lock.mutex->unlock();
}

exit(0);