-
Notifications
You must be signed in to change notification settings - Fork 34
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
Seeking the DB file does not work in a bundled JRuby application, crashes randomly #37
Comments
I think at a minimum JRuby should provide some obvious signal that the file is not seekable (perhaps &.seekable? == false) if that becomes the case we can feature detect and switch implementation. As what to do if JRuby is not going to change anything, I would recommend some sort of magic include that switches the implementation to a completely in-memory implementation if you opt for it (eg: So we leave RandomAccessDb as is and just implement a new cc @headius |
We should fix the buffer dumping, probably. I would guess it was just an oversight... we flush buffers before seek and then don't actually seek for these unseekable resources, but we can't go back to where we were in the buffer.
There is no We are always happy to fix issues in JRuby in a logical way, if you can summarize what you think should be fixed. If it's just repairing the buffer flush, that should be pretty easy. |
@headius I agree that the buffer flush should certainly be fixed. Beyond that, though, I personally also think that a non-trivial seek on a non-seekable file should always raise an exception — where non-trivial means anything that isn't provably a no-op, such as But that's all tangential to the issue at hand: even if my suggestion above was implemented, it would just make MiniMime fail sooner and in a more obvious way when run from a .jar bundle. I can file a separate issue for JRuby if you'd like, but I don't think further in-depth discussion about changing the JRuby @SamSaffron Meanwhile, I'll try to provide a PR for MiniMime soon, probably tomorrow. AFAICT, the method I suggested earlier for detecting seekability (seek, rescue, check pos) should work reliably with or without any changes to JRuby's behavior. (To be safe, we do need to reopen the file if seeking fails, but that's easy enough to do in this case.) |
When forking, file descriptors are inherited and their state shared. In the context of MiniMime this means that the offset of the file opened by RandomAccessDb is shared across processes, so the `seek + read` combo is subject to inter-process race conditions. Of course that file is lazily opened, so assuming most applications don't query MiniMime before fork, it's not a big problem. However when reforking post boot (e.g. https://github.com/Shopify/pitchfork) this becomes an issue. Additionally, even if the file descriptor isn't shared across processes, the file position is still process global requiring a Mutex. By using `pread` instead of `seek + read` we can both make the library fork safe and get rid of the need to synchronize accesses. This also happens to fix an outstanding JRuby issue. Fix: discourse#37 Fix: discourse#38
When forking, file descriptors are inherited and their state shared. In the context of MiniMime this means that the offset of the file opened by RandomAccessDb is shared across processes, so the `seek + read` combo is subject to inter-process race conditions. Of course that file is lazily opened, so assuming most applications don't query MiniMime before fork, it's not a big problem. However when reforking post boot (e.g. https://github.com/Shopify/pitchfork) this becomes an issue. Additionally, even if the file descriptor isn't shared across processes, the file position is still process global requiring a Mutex. By using `pread` instead of `seek + read` we can both make the library fork safe and get rid of the need to synchronize accesses. This also happens to fix an outstanding JRuby issue. Fix: discourse#37 Fix: discourse#38
When forking, file descriptors are inherited and their state shared. In the context of MiniMime this means that the offset of the file opened by RandomAccessDb is shared across processes, so the `seek + read` combo is subject to inter-process race conditions. Of course that file is lazily opened, so assuming most applications don't query MiniMime before fork, it's not a big problem. However when reforking post boot (e.g. https://github.com/Shopify/pitchfork) this becomes an issue. Additionally, even if the file descriptor isn't shared across processes, the file position is still process global requiring a Mutex. By using `pread` instead of `seek + read` we can both make the library fork safe and get rid of the need to synchronize accesses. This also happens to fix an outstanding JRuby issue. Fix: #37 Fix: #38
I missed this when you first posted, @ikaronen-relex, but it's a good idea if you're still out there :-) |
@headius, sure, I can do that. Thanks for the reminder! 😃 Ps. I have a suspicion that the change in #50 doesn't actually fix the behavior when running from a bundled .jar file, since the JRuby implementation of (FWIW, I also think that behavior is contrary to the POSIX spec, which says that "An attempt to perform a pread() on a file that is incapable of seeking results in an error." Arguably it also violates the Ruby stdlib documentation, which just references "the pread system call" and says that it "Raises SystemCallError on error". Anyway, I can also submit a fix for that, either in the same PR or in a separate one.) |
We have a Rails-based JRuby application deployed as a bundled .jar file, in which we currently use ActionMailer (which uses the Mail gem, which use MiniMime) to send reports as e-mail attachments. We've had reports of weird random crashes causing these e-mails sometimes not to be sent, and we've managed to narrow down the source of these crashes to MiniMime, and specifically to the code in MiniMime::Db::RandomAccessDb.
Here's an example stack trace from a crash log:
(Yes, I know we're a few versions behind, but the relevant code in v1.0.2 looks the same as in master and I'm pretty sure the issue exists there too.)
Anyway, the weird crashes seem to happen because MiniMime::Db::RandomAccessDb.resolve tries to seek the DB file. But in a bundled app the DB files end up being
uri:classloader
resources, which are not seekable. Worse, due to a questionable decision by the JRuby devs, attempting to seek them doesn't actually raise an exception but fails silently (and, AFAICT, also causes some internal buffers to be dumped so that the nextreadline
ends up starting from the middle of a line).Anyway, while the weird silent seek failure is arguably a JRuby bug, even if it's fixed those files will never be seekable (since the underlying Java streams aren't). So this would still need to be fixed on MiniMime's side to make it work in a bundled JRuby app.
Off the top of my head, I can see a couple of possible solutions:
The text was updated successfully, but these errors were encountered: