Subject: bug#75209: 30.0.93; Emacs reader failed to read data in "/home/nlj/.cache/org-persist/gc-lock.eld"

From: Eli Zaretskii <[email-masked]>
Date: Sat, 15 Mar 2025 17:52:03 +0200

> From: "N. Jackson" <[email-masked]>
> Cc: Ihor Radchenko <[email-masked]>,  [email-masked]
> Date: Sat, 15 Mar 2025 14:40:00 +0000
> 
> At 15:16 +0200 on Saturday 2025-03-15, Eli Zaretskii wrote:
> 
> >> See the attached diff.
> >> It should be applied on top of previous patches (or on top of the latest
> >> Org main).
> >
> > Thanks, I hope the OP could test this and tell if it makes the problem
> > go away for good.
> 
> I have applied the new patch and will report back.
> 
> I don't think it will help as I only have GNU/Linux systems at the
> moment and I think on such systems the earlier patch already made
> the write atomic.

Yes, I see that now, see below.

> I think what is needed is for the read to be atomic.

It is already atomic, because, as we've already established, the file
is smaller than 16KB, the size of the chunks read by
insert-file-contents in one go.

And if the replacement of the file is atomic, then how the file is
read cannot possibly matter.

Note: I'm not talking about writing to a file that is being read at
the same time, I'm talking about writing to a temporary file, and then
renaming that temporary file into the original name when all of the
new data has been written completely.  On Posix filesystems, as long
as the original file is open in some application, renaming another
file into that original one will NOT delete the original file or
replace it; instead, it will unlink the original file's data from its
directory entry, thus allowing the application that had it open to
keep reading from the original (now outdated) data.  Any application
that will attempt to open the original file's name will get the new
data.  IOW, the original data is still there, but it cannot be
accessed by any application that didn't have it open before the
rename.

> I might be
> completely wrong, but what it seems is happening is that one
> instance of Emacs starts a read and reads the first part of the
> existing file, then the other instance of Emacs writes the file
> (atomically), and then the first instance continues its read,
> getting the end of the new file.  So it gets the beginning of one
> version of the file and the end of another.

That cannot happen in the rename method described above.  So if the
problem still happens, there's some other factor at work here.

> Oughtn't there to be some sort locking mechanism so that the
> instance doing the read can lock the file and then the instance that
> is about to write the file can see that it shouldn't write it then
> and wait until the lock is cleared -- or something along those
> lines?

See above: Posix filesystems make that unnecessary.

Hmm... but now I see that the previous code already renamed the file
with the new data after the new data was completely written, is that
right?  If so, I don't think this last change will help, and we need
to understand how come rename-file doesn't already solve this problem.

Is the file being read and written a regular file or a symlink?

One thing to try is to let-bind write-region-inhibit-fsync to a nil
value around the code which writes the data to the org-persist file.
Maybe we have some tricky race condition between the filesystem
flushing its buffer after one instance of Emacs wrote the file, and
the other instance of Emacs that opens the file for reading.