This is currently only triggered with the tests ran with --rhg without
--rust, by "luck", there probably always was something to write, like an
mtime when also using Rust extensions alongside rhg.
Details
- Reviewers
aalekseyev martinvonz - Group Reviewers
hg-reviewers - Commits
- rHGdd2503a63d33: rust-dirstate-v2: save proper data size if no new data on append
Diff Detail
- Repository
- rHG Mercurial
- Lint
Automatic diff as part of commit; lint not applicable. - Unit
Automatic diff as part of commit; unit tests not applicable.
Event Timeline
Note: the merge into default will require some small care (basically default has more unit tests, and we need to add an unused old_data_size). I can do it.
I don't understand the justification: if it's not correct to store the file length when we're appending empty data, why is it correct to store it when data is not empty? Can't the garbage still be there?
It's never correct to store the file length, the comment just means that if we're appending, we return the position of the last write, which will always be the root node. If we're not appending, we don't write anything, the pointer is always 0, and poof.
Ok, I get it. You're saying size 0 is special because a write of size 0 does not update the current file pointer.
I did not know exactly how append mode interacted with lseek, so I did an experiment.
The following C program always prints "hi2" for me, even if redirected to a file in append mode.
I think this means that even though write in append mode always appends to the end of the file, it doesn't actually advance the file pointer to that position, so the returned value is effectively the amount you wrote, not the total size of the file.
(I did not try the same in rust)
#include <sys/types.h> #include <unistd.h> #include <stdio.h> int main() { write(1, "hi", 2); off_t pos = lseek(1, 0, SEEK_CUR); printf("%ld\n", pos); return 0; }
Yep, same in rust:
use std::io::Seek; use std::io::SeekFrom; use std::io::Write as IoWrite; fn main() -> Result<(), std::io::Error> { let mut options = std::fs::OpenOptions::new(); options.append(true); let mut file = options.open("x")?; file.write_all(b"foobar")?; file.flush()?; println!("{}", file.seek(SeekFrom::Current(0))?); Ok(()) }
always prints 6.
So I'm guessing this doesn't work at all?
Wow, this is actually different on different filesystems: the behavior I described happens on ZFS, while a presumably-desirable behavior (different offset every time) happens on EXT4 and XFS. This is crazy!
Relevant issue: https://github.com/prometheus/prometheus/issues/484.
Presumably hg has reasonable expectations here, the bug is in ZFS. However this does mean that we in Jane Street will experience issues since we don't seem to have a patched ZFS.
This also means that this code path is untested, yes? (Since I'm not seeing any errors) Do you know how to reproduce the append behavior so we have a test that breaks on buggy ZFS?
It looks like the tests from your other long series need to be updated in this patch (they don't compile with this patch applied).
You may have missed my first comment here then. This patch is destined for stable where it should apply cleanly, only the merge will need to be adapted .
This is very interesting, thanks for the investigation. It is indeed untested, I can follow up with a test soon (but not this week).
Ah, you're right that I missed that (well, I forgot about it). Sorry.
This is very interesting, thanks for the investigation. It is indeed untested, I can follow up with a test soon (but not this week).
Since @aalekseyev seemed happy with the patch in it's current form, I suppose I can queue it now and you add those tests in a separate patch. Thanks.