位运算在实践中的尝试
之前碰到一个需要实现工作流的需求,简单来说就是一个事件,可以通过多人多权限进行事件状态的转化,这里我以django-river为例说明。
在一个小team,有 leader 和 coder,现在有工作流状态open,in-progress,resolved,re-open,closed五中状态,状态流向为open -> in-progress,in-progress -> resolved,resolved -> re-open,resolved -> closed,re-open -> in-progress五种,如下图
工作流我们进行权限的分析,open -> in-progress,in-progress -> resolved,re-open -> in-progress 为 coder 的权限,resolved -> closed,resolved -> re-open 为leader 的权限,在事件的各个状态中可由拥有该权限的人修改该事情的状态直到结束,在简单研究了源码后大致了解其工作流程,加上该项目几近一年未更新且bug较多,于是自己有了些想法特地记录下来,当然最后也没有实现:)
首先是权限一个model,事件流一个model,接下来就是用户操作该事件时判断是否有权限,传统做法我想应该是一个记录用户权限的model,当需要判断的时候则从model中查询即可。
在我自己的yy中,考虑到一种情况是权限可能不会很多(通常情况下项目的权限也不会很多,当然是以自己接触到的这个项目需求考虑的),小于20种,如果用户很多则这张用户权限表会比较大,查询会有一定时间消耗(后来觉得此文最后要讲述的方法没必要也是基于对mysql查性能的不了解),所以结合自己对位运算的了解yy了如下的方法:
给用户一个权限的值,没错是值,这个值初始化为0。
将不多(前提是不多)的权限用状态压缩,如有权限a,b,c则压缩成001,010,100,即1,2,4这3个值,所以这是我强调权限种类不多的原因,当权限超过30种就会爆int :)
接下来就是骚操作的开始,假设用户的权限值为x,需要增删查的权限为y:
- 增 x = x | y
- 删 x = x ^ y
- 查 x & y
这样就不必维护一张可能会比较大的表,同时查询的时间复杂度O(1)
最后没有用这种方法基于几个考虑:
1.感觉有点骚怕背锅
2.对于mysql查个几十万条的数据表应该也没什么压力
3.最重要的一点,这个项目后来我没接手做别人负责了:)