快速遍历ACL的策略

时间:2010-04-14 11:34:32

标签: performance algorithm tree acl

我们目前正在开发一个项目,其中主域对象是内容节点,我们正在使用类似ACL的系统,其中层次结构中的每个节点都可以包含覆盖或补充其父节点上的规则的规则。例如,一切都基于角色和行动。

Node 1 - {Deny All, Allow Role1 View}
\- Node 2 - {Allow Role2 View}
   \- Node 3 - {Deny Role1 View}

在这种情况下,将按从上到下的顺序读取规则,因此只能通过Role2查看节点3。它的概念并不复杂。

检索单个节点的规则可能会导致一些查询,获取所有父项,然后重新创建规则列表并对其进行评估,但这个过程可能很麻烦,因为层次结构可能会变得非常深,并且可能会有很多每个节点上的规则。

我一直在考虑为每个节点准备一个具有预先计算规则的表,无论何时更改权限并将其传播到更新权限的所有叶节点,都可以重新创建该表。

您是否考虑过加快检索和计算规则的其他策略?理想情况下,它应该在单个查询中完成,但树不是最好的结构。

2 个答案:

答案 0 :(得分:3)

我认为Observer Pattern可能会被改编。

这个想法是每个Node维护一个预先计算的列表,并且只是通过其父级通知任何更新,以便它可以重新计算这个列表。

这可以通过两种不同的方式完成:

  1. 通知发生了更改但不重新计算任何内容
  2. 每次更新时重新计算
  3. 我建议尽可能使用1,因为它不涉及在更新root时重新计算整个世界,并且只在需要时重新计算(实际上是lazy eval)但是如果你可能更喜欢第二个选项很少更新但需要快速检索(尽管存在更多的并发问题)。

    让我们来说明解决方案1:

    Root ___ Node1 ___ Node1A
         \         \__ Node1B
          \_ Node2 ___ Node2A
                   \__ Node2B
    

    现在,首先,如果我要求Node2A规则,它们都没有预先计算任何东西(都处于脏状态):

    • Node2A意识到它很脏:它查询Node2规则
    • Node2意识到它很脏:它会查询Root
    • Root没有任何父级,因此它不会变脏,它会将其规则发送到Node2
    • Node2缓存来自Root的答案,将其规则与从Root收到的规则合并并清除脏位,它将合并的结果(现在缓存)发送到{{ 1}}
    • Node2A缓存,合并,清除脏位并返回结果

    如果我随后要求Node2A规则:

    • Node2B很脏,它会查询Node2B
    • Node2很干净,它回复
    • Node2缓存,合并,清除脏位并返回结果

    请注意Node2B没有重新计算任何内容。

    在更新案例中:

    • 我更新了Node2:我使用Node1缓存规则来重新计算新规则并向RootNode1A发送节拍以通知他们缓存已过时< / LI>
    • Node1BNode1A设置了他们的脏位,如果他们有孩子,他们也会传播此通知

    请注意,因为我缓存了Node1B个规则,所以我不必查询Root对象,如果这是一个足够简单的操作,你可能根本不想缓存它们:如果你是不在这里播放分发,查询Root只涉及内存往返,你可能不想复制它以节省一些内存和簿记。

    希望它能帮到你。

答案 1 :(得分:1)

您的预计算版本似乎存储了与每个节点上每个角色相关的所有权限。您可以通过遍历树来节省一点时间和空间,在到达它们时为节点编号,并为每个角色生成一个节点号和权限更改的数组,仅用于与该角色相关的权限更改的节点。这会仅在输入树的大小(包括其注释)中生成线性输出。然后,当您检查某个节点上某个角色的权限时,请使用该节点的编号搜索该阵列,以查找数组中代表您在巡视期间访问该节点时最新权限更改的点。 / p>

这可能会以某种方式与http://en.wikipedia.org/wiki/Range_Minimum_Queryhttp://en.wikipedia.org/wiki/Lowest_common_ancestor相关联,但我不知道这些引用是否会有所帮助。