1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 def row_lock_for_priority_update container_uuid
6 # Locks all the containers under this container, and also any
7 # immediate parent containers. This ensures we have locked
8 # everything that gets touched by either a priority update or state
10 # This method assumes we are already in a transaction.
12 conn = ActiveRecord::Base.connection
13 conn.exec_query 'SAVEPOINT row_lock_for_priority_update'
16 select containers.uuid from containers where containers.uuid in (
17 select pri_container_uuid from container_tree($1)
19 select container_requests.requesting_container_uuid from container_requests
20 where container_requests.container_uuid = $1
21 and container_requests.state = 'Committed'
22 and container_requests.requesting_container_uuid is not NULL
24 order by containers.uuid for update of containers
25 }, 'select_for_update_priorities', [container_uuid]
26 rescue ActiveRecord::Deadlocked => rn
29 # Despite deliberately taking the locks in uuid order, reportedly
30 # this method still occasionally deadlocks with another request
31 # handler that is also doing updates on the same container tree.
32 # This happens infrequently so we don't know how to reproduce it
33 # or precisely what circumstances cause it.
35 # However, in this situation it is safe to retry because this
36 # query has no effect on the database content, its only job is to
37 # acquire a set of row locks so we can safely update the container
40 raise if max_retries == 0
43 # Wait random 0-10 seconds then rollback and retry
46 conn.exec_query 'ROLLBACK TO SAVEPOINT row_lock_for_priority_update'
51 def update_priorities starting_container_uuid
52 Container.transaction do
53 # Ensure the row locks were taken in order
54 row_lock_for_priority_update starting_container_uuid
56 ActiveRecord::Base.connection.exec_query %{
57 update containers set priority=computed.upd_priority from container_tree_priorities($1) as computed
58 where containers.uuid = computed.pri_container_uuid and priority != computed.upd_priority
59 }, 'update_priorities', [starting_container_uuid]