Seems like there could be a great performance gain by running some schema as exclusion lists, rather than grants.
This came up for us in using forums. If we want to provide several private forums (and don't want to add another taxonomy and the rules to populate the ACL terms based on forum parent) ... then we adding ACL to the forums vocab ends up with WAY more access lookup than it needs to.
But with any content type linked to a tac_lite enabled vocab will end up running a large query if if NO TERMS are selected.
Do we have this misconfigured somehow? Perhaps it was meant form a grant standpoint and this is the edge case?
Here are some sample queries from a "page" with an ACL vocab with ONLY THREE TERMS.
(The larger vocab is just set to "none" for all roles.)
menu_tree_check_access()
REPEATED 4 TIMES
SELECT DISTINCT n.nid FROM node n INNER JOIN node_access na ON na.nid = n.nid WHERE (na.grant_view >= 1 AND ((na.gid = 0 AND na.realm = 'all') OR (na.gid = 0 AND na.realm = 'tac_lite') OR (na.gid = 677 AND na.realm = 'tac_lite') OR (na.gid = 416 AND na.realm = 'tac_lite') OR (na.gid = 91 AND na.realm = 'tac_lite') OR (na.gid = 92 AND na.realm = 'tac_lite') OR (na.gid = 94 AND na.realm = 'tac_lite') OR (na.gid = 95 AND na.realm = 'tac_lite') OR (na.gid = 93 AND na.realm = 'tac_lite') OR (na.gid = 96 AND na.realm = 'tac_lite') OR (na.gid = 97 AND na.realm = 'tac_lite') OR (na.gid = 98 AND na.realm = 'tac_lite') OR (na.gid = 358 AND na.realm = 'tac_lite') OR (na.gid = 795 AND na.realm = 'tac_lite') OR (na.gid = 604 AND na.realm = 'tac_lite') OR (na.gid = 699 AND na.realm = 'tac_lite') OR (na.gid = 1615 AND na.realm = 'tac_lite') OR (na.gid = 1609 AND na.realm = 'tac_lite') OR (na.gid = 1491 AND na.realm = 'tac_lite') OR (na.gid = 1490 AND na.realm = 'tac_lite') OR (na.gid = 1413 AND na.realm = 'tac_lite') OR (na.gid = 800 AND na.realm = 'tac_lite') OR (na.gid = 754 AND na.realm = 'tac_lite') OR (na.gid = 1344 AND na.realm = 'tac_lite') OR (na.gid = 755 AND na.realm = 'tac_lite') OR (na.gid = 756 AND na.realm = 'tac_lite') OR (na.gid = 805 AND na.realm = 'tac_lite') OR (na.gid = 606 AND na.realm = 'tac_lite') OR (na.gid = 1378 AND na.realm = 'tac_lite') OR (na.gid = 1401 AND na.realm = 'tac_lite') OR (na.gid = 1086 AND na.realm = 'tac_lite') OR (na.gid = 698 AND na.realm = 'tac_lite') OR (na.gid = 605 AND na.realm = 'tac_lite') OR (na.gid = 1376 AND na.realm = 'tac_lite') OR (na.gid = 1375 AND na.realm = 'tac_lite') OR (na.gid = 0 AND na.realm = 'tac_lite_scheme_2'))) AND ( n.status = 1 AND n.nid IN (9, 8, 400, 401, 6, 6305, 10227, 10, 10584, 11510, 11426, 11, 19, 20, 21, 22, 6277, 303, 318, 319, 320, 2567, 329, 2562, 2230, 433, 12478, 327, 429, 422, 432, 426, 424, 423, 409, 408, 420, 419, 14462, 12, 430, 410, 421, 418, 10817, 10519, 11900, 11901, 11903, 12273, 13628, 13655, 11773, 11771, 11763, 11775, 13254, 13916))
node_access()
REPEATED 7 TIMES
SELECT 1 FROM node_access WHERE (nid = 0 OR nid = 9) AND ((gid = 0 AND realm = 'all') OR (gid = 0 AND realm = 'tac_lite') OR (gid = 677 AND realm = 'tac_lite') OR (gid = 416 AND realm = 'tac_lite') OR (gid = 91 AND realm = 'tac_lite') OR (gid = 92 AND realm = 'tac_lite') OR (gid = 94 AND realm = 'tac_lite') OR (gid = 95 AND realm = 'tac_lite') OR (gid = 93 AND realm = 'tac_lite') OR (gid = 96 AND realm = 'tac_lite') OR (gid = 97 AND realm = 'tac_lite') OR (gid = 98 AND realm = 'tac_lite') OR (gid = 358 AND realm = 'tac_lite') OR (gid = 795 AND realm = 'tac_lite') OR (gid = 604 AND realm = 'tac_lite') OR (gid = 699 AND realm = 'tac_lite') OR (gid = 1615 AND realm = 'tac_lite') OR (gid = 1609 AND realm = 'tac_lite') OR (gid = 1491 AND realm = 'tac_lite') OR (gid = 1490 AND realm = 'tac_lite') OR (gid = 1413 AND realm = 'tac_lite') OR (gid = 800 AND realm = 'tac_lite') OR (gid = 754 AND realm = 'tac_lite') OR (gid = 1344 AND realm = 'tac_lite') OR (gid = 755 AND realm = 'tac_lite') OR (gid = 756 AND realm = 'tac_lite') OR (gid = 805 AND realm = 'tac_lite') OR (gid = 606 AND realm = 'tac_lite') OR (gid = 1378 AND realm = 'tac_lite') OR (gid = 1401 AND realm = 'tac_lite') OR (gid = 1086 AND realm = 'tac_lite') OR (gid = 698 AND realm = 'tac_lite') OR (gid = 605 AND realm = 'tac_lite') OR (gid = 1376 AND realm = 'tac_lite') OR (gid = 1375 AND realm = 'tac_lite') OR (gid = 0 AND realm = 'tac_lite_scheme_2')) AND grant_view >= 1 LIMIT 0, 1
Comments
Comment #0.0
doublejosh commentedupdate details about vocab
Comment #0.1
doublejosh commentedquery repeat amounts.
Comment #1
Dave Cohen commentedIt works the way it does because of drupal core's node_access. I think the long query is because the user has so many grants, not because the node has so many terms.
node_access is understood to have overhead associated with it. It is possible to code a custom access scheme that works some other way. (I.e. perform a custom check in hook_nodeapi). Its hard for me to imagine tac_lite working any other way, but if you can explain a better idea please suggest it.
Comment #2
doublejosh commentedThanks for the clarification.
When most roles are allowed to see the majority of terms (my case forums) with only several limited, this will happen.
It seems fairly normal to use it like this, so my suggestion is to allow setting a schema to work as exclusion.
But it sounds like this is a major (or at least tricky) task due to the node_access architecture.
Luckily I think there is a more simple fix to avoid these massive realm checks as a result of the tac_lite UI (at least the version I'm looking at)...
Mainly avoid checking: vocabs not used on a node, but adding the ability to exclude a tac_lite vocab from a scheme.
My use case, and result...
Vocabs:
Schemas:
Outcome: ALL forum term realms are checked on all pages even when though the vocab isn't there.
Perhaps it's an implementation problem on my end to have the two schemes? But isn't it right to have two logically separate ACL intentions broken apart. Also, currently it's impossible to avoid large checks on node types that are unaffected by other vocabs because everything is forced into every scheme, even when all are marked as
<none>.Comment #3
Dave Cohen commentedIf you search d.o you'll find lots of old issues suggesting a change from grant-based node_access to deny-based. You could argue either way. Drupal core decided one way and I doubt you'll convince the powers that be to change it. (I wouldn't change it, personally).
I believe it is in D7 they introduced a couple of alter hooks that make custom access control much more flexible. You might be able to back-port that in a way that lets you improve the queries. I can't recall exactly when it was introduced.
You could, instead of using forum vocab to control privacy, make a new vocab tagging forum posts as public, private 1, or private 2. Then write some custom code that automatically tags forum posts with those tags. In other words use fewer terms, and use drupal hooks to redundantly tag nodes in the private forums.
If you come up with something that works please share it. It might benefit others.
Comment #4
doublejosh commentedAbsolutely.
And you've come to the same conclusion... Was going to use Rules to auto tag with an ACL term (from a small vocab) on all new forum topics within my few 'limited' categories.
However, I still think a give schema should not be forced to include all tac_lite vocabs. If
<none>is selected for all roles, it can be left out of any queries for grants. Realize even a change like that is not trivial.Comment #5
thedavidmeister commentedno movement on this in over a year. I assume a patch won't be coming from doublejosh, so I'm going to close this off. Feel free to re-open if you have something constructive to add.
Comment #5.0
thedavidmeister commentedstyle for clarity