On Sat, Feb 14, 2009 at 5:44 PM, James Reeves <weavejes...@googlemail.com>wrote:

>
> On Feb 14, 5:30 pm, Dan <redalas...@gmail.com> wrote:
> > What about making the file an agent and sending write actions to it?
>
> I don't see how that would solve the problem, unless you're suggesting
> that I have a single agent to handle all reads and writes?
>
> - James
>

Temp files is probably the simplest way to go for "immutable" files. I tried
a temporary agent per file, and it got a little long. To support multiple
writes with interleaved reads and figuring out when to dissoc the agent
would probably make it even longer.

(ns safe-write
  (:import (java.io File))
  (:use [clojure.contrib.duck-streams :as ds]))

(def writers (ref {}))

(defn noop
  "Sends a noop action to an agent and awaits it."
  [agt]
  (send-off agt #(identity %))
  (await agt))

(defn await-writer
  "Waits for f's writer agent to finish if there is one and returns it. Else
  returns nil."
  [f]
  (when-let [agt (@writers f)]
    (while (not (= @agt :done))
      (noop agt))
    agt))

(defn exists?
  [f]
  (.exists (File. f)))

(defn waiting-read
  "Reads f, waiting for it to be written if another thread is writing it."
  [f]
  (await-writer f)
  (when (exists? f)
    (slurp f)))

(defn create-writer
  "Creates an agent to write f and returns it. Returns nil if such an agent
  already exists."
  [f]
  (dosync
   (when-not (@writers f)
     (let [agt (agent :working)]
       (alter writers assoc f agt)
       agt))))

(defn safe-write-once
  "Writes contents to f, but only if it doesn't exist and no other thread is
  writing it."
  [f contents]
  (when-not (exists? f)
    (when-let [writer (create-writer f)]
      (send-off writer (fn [_]
                         ;;(Thread/sleep 2000)
                         (spit f contents)
                         :done))
      (await writer)
      (dosync (alter writers dissoc f)))))

(defn do-test
  []
  (let [f "/tmp/test4.txt"]
    (.delete (File. f))
    (.start (Thread. #(safe-write-once f "crino")))
    (Thread/sleep 0)
    (waiting-read f)))

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to