From d7e0453578e1bcf76c59e16c99bba017f79fa11d Mon Sep 17 00:00:00 2001 From: Jeremy Penner Date: Tue, 12 Mar 2013 00:18:01 -0500 Subject: [PATCH] Resource management / caching with optional automatic expiry on file modification --- src/hottub/resource.clj | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/hottub/resource.clj diff --git a/src/hottub/resource.clj b/src/hottub/resource.clj new file mode 100644 index 0000000..1cc21a4 --- /dev/null +++ b/src/hottub/resource.clj @@ -0,0 +1,57 @@ +(ns hottub.resource + (:use hottub.util) + (:import [org.newdawn.slick Image])) + +(def resource-cache (atom {})) +(def garbage-resources (atom #{})) + +(defn last-modified [filename] + (.lastModified (java.io.File. filename))) + +(defn cached-resource [filename] + (:resource (get @resource-cache filename))) + +(defn cache-resource [filename resource fncleanup] + (println "caching new resource" filename) + (swap! resource-cache assoc filename + {:resource resource + :last-modified (last-modified filename) + :fncleanup fncleanup}) + resource) + +(defn expire-resource [filename] + (swap! garbage-resources conj filename)) + +(defn- expire-resource-impl [filename] + (if-let [resource (get @resource-cache filename)] + (do + (swap! resource-cache dissoc filename) + (if-let [fncleanup (:fncleanup resource)] + (do + (try + (println "cleaning up" resource) + (fncleanup (:resource resource)) + (catch Exception e (println "Couldn't clean up resource" resource e)))))))) + +(defn expire-outdated-resources [] + (doseq [[filename resource] @resource-cache] + (if (not= (:last-modified resource) (last-modified filename)) + (expire-resource filename)))) + +(defn get-resource [filename fnloader & [fncleanup]] + (if-let [resource (cached-resource filename)] + resource + (cache-resource filename (fnloader filename) fncleanup))) + +(defn get-image [filename] (get-resource filename #(Image. %) #(.destroy %))) + +(defn gc-expired-resources [] + (doseq [filename (reset-returning-old! garbage-resources #{})] + (expire-resource-impl filename))) + +(defn start-resource-expiry-thread [] + (.start (Thread. (fn [] + (loop [] + (expire-outdated-resources) + (Thread/sleep 1000) + (recur))))))