improve cache invalidation on group events

This commit is contained in:
Sebastian Sdorra
2016-06-26 15:03:28 +02:00
parent 89660e8ac3
commit 9dc1c6fd8e
2 changed files with 83 additions and 37 deletions

View File

@@ -72,6 +72,8 @@ import sonia.scm.util.Util;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import sonia.scm.Filter; import sonia.scm.Filter;
import sonia.scm.group.Group;
import sonia.scm.group.GroupModificationEvent;
import sonia.scm.repository.RepositoryModificationEvent; import sonia.scm.repository.RepositoryModificationEvent;
import sonia.scm.user.UserModificationEvent; import sonia.scm.user.UserModificationEvent;
@@ -162,28 +164,29 @@ public class AuthorizationCollector
if (event instanceof UserModificationEvent) if (event instanceof UserModificationEvent)
{ {
User beforeModification = ((UserModificationEvent) event).getItemBeforeModification(); User beforeModification = ((UserModificationEvent) event).getItemBeforeModification();
if ( shouldCacheBeCleared(user, beforeModification) ) if (shouldCacheBeCleared(user, beforeModification))
{ {
invalidateUserCache(username); invalidateUserCache(username);
} }
else else
{ {
logger.debug("cache of user {} is not invalidated, because admin and active flag has not changed", username); logger.debug("cache of user {} is not invalidated, because admin and active flag has not changed", username);
} }
} }
else else
{ {
invalidateUserCache(username); invalidateUserCache(username);
} }
} }
} }
private boolean shouldCacheBeCleared(User user, User beforeModification) private boolean shouldCacheBeCleared(User user, User beforeModification)
{ {
return user.isAdmin() != beforeModification.isAdmin() || user.isActive() != beforeModification.isActive(); return user.isAdmin() != beforeModification.isAdmin() || user.isActive() != beforeModification.isActive();
} }
private void invalidateUserCache(final String username){ private void invalidateUserCache(final String username)
{
logger.debug("invalidate cache of user {}, because of a event which could change the permissions", username); logger.debug("invalidate cache of user {}, because of a event which could change the permissions", username);
cache.removeAll(new Filter<CacheKey>() cache.removeAll(new Filter<CacheKey>()
{ {
@@ -223,26 +226,26 @@ public class AuthorizationCollector
{ {
logger.debug("clear cache, because a relevant field of repository {} has changed", repository.getName()); logger.debug("clear cache, because a relevant field of repository {} has changed", repository.getName());
cache.clear(); cache.clear();
} }
else else
{ {
logger.debug( logger.debug(
"cache of repository {} is not invalidated, because non relevant fields have changed", "cache of repository {} is not invalidated, because non relevant fields have changed",
repository.getName() repository.getName()
); );
} }
} }
else else
{ {
logger.debug("clear cache, because repository {} has changed", repository.getName()); logger.debug("clear cache, because repository {} has changed", repository.getName());
cache.clear(); cache.clear();
} }
} }
} }
private boolean shouldCacheBeCleared(Repository repository, Repository beforeModification) private boolean shouldCacheBeCleared(Repository repository, Repository beforeModification)
{ {
return repository.isArchived() != beforeModification.isArchived() return repository.isArchived() != beforeModification.isArchived()
|| repository.isPublicReadable() != beforeModification.isPublicReadable() || repository.isPublicReadable() != beforeModification.isPublicReadable()
|| ! repository.getPermissions().equals(beforeModification.getPermissions()); || ! repository.getPermissions().equals(beforeModification.getPermissions());
} }
@@ -271,7 +274,7 @@ public class AuthorizationCollector
logger.debug("clears the whole cache, because global group permission {} has changed", permission.getId()); logger.debug("clears the whole cache, because global group permission {} has changed", permission.getId());
cache.clear(); cache.clear();
} }
else else
{ {
invalidateUserCache(permission.getName()); invalidateUserCache(permission.getName());
} }
@@ -279,26 +282,50 @@ public class AuthorizationCollector
} }
/** /**
* Method description * Invalidates the whole cache, if a group has changed. The cache get cleared for one of the following reasons:
* <ul>
* <li>New group created</li>
* <li>Group was removed</li>
* <li>Group members was modified</li>
* </ul>
* *
* * @param event group event
* @param event
*/ */
@Subscribe @Subscribe
public void onEvent(GroupEvent event) public void onEvent(GroupEvent event)
{ {
if (event.getEventType().isPost()) if (event.getEventType().isPost())
{ {
if (logger.isDebugEnabled()) Group group = event.getItem();
if (event instanceof GroupModificationEvent)
{ {
logger.debug("clear cache, because group {} has changed", Group beforeModification = ((GroupModificationEvent) event).getItemBeforeModification();
event.getItem().getId()); if (shouldCacheBeCleared(group, beforeModification))
{
logger.debug("clear cache, because group {} has changed", group.getId());
cache.clear();
}
else
{
logger.debug(
"cache of group {} is not invalidated, because non relevant fields have changed",
group.getId()
);
}
}
else
{
logger.debug("clear cache, because group {} has changed", group.getId());
cache.clear();
} }
cache.clear();
} }
} }
private boolean shouldCacheBeCleared(Group group, Group beforeModification)
{
return !group.getMembers().equals(beforeModification.getMembers());
}
/** /**
* Method description * Method description
* *
@@ -356,14 +383,14 @@ public class AuthorizationCollector
{ {
List<StoredAssignedPermission> globalPermissions = List<StoredAssignedPermission> globalPermissions =
securitySystem.getPermissions(new Predicate<AssignedPermission>() securitySystem.getPermissions(new Predicate<AssignedPermission>()
{
@Override
public boolean apply(AssignedPermission input)
{ {
return isUserPermitted(user, groups, input);
} @Override
}); public boolean apply(AssignedPermission input)
{
return isUserPermitted(user, groups, input);
}
});
for (StoredAssignedPermission gp : globalPermissions) for (StoredAssignedPermission gp : globalPermissions)
{ {
@@ -414,8 +441,8 @@ public class AuthorizationCollector
private void collectRepositoryPermissions(Builder<Permission> builder, private void collectRepositoryPermissions(Builder<Permission> builder,
Repository repository, User user, GroupNames groups) Repository repository, User user, GroupNames groups)
{ {
List<sonia.scm.repository.Permission> repositoryPermissions = List<sonia.scm.repository.Permission> repositoryPermissions
repository.getPermissions(); = repository.getPermissions();
if (Util.isNotEmpty(repositoryPermissions)) if (Util.isNotEmpty(repositoryPermissions))
{ {
@@ -426,7 +453,7 @@ public class AuthorizationCollector
{ {
hasPermission = true; hasPermission = true;
RepositoryPermission rp = new RepositoryPermission(repository, RepositoryPermission rp = new RepositoryPermission(repository,
permission.getType()); permission.getType());
if (logger.isTraceEnabled()) if (logger.isTraceEnabled())
{ {
@@ -437,7 +464,7 @@ public class AuthorizationCollector
builder.add(rp); builder.add(rp);
} }
} }
if (!hasPermission && logger.isTraceEnabled()) if (!hasPermission && logger.isTraceEnabled())
{ {
logger.trace("no permission for user {} defined at repository {}", user.getName(), repository.getName()); logger.trace("no permission for user {} defined at repository {}", user.getName(), repository.getName());
@@ -517,7 +544,7 @@ public class AuthorizationCollector
PermissionObject perm) PermissionObject perm)
{ {
//J- //J-
return (perm.isGroupPermission() && groups.contains(perm.getName())) return (perm.isGroupPermission() && groups.contains(perm.getName()))
|| ((!perm.isGroupPermission()) && user.getName().equals(perm.getName())); || ((!perm.isGroupPermission()) && user.getName().equals(perm.getName()));
//J+ //J+
} }
@@ -589,7 +616,6 @@ public class AuthorizationCollector
private final String username; private final String username;
} }
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** Field description */ /** Field description */

