Skip to content
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

Add update-file function #77

Merged
merged 3 commits into from
Nov 12, 2022
Merged

Conversation

PavlosMelissinos
Copy link
Contributor

@PavlosMelissinos PavlosMelissinos commented Nov 11, 2022

clojure.core/swap! semantics for files

Provide the filename and the (pure) function that will transform the contents of
the file (string in, string out) and update-file will open/close the file for you
and execute the operation.

@PavlosMelissinos PavlosMelissinos changed the title Add swap-file! function Add update-file function Nov 11, 2022
@PavlosMelissinos
Copy link
Contributor Author

PavlosMelissinos commented Nov 12, 2022

(posting here for completeness after a discussion on Clojurians slack)

Alternative thread-safe (I think... at least within the JVM process) implementation:

(defn update-file
  "Swaps the contents of file to be:
  (apply f current-contents-of-file args). f should be free of side effects.
  Returns the value that was swapped in."
  [file f & xs]
  (locking file
    (let [old-val (slurp file)
          new-val (apply f old-val xs)]
      (spit file new-val)
      new-val)))

and its test:

(testing "prevent concurrent access to the same file from separate threads"
    (let [file  (fs/file (fs/temp-dir) (str (gensym)))
          file2 (fs/file (fs/temp-dir) (str (gensym)))
          state (atom {})]
      (spit file "")
      (spit file2 "")

      (let [fut1 (future (fs/update-file file (fn [& _xs] (Thread/sleep 50) (pr-str (reset! state (assoc @state :file1-op1-ran true))))))
            fut2 (future (fs/update-file file (fn [& _xs] (pr-str (reset! state (assoc @state :file1-op2-waited (:file1-op1-ran @state)))))))]
        (fs/update-file file2 (fn [& _xs] (pr-str (reset! state (assoc @state :file2-op-waited (:file1-op1-ran @state))))))
        (deref fut1)
        (deref fut2)
        (is (= {:file1-op1-ran true
                :file1-op2-waited true
                :file2-op-waited nil}
               @state)))))

@borkdude
Copy link
Contributor

I think thread-safe is out of scope. Also file can be a string or a file object so you would be locking the string of file object, not the file itself. You can have multiple file objects pointing to the same file, which makes this a bit pointless.

@borkdude borkdude merged commit 4b2afa7 into babashka:master Nov 12, 2022
@PavlosMelissinos PavlosMelissinos deleted the swap-file branch November 13, 2022 08:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants