Skip to content

Commit 6b07299

Browse files
authored
Remove the emulated InterprocessMutex File cache (#7448)
This was added to reduce the number of file descriptors used back when we opened a separate SharedGroup on each thread. We now normally only ever open one DB per file per process at a time, so sharing files between them is no longer useful.
1 parent 4eef991 commit 6b07299

File tree

3 files changed

+25
-156
lines changed

3 files changed

+25
-156
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
### Fixed
77
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
8-
* None.
8+
* Fix an assertion failure "m_lock_info && m_lock_info->m_file.get_path() == m_filename" that appears to be related to opening a Realm while the file is in the process of being closed on another thread ([Swift #8507](https://github.com/realm/realm-swift/issues/8507)).
99

1010
### Breaking changes
1111
* None.

src/realm/util/interprocess_mutex.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,6 @@
2020

2121
using namespace realm::util;
2222

23-
#if REALM_ROBUST_MUTEX_EMULATION
24-
25-
std::once_flag InterprocessMutex::s_init_flag;
26-
std::map<File::UniqueID, std::weak_ptr<InterprocessMutex::LockInfo>>* InterprocessMutex::s_info_map;
27-
Mutex* InterprocessMutex::s_mutex;
28-
29-
#endif // REALM_ROBUST_MUTEX_EMULATION
30-
3123
#if REALM_PLATFORM_APPLE
3224
SemaphoreMutex::SemaphoreMutex() noexcept
3325
: m_semaphore(dispatch_semaphore_create(1))

src/realm/util/interprocess_mutex.hpp

Lines changed: 24 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class SemaphoreMutex {
7474

7575
class InterprocessMutex {
7676
public:
77-
InterprocessMutex();
77+
InterprocessMutex() = default;
7878
~InterprocessMutex() noexcept;
7979

8080
// Disable copying. Copying a locked Mutex will create a scenario
@@ -93,7 +93,6 @@ class InterprocessMutex {
9393
/// The SharedPart is assumed to have been initialized (possibly by another process)
9494
/// elsewhere.
9595
void set_shared_part(SharedPart& shared_part, const std::string& path, const std::string& mutex_name);
96-
void set_shared_part(SharedPart& shared_part, File&& lock_file);
9796

9897
/// Destroy shared object. Potentially release system resources. Caller must
9998
/// ensure that the shared_part is not in use at the point of call.
@@ -130,43 +129,13 @@ class InterprocessMutex {
130129

131130
private:
132131
#if REALM_ROBUST_MUTEX_EMULATION
133-
struct LockInfo {
134-
File m_file;
132+
File m_file;
135133
#if REALM_PLATFORM_APPLE
136-
SemaphoreMutex m_local_mutex;
134+
SemaphoreMutex m_local_mutex;
137135
#else
138-
Mutex m_local_mutex;
136+
Mutex m_local_mutex;
139137
#endif
140-
LockInfo() {}
141-
~LockInfo() noexcept;
142-
// Disable copying.
143-
LockInfo(const LockInfo&) = delete;
144-
LockInfo& operator=(const LockInfo&) = delete;
145-
};
146-
/// InterprocessMutex created on the same file (same inode on POSIX) share the same LockInfo.
147-
/// LockInfo will be saved in a static map as a weak ptr and use the UniqueID as the key.
148-
/// Operations on the map need to be protected by s_mutex
149-
static std::map<File::UniqueID, std::weak_ptr<LockInfo>>* s_info_map;
150-
static Mutex* s_mutex;
151-
/// We manually initialize these static variables when first needed,
152-
/// creating them on the heap so that they last for the entire lifetime
153-
/// of the process. The destructor of these is never called; the
154-
/// process will clean up their memory when exiting. It is not enough
155-
/// to count instances of InterprocessMutex and clean up these statics when
156-
/// the count reaches zero because the program can create more
157-
/// InterprocessMutex instances before the process ends, so we really need
158-
/// these variables for the entire lifetime of the process.
159-
static std::once_flag s_init_flag;
160-
static void initialize_statics();
161-
162-
/// Only used for release_shared_part
163-
std::string m_filename;
164-
File::UniqueID m_fileuid;
165-
std::shared_ptr<LockInfo> m_lock_info;
166-
167-
/// Free the lock info hold by this instance.
168-
/// If it is the last reference, underly resources will be freed as well.
169-
void free_lock_info();
138+
170139
#else
171140
SharedPart* m_shared_part = nullptr;
172141

@@ -178,13 +147,6 @@ class InterprocessMutex {
178147
friend class InterprocessCondVar;
179148
};
180149

181-
inline InterprocessMutex::InterprocessMutex()
182-
{
183-
#if REALM_ROBUST_MUTEX_EMULATION
184-
std::call_once(s_init_flag, initialize_statics);
185-
#endif
186-
}
187-
188150
inline InterprocessMutex::~InterprocessMutex() noexcept
189151
{
190152
#ifdef _WIN32
@@ -193,83 +155,31 @@ inline InterprocessMutex::~InterprocessMutex() noexcept
193155
REALM_ASSERT_RELEASE(b);
194156
}
195157
#endif
196-
197-
#if REALM_ROBUST_MUTEX_EMULATION
198-
free_lock_info();
199-
#endif
200158
}
201159

202-
#if REALM_ROBUST_MUTEX_EMULATION
203-
inline InterprocessMutex::LockInfo::~LockInfo() noexcept
204-
{
205-
if (m_file.is_attached()) {
206-
m_file.close();
207-
}
208-
}
209-
210-
inline void InterprocessMutex::free_lock_info()
211-
{
212-
// It has not been initialized yet.
213-
if (!m_lock_info)
214-
return;
215-
216-
std::lock_guard<Mutex> guard(*s_mutex);
217-
218-
m_lock_info.reset();
219-
if ((*s_info_map)[m_fileuid].expired()) {
220-
s_info_map->erase(m_fileuid);
221-
}
222-
m_filename.clear();
223-
}
224-
225-
inline void InterprocessMutex::initialize_statics()
226-
{
227-
s_mutex = new Mutex();
228-
s_info_map = new std::map<File::UniqueID, std::weak_ptr<LockInfo>>();
229-
}
230-
#endif
231-
232160
inline void InterprocessMutex::set_shared_part(SharedPart& shared_part, const std::string& path,
233161
const std::string& mutex_name)
234162
{
235163
#if REALM_ROBUST_MUTEX_EMULATION
236164
static_cast<void>(shared_part);
237165

238-
free_lock_info();
166+
std::string filename;
239167
if (path.size() == 0) {
240-
m_filename = make_temp_file(mutex_name.c_str());
168+
filename = make_temp_file(mutex_name.c_str());
241169
}
242170
else {
243-
m_filename = path + "." + mutex_name + ".mx";
244-
}
245-
246-
std::lock_guard<Mutex> guard(*s_mutex);
247-
248-
// Try to get the file uid if the file exists
249-
if (auto uid = File::get_unique_id(m_filename)) {
250-
m_fileuid = std::move(*uid);
251-
auto result = s_info_map->find(m_fileuid);
252-
if (result != s_info_map->end()) {
253-
// File exists and the lock info has been created in the map.
254-
m_lock_info = result->second.lock();
255-
REALM_ASSERT_RELEASE(m_lock_info && m_lock_info->m_file.get_path() == m_filename);
256-
return;
257-
}
171+
filename = util::format("%1.%2.mx", path, mutex_name);
258172
}
259173

260-
// LockInfo has not been created yet.
261-
m_lock_info = std::make_shared<LockInfo>();
262174
// Always open file for write and retreive the uid in case other process
263175
// deletes the file. Avoid using just mode_Write (which implies truncate).
264176
// On fat32/exfat uid could be reused by OS in a situation when
265177
// multiple processes open and truncate the same lock file concurrently.
266-
m_lock_info->m_file.open(m_filename, File::mode_Append);
178+
m_file.close();
179+
m_file.open(filename, File::mode_Append);
267180
// exFAT does not allocate a unique id for the file until it's non-empty
268-
m_lock_info->m_file.resize(1);
269-
m_fileuid = m_lock_info->m_file.get_unique_id();
181+
m_file.resize(1);
270182

271-
REALM_ASSERT_RELEASE(s_info_map->find(m_fileuid) == s_info_map->end());
272-
(*s_info_map)[m_fileuid] = m_lock_info;
273183
#elif defined(_WIN32)
274184
if (m_handle) {
275185
bool b = CloseHandle(m_handle);
@@ -292,40 +202,13 @@ inline void InterprocessMutex::set_shared_part(SharedPart& shared_part, const st
292202
#endif
293203
}
294204

295-
inline void InterprocessMutex::set_shared_part(SharedPart& shared_part, File&& lock_file)
296-
{
297-
#if REALM_ROBUST_MUTEX_EMULATION
298-
static_cast<void>(shared_part);
299-
300-
free_lock_info();
301-
302-
std::lock_guard<Mutex> guard(*s_mutex);
303-
304-
m_fileuid = lock_file.get_unique_id();
305-
auto result = s_info_map->find(m_fileuid);
306-
if (result == s_info_map->end()) {
307-
m_lock_info = std::make_shared<LockInfo>();
308-
m_lock_info->m_file = std::move(lock_file);
309-
(*s_info_map)[m_fileuid] = m_lock_info;
310-
}
311-
else {
312-
// File exists and the lock info has been created in the map.
313-
m_lock_info = result->second.lock();
314-
lock_file.close();
315-
}
316-
#else
317-
m_shared_part = &shared_part;
318-
static_cast<void>(lock_file);
319-
#endif
320-
}
321-
322205
inline void InterprocessMutex::release_shared_part()
323206
{
324207
#if REALM_ROBUST_MUTEX_EMULATION
325-
if (!m_filename.empty())
326-
File::try_remove(m_filename);
327-
328-
free_lock_info();
208+
if (m_file.is_attached()) {
209+
m_file.close();
210+
File::try_remove(m_file.get_path());
211+
}
329212
#else
330213
m_shared_part = nullptr;
331214
#endif
@@ -334,8 +217,8 @@ inline void InterprocessMutex::release_shared_part()
334217
inline void InterprocessMutex::lock()
335218
{
336219
#if REALM_ROBUST_MUTEX_EMULATION
337-
std::unique_lock mutex_lock(m_lock_info->m_local_mutex);
338-
m_lock_info->m_file.lock();
220+
std::unique_lock mutex_lock(m_local_mutex);
221+
m_file.lock();
339222
mutex_lock.release();
340223
#else
341224

@@ -352,21 +235,16 @@ inline void InterprocessMutex::lock()
352235
inline bool InterprocessMutex::try_lock()
353236
{
354237
#if REALM_ROBUST_MUTEX_EMULATION
355-
std::unique_lock mutex_lock(m_lock_info->m_local_mutex, std::try_to_lock_t());
238+
std::unique_lock mutex_lock(m_local_mutex, std::try_to_lock_t());
356239
if (!mutex_lock.owns_lock()) {
357240
return false;
358241
}
359-
bool success = m_lock_info->m_file.try_lock();
360-
if (success) {
361-
mutex_lock.release();
362-
return true;
363-
}
364-
else {
242+
if (!m_file.try_lock()) {
365243
return false;
366244
}
367-
#else
368-
369-
#ifdef _WIN32
245+
mutex_lock.release();
246+
return true;
247+
#elif defined(_WIN32)
370248
DWORD ret = WaitForSingleObject(m_handle, 0);
371249
REALM_ASSERT_RELEASE(ret != WAIT_FAILED);
372250

@@ -380,15 +258,14 @@ inline bool InterprocessMutex::try_lock()
380258
REALM_ASSERT(m_shared_part);
381259
return m_shared_part->try_lock([]() {});
382260
#endif
383-
#endif
384261
}
385262

386263

387264
inline void InterprocessMutex::unlock()
388265
{
389266
#if REALM_ROBUST_MUTEX_EMULATION
390-
m_lock_info->m_file.unlock();
391-
m_lock_info->m_local_mutex.unlock();
267+
m_file.unlock();
268+
m_local_mutex.unlock();
392269
#else
393270
#ifdef _WIN32
394271
bool b = ReleaseMutex(m_handle);

0 commit comments

Comments
 (0)