Performance impact of overlapping roles

Can someone speak to any potential performance impact/issues related to overlapping roles? That is, multiple roles with the same membership, but adding different privileges.

I am, for the moment, assuming no conflicting privileges, but that is also a thought in the back of my mind.

Motivation: I am working through ideas to make bootstrapping new databases more modular. Right off the bat, I am seeking a clean way to configure and bootstrap the auth portion of the app mostly independent of the rest of the rest of it. In doing so, I also hope to make it more straight forward to get new/different apps off the ground easier.

Using @databrecht ‘s Skeleton auth repo as an example of what I’m looking at… There is the logged in role:

{
  name: 'membershiprole_loggedin',
  membership: [
    {
      resource: Collection('accounts')
    }
  ],
  privileges: [
    {
      resource: Collection('dinos'),
      actions: {
        read: Query(
          Lambda(['dinoReference'], Not(Equals(Select(['data', 'rarity'], Get(Var('dinoReference'))), 'legendary')))
        )
      }
    },
    {
      resource: q.Function('request_reset'),
      actions: { call: true }
    }
  ]
}

What might the performance impact be if privileges are expanded by creating multiple roles, rather than updating an existing one?

// Auth module
{
  name: 'membershiprole_loggedin',
  membership: [
    {
      resource: Collection('accounts')
    }
  ],
  privileges: [
    {
      resource: q.Function('request_reset'),
      actions: { call: true }
    }
  ]
}

// Simple Dino module
{
  name: 'membershiprole_loggedin_simpleDino',
  membership: [
    {

      resource: Collection('accounts')
    }
  ],
  privileges: [
    {
      resource: Collection('dinos'),
      actions: {
        read: Query(
          Lambda(['dinoReference'], Not(Equals(Select(['data', 'rarity'], Get(Var('dinoReference'))), 'legendary')))
        )
      }
    },
  ]
}

// Advanced Dino module
{
  name: 'membershiprole_loggedin_advancedDino',
  membership: [
    {

      resource: Collection('accounts')
    }
  ],
  privileges: [
    /* even more privileges ... */
  ]
}

Hi @ptpaterson,

Let me collect all the information and I’ll come back to you as soon as possible.

Luigi

1 Like

Hi @ptpaterson,

The database does its best to optimize for the most common access pattern. There is a single permission table for the set of overlapping roles. The permission lookup is a tuple of

(resource_id, action_name)

the result is a set of permissions composed by all configured actions among the overlapping roles.
While building the permission table, if one of the actions for a lookup key is trivially true, we don’t evaluate all roles but rather just grant the permission on lookup. However, if all actions for a given lookup key are predicates, we evaluate them sequentially until one of them returns true, or we deny access otherwise.
In that case, the system keeps track of the predicates that are most successful (returns true) and evaluate them first.
So, in the case all overlapping role’s actions are predicates, make sure they are as much efficient as possible.
Lastly, there is a maximum number of roles per resource. Currently, it’s 64.

Hope this help.

Luigi

2 Likes

This is very helpful! Thank you.