View File

@@ -59,6 +59,7 @@ import sonia.scm.cache.Cache;
import sonia.scm.cache.CacheManager; import sonia.scm.cache.CacheManager;
import sonia.scm.group.Group; import sonia.scm.group.Group;
import sonia.scm.group.GroupEvent; import sonia.scm.group.GroupEvent;
import sonia.scm.group.GroupModificationEvent;
import sonia.scm.group.GroupNames; import sonia.scm.group.GroupNames;
import sonia.scm.repository.PermissionType; import sonia.scm.repository.PermissionType;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
@@ -163,6 +164,25 @@ public class AuthorizationCollectorTest {
verify(cache).clear(); verify(cache).clear();
} }
/**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.group.GroupEvent)} with modified groups.
*/
@Test
public void testOnGroupModificationEvent()
{
Group group = new Group("xml", "base");
Group modifiedGroup = new Group("xml", "base");
collector.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.BEFORE_MODIFY));
verify(cache, never()).clear();
collector.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.MODIFY));
verify(cache, never()).clear();
modifiedGroup.add("test");
collector.onEvent(new GroupModificationEvent(modifiedGroup, group, HandlerEvent.MODIFY));
verify(cache).clear();
}
/** /**
* Tests {@link AuthorizationCollector#onEvent(sonia.scm.repository.RepositoryEvent)}. * Tests {@link AuthorizationCollector#onEvent(sonia.scm.repository.RepositoryEvent)}.
*/ */