-
Notifications
You must be signed in to change notification settings - Fork 171
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
Throw an exception if File::unlock has failed + use same logic for all platforms, for detecting when we hold a lock on a file #6926
Changes from 6 commits
36b1885
2174e62
70d56f9
fb00459
7a71337
bc7edfb
a75e5d2
cca4eb1
e55c5dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -507,6 +507,7 @@ void File::open_internal(const std::string& path, AccessMode a, CreateMode c, in | |
int fd = ::open(path.c_str(), flags2, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); | ||
if (0 <= fd) { | ||
m_fd = fd; | ||
m_have_lock = false; | ||
if (success) | ||
*success = true; | ||
return; | ||
|
@@ -562,7 +563,8 @@ void File::close() noexcept | |
|
||
if (m_fd < 0) | ||
return; | ||
unlock(); | ||
if (m_have_lock) | ||
unlock(); | ||
int r = ::close(m_fd); | ||
REALM_ASSERT_RELEASE(r == 0); | ||
m_fd = -1; | ||
|
@@ -1098,7 +1100,16 @@ static void _unlock(int m_fd) | |
do { | ||
r = flock(m_fd, LOCK_UN); | ||
} while (r != 0 && errno == EINTR); | ||
REALM_ASSERT_RELEASE_EX(r == 0 && "File::unlock()", r, errno); | ||
if (r) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So almost all good now, i'm not entirely convinced about this bit still. We've almost misdiagnosed this issues 9th time in a row, do i understand it right? Essentially, we tried to unlock what we didn't lock (most likely from bugreports) since it wasn't needed for Realm::convert (Realm.writeCopyTo in java/kotlin sdks). And since the assumption was that unlock is noop if file is not locked, we called it unconditionally every time and it was fine until new storage restrictions in Android hit and this syscall started to fail. So we were crashing apps for no reason for few years already. Under #5107 and realm-java#6893 it was already mentioned that users activated needed permissions, and it was still crashing. To me this case already looks irrelevant, since we're not going to hit exact same code path now. The message may still be relevant for some realm opening scenarios though. @cmelchior could you confirm this? Also, it seems that sqlite3 essentially ignored the result of unlock call failure (although logs it still internally) on close at least. The same seems to be true for windows where in most cases the return result is ignored, and it never asserts or propages further. Exception in this case not much better that assertion. @finnschiermer shouldn't we just dump the error into logger, but essentially ignore it? Why interrupt any flow here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to throw an exception for 2 reasons. b) this is a limitation of some SDKs, but impacts also us, they don't easily print error messages that are coming from our ASSERTIONS. Yes, there are some ways for the developer to check the system logs, but I would not rely on that, and surely we can't grab those logs from the device ourselves. Ignoring the error can be a viable option, but I don't think it is correct. IMO we need to merge this PR in our code. |
||
std::string message = | ||
"File::unlock() has failed, this is likely due to some limitation in the OS file system."; | ||
#ifdef REALM_ANDROID | ||
message += | ||
" The most common cause is trying to use Realm on external storage. From Android API 30 this is no " | ||
"longer supported. See https://developer.android.com/about/versions/11/privacy/storage for more details."; | ||
#endif | ||
throw SystemError(errno, message); | ||
} | ||
} | ||
#endif | ||
|
||
|
@@ -1203,9 +1214,9 @@ bool File::rw_lock(bool exclusive, bool non_blocking) | |
bool File::lock(bool exclusive, bool non_blocking) | ||
{ | ||
REALM_ASSERT_RELEASE(is_attached()); | ||
REALM_ASSERT_RELEASE(!m_have_lock); | ||
|
||
#ifdef _WIN32 // Windows version | ||
REALM_ASSERT_RELEASE(!m_have_lock); | ||
|
||
// Under Windows a file lock must be explicitely released before | ||
// the file is closed. It will eventually be released by the | ||
|
@@ -1250,8 +1261,10 @@ bool File::lock(bool exclusive, bool non_blocking) | |
if (non_blocking) | ||
operation |= LOCK_NB; | ||
do { | ||
if (flock(m_fd, operation) == 0) | ||
if (flock(m_fd, operation) == 0) { | ||
m_have_lock = true; | ||
return true; | ||
} | ||
} while (errno == EINTR); | ||
int err = errno; // Eliminate any risk of clobbering | ||
if (err == EWOULDBLOCK) | ||
|
@@ -1262,10 +1275,10 @@ bool File::lock(bool exclusive, bool non_blocking) | |
|
||
void File::unlock() noexcept | ||
{ | ||
#ifdef _WIN32 // Windows version | ||
if (!m_have_lock) | ||
return; | ||
|
||
#ifdef _WIN32 // Windows version | ||
OVERLAPPED overlapped; | ||
overlapped.hEvent = 0; | ||
overlapped.OffsetHigh = 0; | ||
|
@@ -1276,11 +1289,8 @@ void File::unlock() noexcept | |
REALM_ASSERT_RELEASE(r); | ||
m_have_lock = false; | ||
#else | ||
// The Linux man page for flock() does not state explicitely that | ||
// unlocking is idempotent, however, we will assume it since there | ||
// is no mention of the error that would be reported if a | ||
// non-locked file were unlocked. | ||
_unlock(m_fd); | ||
m_have_lock = false; | ||
nicola-cab marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#endif | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great! So that's what was the issue all along it seems.... We just don't need to lock at all for mentioned usecases in bug reports
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but bear in mind that is very likely that since the system call for unlocking the file fails on certain circumstances, the same system call will eventually fail also when locking the file. So an exception will be thrown either way.