[ARVADOS] updated: 397c907933cebb03a2a8dfd7626100ce6b8a2eb6
Git user
git at public.curoverse.com
Thu Sep 7 13:40:22 EDT 2017
Summary of changes:
services/api/app/models/arvados_model.rb | 9 +--
.../20170906224040_materialized_permission_view.rb | 43 +++++++++++++-
services/api/lib/create_permission_view.sql | 69 ----------------------
3 files changed, 44 insertions(+), 77 deletions(-)
delete mode 100644 services/api/lib/create_permission_view.sql
via 397c907933cebb03a2a8dfd7626100ce6b8a2eb6 (commit)
from 9b94f9f3068ee431b81131472fe4353defaffb32 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 397c907933cebb03a2a8dfd7626100ce6b8a2eb6
Author: Peter Amstutz <peter.amstutz at curoverse.com>
Date: Thu Sep 7 13:39:12 2017 -0400
12032: Add comments to migration. Also special case api_client_authorizations
in readable_by.
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz at veritasgenetics.com>
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index f6e914d..94c2cc5 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -263,16 +263,11 @@ class ArvadosModel < ActiveRecord::Base
if users_list.select { |u| u.is_admin }.any?
if !include_trash
# exclude rows that are explicitly trashed.
- if self.column_names.include? "owner_uuid"
+ if sql_table != "api_client_authorizations"
sql_conds.push "NOT EXISTS(SELECT 1
FROM permission_view
WHERE trashed = 1 AND
(#{sql_table}.uuid = target_uuid OR #{sql_table}.owner_uuid = target_uuid))"
- else
- sql_conds.push "NOT EXISTS(SELECT 1
- FROM permission_view
- WHERE trashed = 1 AND
- (#{sql_table}.uuid = target_uuid))"
end
end
else
@@ -286,7 +281,7 @@ class ArvadosModel < ActiveRecord::Base
trashed_check = "trashed = 0"
end
- if self.column_names.include? "owner_uuid" and sql_table != "groups"
+ if sql_table != "api_client_authorizations" and sql_table != "groups"
owner_check = "OR (target_uuid = #{sql_table}.owner_uuid AND target_owner_uuid IS NOT NULL)"
sql_conds.push "#{sql_table}.owner_uuid IN (:user_uuids)"
else
diff --git a/services/api/db/migrate/20170906224040_materialized_permission_view.rb b/services/api/db/migrate/20170906224040_materialized_permission_view.rb
index de0814e..8e5df35 100644
--- a/services/api/db/migrate/20170906224040_materialized_permission_view.rb
+++ b/services/api/db/migrate/20170906224040_materialized_permission_view.rb
@@ -1,10 +1,38 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
class MaterializedPermissionView < ActiveRecord::Migration
@@idxtables = [:collections, :container_requests, :groups, :jobs, :links, :pipeline_instances, :pipeline_templates, :repositories, :users, :virtual_machines, :workflows]
def up
+
+ #
+ # Construct a materialized view for permissions. This is a view which is
+ # derived from querying other tables, but is saved to a static table itself
+ # so that it can be indexed and queried efficiently without rerunning the
+ # query. The view is updated using "REFRESH MATERIALIZED VIEW" which is
+ # executed after an operation invalidates the permission graph.
+ #
+
ActiveRecord::Base.connection.execute(
- "CREATE MATERIALIZED VIEW permission_view AS
+"-- constructing perm_edges
+-- 1. get the list of all permission links,
+-- 2. any can_manage link or permission link to a group means permission should "follow through"
+-- (as a special case, can_manage links to a user grant access to everything owned by the user,
+-- unlike can_read or can_write which only grant access to the user record)
+-- 3. add all owner->owned relationships between groups as can_manage edges
+--
+-- constructing permissions
+-- 1. base case: start with set of all users as the working set
+-- 2. recursive case:
+-- join with edges where the tail is in the working set and "follow" is true
+-- produce a new working set with the head (target) of each edge
+-- set permission to the least permission encountered on the path
+-- propagate trashed flag down
+
+CREATE MATERIALIZED VIEW permission_view AS
WITH RECURSIVE
perm_value (name, val) AS (
VALUES
@@ -58,6 +86,19 @@ SELECT user_uuid,
add_index :permission_view, [:trashed, :target_uuid], name: 'permission_target_trashed'
add_index :permission_view, [:user_uuid, :trashed, :perm_level], name: 'permission_target_user_trashed_level'
+ # Indexes on the other tables are essential to for the query planner to
+ # construct an efficient join with permission_view.
+ #
+ # Our default query uses "ORDER BY modified_by desc, uuid"
+ #
+ # It turns out the existing simple index on modified_by can't be used
+ # because of the additional ordering on "uuid".
+ #
+ # To be able to utilize the index, the index ordering has to match the
+ # ORDER BY clause. For more detail see:
+ #
+ # https://www.postgresql.org/docs/9.3/static/indexes-ordering.html
+ #
@@idxtables.each do |table|
ActiveRecord::Base.connection.execute("CREATE INDEX index_#{table.to_s}_on_modified_at_uuid ON #{table.to_s} USING btree (modified_at desc, uuid asc)")
end
diff --git a/services/api/lib/create_permission_view.sql b/services/api/lib/create_permission_view.sql
deleted file mode 100644
index 71ac8c4..0000000
--- a/services/api/lib/create_permission_view.sql
+++ /dev/null
@@ -1,69 +0,0 @@
--- Copyright (C) The Arvados Authors. All rights reserved.
---
--- SPDX-License-Identifier: AGPL-3.0
-
--- constructing perm_edges
--- 1. get the list of all permission links,
--- 2. any can_manage link or permission link to a group means permission should "follow through"
--- (as a special case, can_manage links to a user grant access to everything owned by the user,
--- unlike can_read or can_write which only grant access to the user record)
--- 3. add all owner->owned relationships between groups as can_manage edges
---
--- constructing permissions
--- 1. base case: start with set of all users as the working set
--- 2. recursive case:
--- join with edges where the tail is in the working set and "follow" is true
--- produce a new working set with the head (target) of each edge
--- set permission to the least permission encountered on the path
--- propagate trashed flag down
-
-CREATE TEMPORARY VIEW permission_view AS
-WITH RECURSIVE
-perm_value (name, val) AS (
- VALUES
- ('can_read', 1::smallint),
- ('can_login', 1),
- ('can_write', 2),
- ('can_manage', 3)
- ),
-perm_edges (tail_uuid, head_uuid, val, follow, trashed) AS (
- SELECT links.tail_uuid,
- links.head_uuid,
- pv.val,
- (pv.val = 3 OR groups.uuid IS NOT NULL) AS follow,
- 0::smallint AS trashed
- FROM links
- LEFT JOIN perm_value pv ON pv.name = links.name
- LEFT JOIN groups ON pv.val<3 AND groups.uuid = links.head_uuid
- WHERE links.link_class = 'permission'
- UNION ALL
- SELECT owner_uuid, uuid, 3, true,
- CASE WHEN trash_at IS NOT NULL and trash_at < clock_timestamp() THEN 1 ELSE 0 END
- FROM groups
- ),
-perm (val, follow, user_uuid, target_uuid, trashed, startnode) AS (
- SELECT 3::smallint AS val,
- false AS follow,
- users.uuid::varchar(32) AS user_uuid,
- users.uuid::varchar(32) AS target_uuid,
- 0::smallint AS trashed,
- true AS startnode
- FROM users
- UNION
- SELECT LEAST(perm.val, edges.val)::smallint AS val,
- edges.follow AS follow,
- perm.user_uuid::varchar(32) AS user_uuid,
- edges.head_uuid::varchar(32) AS target_uuid,
- GREATEST(perm.trashed, edges.trashed)::smallint AS trashed,
- false AS startnode
- FROM perm
- INNER JOIN perm_edges edges
- ON (perm.startnode or perm.follow) AND edges.tail_uuid = perm.target_uuid
-)
-SELECT user_uuid,
- target_uuid,
- MAX(val) AS perm_level,
- CASE follow WHEN true THEN target_uuid ELSE NULL END AS target_owner_uuid,
- MAX(trashed) AS trashed
- FROM perm
- GROUP BY user_uuid, target_uuid, target_owner_uuid;
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list