[ARVADOS] updated: 1.3.0-2604-ga5c857c5a
Git user
git at public.arvados.org
Tue May 26 18:11:55 UTC 2020
Summary of changes:
.../db/migrate/20200501150153_permission_table.rb | 63 +++++++++++++++++++---
1 file changed, 56 insertions(+), 7 deletions(-)
via a5c857c5ab354d3b0e6a51653d0f1f21c108e131 (commit)
from dc6710242d28803f085e92acd2ff6ad313a51860 (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 a5c857c5ab354d3b0e6a51653d0f1f21c108e131
Author: Peter Amstutz <peter.amstutz at curii.com>
Date: Tue May 26 14:11:24 2020 -0400
16007: More code comment detail about compute_permission_subgraph query
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>
diff --git a/services/api/db/migrate/20200501150153_permission_table.rb b/services/api/db/migrate/20200501150153_permission_table.rb
index 9e8ff7c00..89c1db593 100644
--- a/services/api/db/migrate/20200501150153_permission_table.rb
+++ b/services/api/db/migrate/20200501150153_permission_table.rb
@@ -217,13 +217,58 @@ $$;
# from the materialized_permissions table. This is the clever
# bit.
#
- # Key insight: because permissions are transitive (unless
- # traverse_owned is false), by knowing the permissions granted
- # from all the "origins" (perm_origin_uuid, tail_uuid of links
- # where head_uuid is in our potentially affected set, etc) we can
- # join with the materialized_permissions table to get user
- # permissions on those origins, and apply that to the whole graph
- # of objects reached through that origin.
+ # Key insights:
+ #
+ # * Permissions are transitive (with some special cases involving
+ # users, this is controlled by the traverse_owned flag).
+ #
+ # * A user object can only gain permissions via an inbound edge,
+ # or appearing in the graph.
+ #
+ # * The materialized_permissions table includes the permission
+ # each user has on the tail end of each inbound edge.
+ #
+ # * The all_perms subquery has permissions for each object in the
+ # subgraph reachable from certain origin (tail end of an edge).
+ #
+ # * Therefore, for each user, we can compute user permissions on
+ # each object in subgraph by determining the permission the user
+ # has on each origin (tail end of an edge), joining that with the
+ # perm_origin_uuid column of all_perms, and taking the least() of
+ # the origin edge or all_perms val (because of the "least
+ # permission on the path" rule). If an object was reachable by
+ # more than one path (appears with more than one origin), we take
+ # the max() of the computed permissions.
+ #
+ # Finally, because users always have permission on themselves, the
+ # query also makes sure those permission rows are always
+ # returned.
+ #
+ # Notes on query optimization:
+ #
+ # Each clause in a "with" statement is called a "common table
+ # expression" or CTE.
+ #
+ # In Postgres, they are evaluated in sequence and results of each
+ # CTE is stored in a temporary table. This means Postgres does
+ # not propagate constraints from later queries to earlier CTEs.
+ #
+ # This is a problem if, for example, a later CTE only needs to
+ # choose 10 items out of a set of 1000000 from an earlier CTE,
+ # because it will always compute all 1000000 rows even if the
+ # query on the 1000000 rows could have been constrained. This is
+ # why permission_graph_edges is a view and not a CTE -- views are
+ # inlined so and can be optimized using external constraints.
+ #
+ # The query optimizer does sort the temporary tables for later use
+ # in joins.
+ #
+ # Final note, this query would have been almost impossible to
+ # write (and certainly impossible to read) without using SQL
+ # "with" and CTEs but unfortunately it also stumbles into a
+ # frustrating Postgres optimizer bug, see
+ # lib/refresh_permission_view.rb#update_permissions for details
+ # and a partial workaround.
#
ActiveRecord::Base.connection.execute %{
create or replace function compute_permission_subgraph (perm_origin_uuid varchar(27),
@@ -282,6 +327,10 @@ with
$$;
}
+ #
+ # Populate the materialized_permissions by traversing permissions
+ # starting at each user.
+ #
ActiveRecord::Base.connection.execute %{
INSERT INTO materialized_permissions
select users.uuid, g.target_uuid, g.val, g.traverse_owned
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list