Added caching to allowed indices matcher

In order to prevent too many automata constructions (which can be expensive) all the time, the automatas are now cached per action/privilege (since there are limited number of those, we don't expect a cache explosion).

 Closes elastic/elasticsearch#125

Original commit: elastic/x-pack-elasticsearch@27a4e1fdbe
This commit is contained in:
uboness 2014-10-10 19:26:35 +02:00
parent f2aca1e9bc
commit 5b3ae0c4d9
3 changed files with 65 additions and 15 deletions

View File

@ -9,6 +9,10 @@ import org.elasticsearch.action.CompositeIndicesRequest;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.base.Predicate;
import org.elasticsearch.common.cache.Cache;
import org.elasticsearch.common.cache.CacheBuilder;
import org.elasticsearch.common.cache.CacheLoader;
import org.elasticsearch.common.cache.LoadingCache;
import org.elasticsearch.common.collect.ImmutableList;
import org.elasticsearch.shield.User;
import org.elasticsearch.shield.authz.indicesresolver.DefaultIndicesResolver;
@ -144,6 +148,34 @@ public interface Permission {
}
};
private final LoadingCache<String, Predicate<String>> allowedIndicesMatchersForAction = CacheBuilder.newBuilder()
.build(new CacheLoader<String, Predicate<String>>() {
@Override
public Predicate<String> load(String action) throws Exception {
ImmutableList.Builder<String> indices = ImmutableList.builder();
for (Group group : groups) {
if (group.actionMatcher.apply(action)) {
indices.add(group.indices);
}
}
return new AutomatonPredicate(Automatons.patterns(indices.build()));
}
});
private final LoadingCache<Privilege.Index, Predicate<String>> allowedIndicesMatchersForPrivilege = CacheBuilder.newBuilder()
.build(new CacheLoader<Privilege.Index, Predicate<String>>() {
@Override
public Predicate<String> load(Privilege.Index privilege) throws Exception {
ImmutableList.Builder<String> indices = ImmutableList.builder();
for (Group group : groups) {
if (group.privilege.implies(privilege)) {
indices.add(group.indices);
}
}
return new AutomatonPredicate(Automatons.patterns(indices.build()));
}
});
private final IndicesResolver[] indicesResolvers;
private final Group[] groups;
@ -152,7 +184,6 @@ public interface Permission {
this.groups = new Group[0];
}
public Indices(AuthorizationService authzService, Collection<Group> groups) {
this.groups = groups.toArray(new Group[groups.size()]);
this.indicesResolvers = new IndicesResolver[] {
@ -170,13 +201,7 @@ public interface Permission {
* has the given privilege for.
*/
public Predicate<String> allowedIndicesMatcher(Privilege.Index privilege) {
ImmutableList.Builder<String> indices = ImmutableList.builder();
for (Group group : groups) {
if (group.privilege.implies(privilege)) {
indices.add(group.indices);
}
}
return new AutomatonPredicate(Automatons.patterns(indices.build()));
return allowedIndicesMatchersForPrivilege.getUnchecked(privilege);
}
/**
@ -184,13 +209,7 @@ public interface Permission {
* has the privilege for executing the given action on.
*/
public Predicate<String> allowedIndicesMatcher(String action) {
ImmutableList.Builder<String> indices = ImmutableList.builder();
for (Group group : groups) {
if (group.actionMatcher.apply(action)) {
indices.add(group.indices);
}
}
return new AutomatonPredicate(Automatons.patterns(indices.build()));
return allowedIndicesMatchersForAction.getUnchecked(action);
}
@Override @SuppressWarnings("unchecked")

View File

@ -47,6 +47,23 @@ public abstract class Privilege<P extends Privilege<P>> {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Privilege privilege = (Privilege) o;
if (name != null ? !name.equals(privilege.name) : privilege.name != null) return false;
return true;
}
@Override
public int hashCode() {
return name != null ? name.hashCode() : 0;
}
public abstract Predicate<String> predicate();
public abstract boolean implies(P other);

View File

@ -36,11 +36,25 @@ public class PermissionTests extends ElasticsearchTestCase {
testAllowedIndicesMatcher(permission.indices().allowedIndicesMatcher(GET));
}
@Test
public void testAllowedIndicesMatcher_Privilege_Caching() throws Exception {
Predicate<String> matcher1 = permission.indices().allowedIndicesMatcher(GET.plus(SEARCH).plus(WRITE));
Predicate<String> matcher2 = permission.indices().allowedIndicesMatcher(GET.plus(SEARCH).plus(WRITE));
assertThat(matcher1, is(matcher2));
}
@Test
public void testAllowedIndicesMatcher_Action() throws Exception {
testAllowedIndicesMatcher(permission.indices().allowedIndicesMatcher(GetAction.NAME));
}
@Test
public void testAllowedIndicesMatcher_Action_Caching() throws Exception {
Predicate<String> matcher1 = permission.indices().allowedIndicesMatcher(GetAction.NAME);
Predicate<String> matcher2 = permission.indices().allowedIndicesMatcher(GetAction.NAME);
assertThat(matcher1, is(matcher2));
}
private void testAllowedIndicesMatcher(Predicate<String> indicesMatcher) {
assertThat(indicesMatcher.apply("test_123"), is(true));
assertThat(indicesMatcher.apply("foobar"), is(true));