X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/035b113f60302f6d9c265e6e3a63dbb3c5873153..685db28b50225cde7dbb03aa2275f7a165d888a3:/services/api/lib/update_priority.rb diff --git a/services/api/lib/update_priority.rb b/services/api/lib/update_priority.rb index 724d2b20a8..6c17f1bd03 100644 --- a/services/api/lib/update_priority.rb +++ b/services/api/lib/update_priority.rb @@ -3,17 +3,41 @@ # SPDX-License-Identifier: AGPL-3.0 module UpdatePriority - # Clean up after races: if container priority>0 but there are no - # committed container requests for it, reset priority to 0. - def self.update_priority + extend CurrentApiClient + + # Clean up after races. + # + # If container priority>0 but there are no committed container + # requests for it, reset priority to 0. + # + # If container priority=0 but there are committed container requests + # for it with priority>0, update priority. + # + # Normally, update_priority is a no-op if another thread/process is + # already updating. Test cases that need to check priorities after + # updating can force a (possibly overlapping) update in the current + # thread/transaction by setting the "nolock" flag. See #14878. + def self.update_priority(nolock: false) if !File.owned?(Rails.root.join('tmp')) Rails.logger.warn("UpdatePriority: not owner of #{Rails.root}/tmp, skipping") return end lockfile = Rails.root.join('tmp', 'update_priority.lock') File.open(lockfile, File::RDWR|File::CREAT, 0600) do |f| - return unless f.flock(File::LOCK_NB|File::LOCK_EX) - ActiveRecord::Base.connection.execute("UPDATE containers AS c SET priority=0 WHERE state='Queued' AND priority>0 AND uuid NOT IN (SELECT container_uuid FROM container_requests WHERE priority>0);") + return unless nolock || f.flock(File::LOCK_NB|File::LOCK_EX) + + # priority>0 but should be 0: + ActiveRecord::Base.connection. + exec_query("UPDATE containers AS c SET priority=0 WHERE state IN ('Queued', 'Locked', 'Running') AND priority>0 AND uuid NOT IN (SELECT container_uuid FROM container_requests WHERE priority>0 AND state='Committed');", 'UpdatePriority') + + # priority==0 but should be >0: + act_as_system_user do + Container. + joins("JOIN container_requests ON container_requests.container_uuid=containers.uuid AND container_requests.state=#{ActiveRecord::Base.connection.quote(ContainerRequest::Committed)} AND container_requests.priority>0"). + where('containers.state IN (?) AND containers.priority=0 AND container_requests.uuid IS NOT NULL', + [Container::Queued, Container::Locked, Container::Running]). + map(&:update_priority!) + end end end @@ -31,7 +55,12 @@ module UpdatePriority rescue => e Rails.logger.error "#{e.class}: #{e}\n#{e.backtrace.join("\n\t")}" ensure - ActiveRecord::Base.connection.close + # Rails 5.1+ makes test threads share a database connection, so we can't + # close a connection shared with other threads. + # https://github.com/rails/rails/commit/deba47799ff905f778e0c98a015789a1327d5087 + if Rails.env != "test" + ActiveRecord::Base.connection.close + end end end end