I started to work on a PR for fixing this bug (in XWIKI-21012: Rights are messed up after unregistering a right/uninstalling the like application by surli · Pull Request #2218 · xwiki/xwiki-platform · GitHub) but we found out that the fix Michael proposed would break RightSet/RightMap API. The problem is that right now every rights gets an index based on a static list named
VALUES. This index is limited to 64 entries (which is a limitation for which I opened a ticket btw) and each new registered right gets a new value. The bug is that right now if we unregister a right that wasn’t the last one, every rights registered after it are shifted in the list so their stored index returned by
Right#ordinal doesn’t match anymore the index they are actually stored at in this list.
Moreover, RightSet and RightMap are designed to entirely rely on this index: RightSet even use it to perform the storage on a long, which explains the 64 rights limitation.
There’s no easy solution for fixing this:
- if we put
nullplaceholder in the
VALUESlist to keep the index we risk to get NPE in various API including the ones using RightSet
- we could use a custom Right.UNREGISTERED placeholder, but then it means the RightSet would contain several times this right in case of multiple calls of unregister which breaks the contract of the set
- we could try to shift the values of the right after the one unregistered, but then the RightSet in memory wouldn’t be valid anymore and we risk to obtain an
IndexOutOfBoundExceptionas its max size wouldn’t be valid anymore
So it feels like the only way to solve this would be to stop having implementations of RightSet and RightMap entirely based on the index of rights, if we’re aiming to support unregistering of rights.
AFAIK this implementation was made by @dgervalle for solving performance issue, but that was a long time ago, I have no idea if we still need such optimization now.
Changing current implementation would also automatically fix the 64 rights limitation.
Another solution, if we want to keep current design, would be to find a way to mark a right as “inactive” somehow: so we’d keep it in the list, but just disable it when calling unregister. It doesn’t look very difficult, at first sight, but there’s probably a huge amount of places where we’d need to actually check if a right is active or not…
Note that I’d like first to have opinions on what direction we want to take, we can discuss later on which branch to apply the solution knowing that it’s a bug impacting LTS too.