Skip to content

Commit

Permalink
Disabled parallel init/reload via lock (closes #9)
Browse files Browse the repository at this point in the history
  • Loading branch information
tonsky committed May 3, 2024
1 parent b79ecf0 commit 6b833d9
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 50 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.6.0 - May 3, 2024

- Disabled parallel init/reload via lock #9

# 0.5.0 - Apr 15, 2024

- Added `:files` option for custom file patterns #8 via @danieroux
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This is only about namespace dependencies within a single project. It has nothin
## Dependency

```clojure
io.github.tonsky/clj-reload {:mvn/version "0.5.0"}
io.github.tonsky/clj-reload {:mvn/version "0.6.0"}
```

## The problem
Expand Down
112 changes: 63 additions & 49 deletions src/clj_reload/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
[clj-reload.keep :as keep]
[clj-reload.parse :as parse]
[clj-reload.util :as util]
[clojure.java.io :as io]))
[clojure.java.io :as io])
(:import
[java.util.concurrent.locks ReentrantLock]))

; Config :: {:dirs [<string> ...] - where to look for files
; :files #"<regex>" - which files to scan, defaults to #".*\.cljc?"
Expand Down Expand Up @@ -47,6 +49,16 @@
(def ^:private *state
(atom {}))

(def ^ReentrantLock lock
(ReentrantLock.))

(defmacro with-lock [& body]
`(try
(.lock lock)
~@body
(finally
(.unlock lock))))

(defn- files->namespaces [files already-read]
(let [*res (volatile! {})]
(doseq [file files
Expand Down Expand Up @@ -122,22 +134,23 @@
:reload-hook :: <symbol> - if function with this name exists in a namespace,
it will be called after reloading. Default: 'after-ns-reload"
[opts]
(binding [util/*log-fn* nil]
(let [dirs (vec (:dirs opts))
files (or (:files opts) #".*\.cljc?")
now (util/now)]
(alter-var-root #'*config*
(constantly
{:dirs dirs
:files files
:no-unload (set (:no-unload opts))
:no-reload (set (:no-reload opts))
:reload-hook (:reload-hook opts 'after-ns-reload)
:unload-hook (:unload-hook opts 'before-ns-unload)}))
(let [{:keys [files' namespaces']} (scan-impl nil 0)]
(reset! *state {:since now
:files files'
:namespaces namespaces'})))))
(with-lock
(binding [util/*log-fn* nil]
(let [dirs (vec (:dirs opts))
files (or (:files opts) #".*\.cljc?")
now (util/now)]
(alter-var-root #'*config*
(constantly
{:dirs dirs
:files files
:no-unload (set (:no-unload opts))
:no-reload (set (:no-reload opts))
:reload-hook (:reload-hook opts 'after-ns-reload)
:unload-hook (:unload-hook opts 'before-ns-unload)}))
(let [{:keys [files' namespaces']} (scan-impl nil 0)]
(reset! *state {:since now
:files files'
:namespaces namespaces'}))))))

(defn- topo-sort-fn
"Accepts dependees map {ns -> #{downsteram-ns ...}},
Expand Down Expand Up @@ -301,38 +314,39 @@
([]
(reload nil))
([opts]
(binding [util/*log-fn* (:log-fn opts util/*log-fn*)]
(let [{:keys [unloaded]} (unload opts)]
(loop [loaded []]
(let [state @*state]
(if (not-empty (:to-load state))
(let [[ns & to-load'] (:to-load state)
files (-> state :namespaces ns :ns-files)]
(if-some [ex (some #(ns-load ns % (-> state :namespaces ns :keep)) files)]
(do
(swap! *state update :to-unload #(cons ns %))
(if (:throw opts true)
(throw
(ex-info
(str "Failed to load namespace: " ns)
{:unloaded unloaded
:loaded loaded
:failed ns}
ex))
{:unloaded unloaded
:loaded loaded
:failed ns
:exception ex}))
(do
(swap! *state #(-> %
(assoc :to-load to-load')
(update-in [:namespaces ns] dissoc :keep)))
(recur (conj loaded ns)))))
(do
(when (empty? loaded)
(util/log "Nothing to reload"))
{:unloaded unloaded
:loaded loaded}))))))))
(with-lock
(binding [util/*log-fn* (:log-fn opts util/*log-fn*)]
(let [{:keys [unloaded]} (unload opts)]
(loop [loaded []]
(let [state @*state]
(if (not-empty (:to-load state))
(let [[ns & to-load'] (:to-load state)
files (-> state :namespaces ns :ns-files)]
(if-some [ex (some #(ns-load ns % (-> state :namespaces ns :keep)) files)]
(do
(swap! *state update :to-unload #(cons ns %))
(if (:throw opts true)
(throw
(ex-info
(str "Failed to load namespace: " ns)
{:unloaded unloaded
:loaded loaded
:failed ns}
ex))
{:unloaded unloaded
:loaded loaded
:failed ns
:exception ex}))
(do
(swap! *state #(-> %
(assoc :to-load to-load')
(update-in [:namespaces ns] dissoc :keep)))
(recur (conj loaded ns)))))
(do
(when (empty? loaded)
(util/log "Nothing to reload"))
{:unloaded unloaded
:loaded loaded})))))))))

(defmulti keep-methods
(fn [tag]
Expand Down

0 comments on commit 6b833d9

Please sign in to comment.