Skip to content

Commit

Permalink
fix: compile cache doesn't take effect and add md5 string as cacheKey (
Browse files Browse the repository at this point in the history
…#259)

Signed-off-by: tangyang <[email protected]>
  • Loading branch information
tangyang9464 authored Mar 21, 2022
1 parent 629f545 commit 5b43351
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 92 deletions.
2 changes: 1 addition & 1 deletion examples/rbac_policy.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin
g, alice, data2_admin
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,11 @@
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>

</project>
45 changes: 31 additions & 14 deletions src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.casbin.jcasbin.effect.Effect;
import org.casbin.jcasbin.effect.Effector;
import org.casbin.jcasbin.effect.StreamEffector;
import org.casbin.jcasbin.effect.StreamEffectorResult;
import org.casbin.jcasbin.exception.CasbinAdapterException;
import org.casbin.jcasbin.exception.CasbinEffectorException;
import org.casbin.jcasbin.exception.CasbinMatcherException;
Expand Down Expand Up @@ -65,6 +64,8 @@ public class CoreEnforcer {
boolean autoNotifyWatcher = true;
boolean autoNotifyDispatcher = true;

private AviatorEvaluatorInstance aviatorEval;

void initialize() {
rmMap = new HashMap<>();
eft = new DefaultEffector();
Expand All @@ -74,7 +75,9 @@ void initialize() {
autoSave = true;
autoBuildRoleLinks = true;
dispatcher = null;
aviatorEval = AviatorEvaluator.newInstance();
initRmMap();
initBuiltInFunction();
}

/**
Expand Down Expand Up @@ -323,6 +326,17 @@ private void initRmMap() {
}
}

private void initBuiltInFunction(){
for (Map.Entry<String, AviatorFunction> entry : fm.fm.entrySet()) {
AviatorFunction function = entry.getValue();

if(aviatorEval.containsFunction(function.getName())){
aviatorEval.removeFunction(function.getName());
}
aviatorEval.addFunction(function);
}
}

/**
* clearRmMap clears rmMap.
*/
Expand Down Expand Up @@ -400,28 +414,30 @@ private boolean enforce(String matcher, Object... rvals) {
return true;
}

Map<String, AviatorFunction> functions = new HashMap<>();
for (Map.Entry<String, AviatorFunction> entry : fm.fm.entrySet()) {
String key = entry.getKey();
AviatorFunction function = entry.getValue();

functions.put(key, function);
boolean compileCached = true;
if(fm.isModify){
compileCached = false;
initBuiltInFunction();
fm.isModify=false;
}
Map<String, AviatorFunction> gFunctions = new HashMap<>();
if (model.model.containsKey("g")) {
for (Map.Entry<String, Assertion> entry : model.model.get("g").entrySet()) {
String key = entry.getKey();
Assertion ast = entry.getValue();

RoleManager rm = ast.rm;
functions.put(key, BuiltInFunctions.generateGFunction(key, rm));
AviatorFunction aviatorFunction = BuiltInFunctions.generateGFunctionClass.generateGFunction(key, rm);
gFunctions.put(key, aviatorFunction);

BuiltInFunctions.generateGFunctionClass.updateGFunctionCache(key);
}
}
AviatorEvaluatorInstance aviatorEval = AviatorEvaluator.newInstance();
for (AviatorFunction f : functions.values()) {
if (aviatorEval.containsFunction(f.getName())) {
aviatorEval.removeFunction(f.getName());
for (AviatorFunction f : gFunctions.values()) {
if (!aviatorEval.containsFunction(f.getName())) {
aviatorEval.addFunction(f);
compileCached = false;
}
aviatorEval.addFunction(f);
}
fm.setAviatorEval(aviatorEval);

Expand All @@ -445,7 +461,8 @@ private boolean enforce(String matcher, Object... rvals) {
}

expString = Util.convertInSyntax(expString);
Expression expression = aviatorEval.compile(expString, true);
// Use md5 encryption as cacheKey to prevent expString from being too long
Expression expression = aviatorEval.compile(Util.md5(expString),expString, compileCached);

StreamEffector streamEffector = null;
try {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/casbin/jcasbin/model/FunctionMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ public class FunctionMap {
*/
public Map<String, AviatorFunction> fm;

public boolean isModify = false;

/**
* addFunction adds an expression function.
*
Expand All @@ -38,6 +40,7 @@ public class FunctionMap {
*/
public void addFunction(String name, AviatorFunction function) {
fm.put(name, function);
isModify=true;
}

/**
Expand Down
164 changes: 87 additions & 77 deletions src/main/java/org/casbin/jcasbin/util/BuiltInFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,98 +333,108 @@ public static boolean allMatch(String key1, String key2) {
return key1.equals(key2);
}

/**
* generateGFunction is the factory method of the g(_, _) function.
*
* @param name the name of the g(_, _) function, can be "g", "g2", ..
* @param rm the role manager used by the function.
* @return the function.
*/
public static AviatorFunction generateGFunction(String name, RoleManager rm) {

Map<String, AviatorBoolean> memorized = new HashMap<>();
public static class generateGFunctionClass{
// key:name such as g,g2 value:user-role mapping
private static Map<String, Map<String, AviatorBoolean>> memorizedMap = new HashMap<>();

return new AbstractVariadicFunction() {
@Override
public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
int len = args.length;
if(len < 2){
return AviatorBoolean.valueOf(false);
}
Object name1Obj = FunctionUtils.getJavaObject(args[0], env);
String name2 = FunctionUtils.getStringValue(args[1], env);
Sequence name1List = null;
String name1 = null;
if (name1Obj instanceof java.util.List) {
name1List = RuntimeUtils.seq(name1Obj,env);
} else{
name1 = (String) name1Obj;
}
public static void updateGFunctionCache(String name){
Map<String, AviatorBoolean> memorized = memorizedMap.get(name);
memorized = new HashMap<>();
}

String key = "";
for (int i = 0; i < len; i++) {
Object nameObj = FunctionUtils.getJavaObject(args[i], env);
if (nameObj instanceof java.util.List) {
Sequence nameList = RuntimeUtils.seq(name, env);
for (Object obj : nameList) {
key += ";" + obj;
/**
* generateGFunction is the factory method of the g(_, _) function.
*
* @param name the name of the g(_, _) function, can be "g", "g2", ..
* @param rm the role manager used by the function.
* @return the function.
*/
public static AviatorFunction generateGFunction(String name, RoleManager rm) {
memorizedMap.put(name,new HashMap<>());

return new AbstractVariadicFunction() {
@Override
public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
Map<String, AviatorBoolean> memorized = memorizedMap.get(name);
int len = args.length;
if(len < 2){
return AviatorBoolean.valueOf(false);
}
Object name1Obj = FunctionUtils.getJavaObject(args[0], env);
String name2 = FunctionUtils.getStringValue(args[1], env);
Sequence name1List = null;
String name1 = null;
if (name1Obj instanceof java.util.List) {
name1List = RuntimeUtils.seq(name1Obj,env);
} else{
name1 = (String) name1Obj;
}

String key = "";
for (int i = 0; i < len; i++) {
Object nameObj = FunctionUtils.getJavaObject(args[i], env);
if (nameObj instanceof java.util.List) {
Sequence nameList = RuntimeUtils.seq(name, env);
for (Object obj : nameList) {
key += ";" + obj;
}
} else {
key += ";" + nameObj;
}
} else {
key += ";" + nameObj;
}
}

AviatorBoolean value = memorized.get(key);
if (value != null) {
return value;
}
AviatorBoolean value = memorized.get(key);
if (value != null) {
return value;
}

if (rm == null) {
value = AviatorBoolean.valueOf(name1.equals(name2));
} else if (len == 2) {
if (name1List!=null) {
boolean res = false;
for (Object obj : name1List) {
if (rm.hasLink((String) obj, name2)){
res = true;
break;
if (rm == null) {
value = AviatorBoolean.valueOf(name1.equals(name2));
} else if (len == 2) {
if (name1List!=null) {
boolean res = false;
for (Object obj : name1List) {
if (rm.hasLink((String) obj, name2)){
res = true;
break;
}
}
value = AviatorBoolean.valueOf(res);
}
value = AviatorBoolean.valueOf(res);
}
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2));
} else if (len == 3) {
String domain = FunctionUtils.getStringValue(args[2], env);
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2, domain));
} else if (len == 4) {
String p_dom = FunctionUtils.getStringValue(args[3], env);
Object domainObj = FunctionUtils.getJavaObject(args[2], env);

boolean res = false;
if (domainObj instanceof java.util.List){
Sequence domainSeq = RuntimeUtils.seq(domainObj,env);
for (Object r_dom : domainSeq) {
if (r_dom.equals(p_dom) && rm.hasLink(name1, name2, (String) r_dom)){
res = true;
break;
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2));
} else if (len == 3) {
String domain = FunctionUtils.getStringValue(args[2], env);
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2, domain));
} else if (len == 4) {
String p_dom = FunctionUtils.getStringValue(args[3], env);
Object domainObj = FunctionUtils.getJavaObject(args[2], env);

boolean res = false;
if (domainObj instanceof java.util.List){
Sequence domainSeq = RuntimeUtils.seq(domainObj,env);
for (Object r_dom : domainSeq) {
if (r_dom.equals(p_dom) && rm.hasLink(name1, name2, (String) r_dom)){
res = true;
break;
}
}
}
value = AviatorBoolean.valueOf(res);
} else {
value = AviatorBoolean.valueOf(false);
}
value = AviatorBoolean.valueOf(res);
} else {
value = AviatorBoolean.valueOf(false);
memorized.put(key, value);
return value;
}
memorized.put(key, value);
return value;
}

@Override
public String getName() {
return name;
}
};
@Override
public String getName() {
return name;
}
};
}
}

/**
* eval calculates the stringified boolean expression and return its result.
*
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/casbin/jcasbin/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

package org.casbin.jcasbin.util;

import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
Expand All @@ -22,6 +25,7 @@

import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -34,6 +38,9 @@ public class Util {

private static Logger LOGGER = LoggerFactory.getLogger("org.casbin.jcasbin");

private static HashFunction hf = Hashing.md5();
private static Charset defaultCharset = Charset.forName("UTF-8");

/**
* logPrint prints the log.
*
Expand Down Expand Up @@ -283,4 +290,9 @@ public static boolean hasEval(String exp) {
public static String replaceEval(String s, String replacement) {
return evalReg.matcher(s).replaceAll("(" + replacement + ")");
}

public static String md5(String data) {
HashCode hash = hf.newHasher().putString(data, defaultCharset).hash();
return hash.toString();
}
}

0 comments on commit 5b43351

Please sign in to comment.