diff --git a/backend/src/app/db.clj b/backend/src/app/db.clj index 2b98c5e31..e11e5b8bc 100644 --- a/backend/src/app/db.clj +++ b/backend/src/app/db.clj @@ -11,6 +11,7 @@ [app.common.geom.point :as gpt] [app.common.spec :as us] [app.common.transit :as t] + [app.common.uuid :as uuid] [app.db.sql :as sql] [app.metrics :as mtx] [app.util.json :as json] @@ -366,3 +367,25 @@ (defn pgarray->vector [v] (vec (.getArray ^PgArray v))) + + +;; --- Locks + +(defn- xact-check-param + [n] + (cond + (uuid? n) (uuid/get-word-high n) + (int? n) n + :else (throw (IllegalArgumentException. "uuid or number allowed")))) + +(defn xact-lock! + [conn n] + (let [n (xact-check-param n)] + (exec-one! conn ["select pg_advisory_xact_lock(?::bigint) as lock" n]) + true)) + +(defn xact-try-lock! + [conn n] + (let [n (xact-check-param n) + row (exec-one! conn ["select pg_try_advisory_xact_lock(?::bigint) as lock" n])] + (:lock row))) diff --git a/backend/src/app/db/sql.clj b/backend/src/app/db/sql.clj index 6ee5d3073..0ce621f23 100644 --- a/backend/src/app/db/sql.clj +++ b/backend/src/app/db/sql.clj @@ -43,8 +43,8 @@ ([table where-params opts] (let [opts (merge default-opts opts) opts (cond-> opts - (:for-update opts) - (assoc :suffix "FOR UPDATE"))] + (:for-update opts) (assoc :suffix "FOR UPDATE") + (:for-key-share opts) (assoc :suffix "FOR KEY SHARE"))] (sql/for-query table where-params opts)))) (defn update diff --git a/backend/src/app/rpc/mutations/files.clj b/backend/src/app/rpc/mutations/files.clj index 02e8963a9..90e79860c 100644 --- a/backend/src/app/rpc/mutations/files.clj +++ b/backend/src/app/rpc/mutations/files.clj @@ -268,8 +268,9 @@ (sv/defmethod ::update-file [{:keys [pool] :as cfg} {:keys [id profile-id] :as params}] (db/with-atomic [conn pool] - (let [{:keys [id] :as file} (db/get-by-id conn :file id {:for-update true})] + (let [{:keys [id] :as file} (db/get-by-id conn :file id {:for-key-share true})] (files/check-edition-permissions! conn profile-id id) + (db/xact-lock! conn id) (update-file (assoc cfg :conn conn) (assoc params :file file))))) diff --git a/common/src/app/common/uuid.cljc b/common/src/app/common/uuid.cljc index f7530aae3..25f989381 100644 --- a/common/src/app/common/uuid.cljc +++ b/common/src/app/common/uuid.cljc @@ -6,13 +6,13 @@ (ns app.common.uuid (:refer-clojure :exclude [next uuid zero?]) - #?(:clj (:import java.util.UUID)) - #?(:clj - (:require [clj-uuid :as impl] - [clojure.core :as c]) - :cljs - (:require [app.common.uuid-impl :as impl] - [cljs.core :as c]))) + (:require + [app.common.data :as d] + #?(:clj [clj-uuid :as impl]) + #?(:clj [clojure.core :as c]) + #?(:cljs [app.common.uuid-impl :as impl]) + #?(:cljs [cljs.core :as c])) + #?(:clj (:import java.util.UUID))) (def zero #uuid "00000000-0000-0000-0000-000000000000") @@ -45,3 +45,6 @@ (defn custom ([a] #?(:clj (UUID. 0 a) :cljs (c/uuid (impl/custom 0 a)))) ([b a] #?(:clj (UUID. b a) :cljs (c/uuid (impl/custom b a))))) + +#?(:clj + (d/export impl/get-word-high))