   (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]

           (let [sid (insert-scores-fn (ahashable (score-encode block)))]
             (insert-join pid i sid))) blocks indx))))

; insert matrix, updating scores, probes, and joins tables
(defn- load-exp-matrix [exp matrix]
  (let [loadp (partial load-probe (insert-unique-scores-fn) exp)]
    (dorun (map loadp matrix))))

(defn- cohort-sample-list [cid sample-list]
  (select samples (fields :id :sample)

                       `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` (
