   (defn- format-timestamp [timestamp]
     (unparse fmtr timestamp)))
 
+(defn lock-matrix [file func]
+  (kdb/transaction (update experiments (where {:file file}) (set-fields {:loaded false})))
+  (func)
+  (kdb/transaction (update experiments (where {:file file}) (set-fields {:loaded true}))))
+
 (defn load-exp [file timestamp filehash matrix]
-  (kdb/transaction
-    (let [cid (merge-cohort file)
-          exp (merge-exp file (format-timestamp timestamp) filehash cid)
-          sids (load-samples cid (:samples (meta matrix)))]
-      (load-exp-samples exp sids)
-      (load-exp-matrix exp matrix))))
+  (lock-matrix
+    file
+    (fn []
+      (let [cid (kdb/transaction (merge-cohort file))
+            exp (kdb/transaction (merge-exp file (format-timestamp timestamp) filehash cid))
+            sids (kdb/transaction (load-samples cid (:samples (meta matrix))))]
+        (kdb/transaction (load-exp-samples exp sids))
+        (load-exp-matrix exp matrix)))))
 
 ; XXX factor out common parts with merge, above?
 (defn del-exp [file]


; Delete experiment data & update experiment record.
(defn- merge-exp [file timestamp filehash cohort]
  (exec-raw ["MERGE INTO experiments (file, time, hash, cid) KEY(file) VALUES (?, ?, ?, ?)"
             [file timestamp filehash cohort]])
  (let [[{exp :ID}] (select experiments (where {:file file}))]
    (clear-by-exp exp)
    exp))

                       `time` TIMESTAMP NOT NULL,
                       `hash` VARCHAR(40) NOT NULL,
                       `cid` INT NOT NULL,
                        `loaded` BOOLEAN NOT NULL,
                       FOREIGN KEY (cid) REFERENCES `cohorts` (`id`))"])

(def exp-samples-table ["CREATE TABLE IF NOT EXISTS `exp_samples` (
