df6f9d0bb53adfd3bcfd4b51ba6c8cd0c6dd4651
[arvados.git] / services / api / db / migrate / 20230503224107_priority_update_functions.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 class PriorityUpdateFunctions < ActiveRecord::Migration[5.2]
6   def up
7     ActiveRecord::Base.connection.execute %{
8 CREATE OR REPLACE FUNCTION container_priority(for_container_uuid character varying, inherited bigint, inherited_from character varying) returns bigint
9     LANGUAGE sql
10     AS $$
11 /* Determine the priority of an individual container.
12    The "inherited" priority comes from the path we followed from the root, the parent container
13    priority hasn't been updated in the table yet but we need to behave it like it has been.
14 */
15 select coalesce(max(case when container_requests.priority = 0 then 0
16                          when containers.uuid = inherited_from then inherited
17                          when containers.priority is not NULL then containers.priority
18                          else container_requests.priority * 1125899906842624::bigint - (extract(epoch from container_requests.created_at)*1000)::bigint
19                     end), 0) from
20     container_requests left outer join containers on container_requests.requesting_container_uuid = containers.uuid
21     where container_requests.container_uuid = for_container_uuid and container_requests.state = 'Committed' and container_requests.priority > 0;
22 $$;
23 }
24
25     ActiveRecord::Base.connection.execute %{
26 CREATE OR REPLACE FUNCTION update_priorities(for_container_uuid character varying) returns table (pri_container_uuid character varying, upd_priority bigint)
27     LANGUAGE sql
28     AS $$
29 /* Calculate the priorities of all containers starting from for_container_uuid.
30    This traverses the process tree downward and calls container_priority for each container
31    and returns a table of container uuids and their new priorities.
32 */
33 with recursive tab(upd_container_uuid, upd_priority) as (
34   select for_container_uuid, container_priority(for_container_uuid, 0, '')
35 union
36   select containers.uuid, container_priority(containers.uuid, child_requests.upd_priority, child_requests.upd_container_uuid)
37   from (tab join container_requests on tab.upd_container_uuid = container_requests.requesting_container_uuid) as child_requests
38   join containers on child_requests.container_uuid = containers.uuid
39   where containers.state in ('Queued', 'Locked', 'Running')
40 )
41 select upd_container_uuid, upd_priority from tab;
42 $$;
43 }
44
45     ActiveRecord::Base.connection.execute %{
46 CREATE OR REPLACE FUNCTION container_tree(for_container_uuid character varying) returns table (pri_container_uuid character varying)
47     LANGUAGE sql
48     AS $$
49 /* A lighter weight version of the update_priorities query that only returns the containers in a tree,
50    used by SELECT FOR UPDATE.
51 */
52 with recursive tab(upd_container_uuid) as (
53   select for_container_uuid
54 union
55   select containers.uuid
56   from (tab join container_requests on tab.upd_container_uuid = container_requests.requesting_container_uuid) as child_requests
57   join containers on child_requests.container_uuid = containers.uuid
58   where containers.state in ('Queued', 'Locked', 'Running')
59 )
60 select upd_container_uuid from tab;
61 $$;
62 }
63   end
64
65   def down
66     ActiveRecord::Base.connection.execute "DROP FUNCTION container_priority"
67     ActiveRecord::Base.connection.execute "DROP FUNCTION update_priorities"
68     ActiveRecord::Base.connection.execute "DROP FUNCTION container_tree"
69   end
70 end