Conversation
To support failing fast on invalid time, internal `->file-time` now throws when input time is not a convertable to `FileTime`. Added internal `fs/now` to support redeffing current time for tests. This initial implementation does not pass `touch` opts through to `create-file` to avoid the complexity of dealing with `:posix-file-permissions`. Closes #232
|
Maybe a bit of an edge case, but: The GNU (-> (java.nio.channels.FileChannel/open
(as-path path)
(into-array [java.nio.file.StandardOpenOption/CREATE
java.nio.file.StandardOpenOption/WRITE]))
(.close))This ensures the file will exists, either opening an existing one or creating one. |
|
Yes, great idea! I will make it so. |
|
Oh, I'll also add tests for touching existing dirs too. And adjust accordingly. |
Decided to turf mockable `now` in `babashka.fs` ns. Tests now instead check that file was very recently modified. The idea of using `FileChannel` is exciting, but had to adapt slightly to also handle touching directories.
|
The updated approach has another problem. If another process deletes the file after our create and before our set-last-modified-time, we'd get a NoSuchFileExcpetion. To do the touch functionality atomically, we could do: (with-open [chan (java.nio.channels.FileChannel/open
path
(into-array java.nio.file.OpenOption
(cond-> [java.nio.file.StandardOpenOption/CREATE
java.nio.file.StandardOpenOption/WRITE]
nofollow-links (conj java.nio.file.LinkOption/NOFOLLOW_LINKS))))]
(-> (.getFileAttributeView chan java.nio.file.attribute.BasicFileAttributeView)
(.setTimes time nil nil)))Actually |
|
Ah... interesting. I looked into setting time on the file channel We could get the file attribute view on the I'm not sure we can achieve a race-condition-free touch in Java(?). We could set the last acccess time though... |
|
I just tried to find another way to deal without the try/catch, but we probably can't. Your approach seems valid. We could use (try (BasicFile.../setTimes ....) (catch NoSuchFileException ... (create the file) (recur)) ? |
|
Nope, recur isn't going to work in try/catch. So the only thing left is very minor: the access time. We could also ignore that and merge yours. |
|
I'm guessing that setting last access time is not that important for bb fs. But maybe I should make some mention that bb fs touch is not race-condition-free in docstring? |
|
So: |
|
sorry I missed the accompanying text: I guess we could make it race condition free by calling ourselves when hitting the exception |
|
Lemme explore your retry idea: case 1 - file/dir exists
case 2 - file/dir does not exist
case 3 - race condition
Unlikely but: the retry could end up retrying forever (or until the stack blows). Option 1: don't retry, don't document Option 2: don't retry, document in docstring, Option 3: auto-retry with recursion (technically can blow stack) Option 4: auto-retry with loop (technically can hang) Option 5: add hard retry limit Option 6: add configurable retry limit option I think I like option 2. What would you prefer? As for setting last access time, I have no strong preference, but I would lean torwards not bothering. |
|
Yes, option 2. |
Also add a comment as to why we are using FileChannel/open
This one was definitely a collaboration!
|
Thanks! |
To support failing fast on invalid time, internal
->file-timenow throws when input time is not a convertable toFileTime.Added internal
fs/nowto support redeffing current time for tests.This initial implementation does not pass
touchopts through tocreate-fileto avoid the complexity of dealing with:posix-file-permissions.Closes #232
Please answer the following questions and leave the below in as part of your PR.
This PR corresponds to an issue with a clear problem statement.
This PR contains a test to prevent against future regressions
I have updated the CHANGELOG.md file with a description of the addressed issue.