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
Improve module file reading and writing #758
Conversation
I'm not too clear on the reason for the locking. Isn't a mod file written to a tmp file & then, if the tmp mod file is different from the original, the tmp is renamed? If that's the case, then any process that has the old file open will still be accessing the old file even after the old file is removed. |
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.
Looks good. I have the same question as Steve regarding when such file conflicts can happen. It looks OK to me as additional safety though since it seems to have a small code footprint.
No, the mod file is written directly to its destination, which is why locking is necessary but a temp file is not. What you're suggesting is:
That does seem simpler -- I'll try it that way and see. |
I've pushed a new version that uses a temp file instead of file locking. I'm interested in opinions on which is better. |
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.
I like the use of a (presumably) atomic rename
more than locking.
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.
I don't understand much of the code, but what I understand looks good to me.
Fix problems with writing a mod file while another compilation is reading or writing. Write to a temp and then rename it: - compute the new contents of the .mod file - if it already exists, check if it is already correct - if not, write new contents to a temp file - rename the temp to the final destination `mkstemps()` seems to be the best way to create the temp file. It returns a file descriptor, so change the rest of the mod file writing to use POSIX open/read/write/close. This seems to set errno more reliably too. There is some extra work around creating the temp to make it have the same directory and suffix as the final file (so that if one gets left behind by a crash, "rm *.mod" still cleans it up). `mkstemps()` creates file with 0600 permissions so try to change it to what it would have been if we just wrote the file. Change module file reading to only read the file once; we used to read it to verify the checksum and then again to parse it. Instead, change `Parsing` so that we can get the file contents after `Prescan()` and use that to verify the checksum. Also, it has a mechanism for searching directories for files, so make use of that instead of duplicating that functionality in `ModFileReader`. This requires some changes to how errors are returned so they can be reported in the right place.
The tests run by `test_any.sh` don't redirect their .mod files to a different directory so they occasionally fail when the same file is accessed by different tests at the same time. With locking of module files implemented, this problem reproduces much more reliably Work around it by changing the module names to be distinct. Also remove some comments left over when copied from `test_symbols.sh` tests.
866e39f
to
a931d3e
Compare
Fix problems with writing a mod file while another compilation is reading or writing. Write to a temp and then rename it: - compute the new contents of the .mod file - if it already exists, check if it is already correct - if not, write new contents to a temp file - rename the temp to the final destination `mkstemps()` seems to be the best way to create the temp file. It returns a file descriptor, so change the rest of the mod file writing to use POSIX open/read/write/close. This seems to set errno more reliably too. There is some extra work around creating the temp to make it have the same directory and suffix as the final file (so that if one gets left behind by a crash, "rm *.mod" still cleans it up). `mkstemps()` creates file with 0600 permissions so try to change it to what it would have been if we just wrote the file. Change module file reading to only read the file once; we used to read it to verify the checksum and then again to parse it. Instead, change `Parsing` so that we can get the file contents after `Prescan()` and use that to verify the checksum. Also, it has a mechanism for searching directories for files, so make use of that instead of duplicating that functionality in `ModFileReader`. This requires some changes to how errors are returned so they can be reported in the right place. Original-commit: flang-compiler/f18@d0d5497 Reviewed-on: flang-compiler/f18#758 Tree-same-pre-rewrite: false
The tests run by `test_any.sh` don't redirect their .mod files to a different directory so they occasionally fail when the same file is accessed by different tests at the same time. With locking of module files implemented, this problem reproduces much more reliably Work around it by changing the module names to be distinct. Also remove some comments left over when copied from `test_symbols.sh` tests. Original-commit: flang-compiler/f18@f7b5c5f Reviewed-on: flang-compiler/f18#758
…/tsk-modfiles Improve module file reading and writing Original-commit: flang-compiler/f18@b5f48df Reviewed-on: flang-compiler/f18#758
Fix problems with writing a mod file while another compilation is reading or writing. Write to a temp and then rename it: - compute the new contents of the .mod file - if it already exists, check if it is already correct - if not, write new contents to a temp file - rename the temp to the final destination `mkstemps()` seems to be the best way to create the temp file. It returns a file descriptor, so change the rest of the mod file writing to use POSIX open/read/write/close. This seems to set errno more reliably too. There is some extra work around creating the temp to make it have the same directory and suffix as the final file (so that if one gets left behind by a crash, "rm *.mod" still cleans it up). `mkstemps()` creates file with 0600 permissions so try to change it to what it would have been if we just wrote the file. Change module file reading to only read the file once; we used to read it to verify the checksum and then again to parse it. Instead, change `Parsing` so that we can get the file contents after `Prescan()` and use that to verify the checksum. Also, it has a mechanism for searching directories for files, so make use of that instead of duplicating that functionality in `ModFileReader`. This requires some changes to how errors are returned so they can be reported in the right place. Original-commit: flang-compiler/f18@d0d5497 Reviewed-on: flang-compiler/f18#758 Tree-same-pre-rewrite: false
The tests run by `test_any.sh` don't redirect their .mod files to a different directory so they occasionally fail when the same file is accessed by different tests at the same time. With locking of module files implemented, this problem reproduces much more reliably Work around it by changing the module names to be distinct. Also remove some comments left over when copied from `test_symbols.sh` tests. Original-commit: flang-compiler/f18@f7b5c5f Reviewed-on: flang-compiler/f18#758
Use
flock()
to lock.mod
files during reading and writing to preventwriting while a read is in progress and reading or writing when a write
is in progress. To achieve this, change module file writing to use C
stdio so that the file descriptor is readily available.
errno
seemsto be set more reliably as well.
Change module file reading to only read the file once; we used to
read it to verify the checksum and then again to parse it.
Instead, change
Parsing
so that we can get the file contentsafter
Prescan()
and use that to verify the checksum. Also, it hasa mechanism for searching directories for files, so make use of that
instead of duplicating that functionality in
ModFileReader
.This requires some changes to how errors are returned so they can
be reported in the right place. The "isModuleFile" flag is passed in
to
SourceFile
so that file locking can be done only for module files.