Skip to content

Commit 5b43351

Browse files
authored
fix: compile cache doesn't take effect and add md5 string as cacheKey (casbin#259)
Signed-off-by: tangyang <[email protected]>
1 parent 629f545 commit 5b43351

File tree

6 files changed

+139
-92
lines changed

6 files changed

+139
-92
lines changed

examples/rbac_policy.csv

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ p, alice, data1, read
22
p, bob, data2, write
33
p, data2_admin, data2, read
44
p, data2_admin, data2, write
5-
g, alice, data2_admin
5+
g, alice, data2_admin

pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@
222222
<artifactId>gson</artifactId>
223223
<version>2.8.9</version>
224224
</dependency>
225+
<dependency>
226+
<groupId>com.google.guava</groupId>
227+
<artifactId>guava</artifactId>
228+
<version>19.0</version>
229+
</dependency>
225230
</dependencies>
226231

227232
</project>

src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java

+31-14
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.casbin.jcasbin.effect.Effect;
2828
import org.casbin.jcasbin.effect.Effector;
2929
import org.casbin.jcasbin.effect.StreamEffector;
30-
import org.casbin.jcasbin.effect.StreamEffectorResult;
3130
import org.casbin.jcasbin.exception.CasbinAdapterException;
3231
import org.casbin.jcasbin.exception.CasbinEffectorException;
3332
import org.casbin.jcasbin.exception.CasbinMatcherException;
@@ -65,6 +64,8 @@ public class CoreEnforcer {
6564
boolean autoNotifyWatcher = true;
6665
boolean autoNotifyDispatcher = true;
6766

67+
private AviatorEvaluatorInstance aviatorEval;
68+
6869
void initialize() {
6970
rmMap = new HashMap<>();
7071
eft = new DefaultEffector();
@@ -74,7 +75,9 @@ void initialize() {
7475
autoSave = true;
7576
autoBuildRoleLinks = true;
7677
dispatcher = null;
78+
aviatorEval = AviatorEvaluator.newInstance();
7779
initRmMap();
80+
initBuiltInFunction();
7881
}
7982

8083
/**
@@ -323,6 +326,17 @@ private void initRmMap() {
323326
}
324327
}
325328

329+
private void initBuiltInFunction(){
330+
for (Map.Entry<String, AviatorFunction> entry : fm.fm.entrySet()) {
331+
AviatorFunction function = entry.getValue();
332+
333+
if(aviatorEval.containsFunction(function.getName())){
334+
aviatorEval.removeFunction(function.getName());
335+
}
336+
aviatorEval.addFunction(function);
337+
}
338+
}
339+
326340
/**
327341
* clearRmMap clears rmMap.
328342
*/
@@ -400,28 +414,30 @@ private boolean enforce(String matcher, Object... rvals) {
400414
return true;
401415
}
402416

403-
Map<String, AviatorFunction> functions = new HashMap<>();
404-
for (Map.Entry<String, AviatorFunction> entry : fm.fm.entrySet()) {
405-
String key = entry.getKey();
406-
AviatorFunction function = entry.getValue();
407-
408-
functions.put(key, function);
417+
boolean compileCached = true;
418+
if(fm.isModify){
419+
compileCached = false;
420+
initBuiltInFunction();
421+
fm.isModify=false;
409422
}
423+
Map<String, AviatorFunction> gFunctions = new HashMap<>();
410424
if (model.model.containsKey("g")) {
411425
for (Map.Entry<String, Assertion> entry : model.model.get("g").entrySet()) {
412426
String key = entry.getKey();
413427
Assertion ast = entry.getValue();
414428

415429
RoleManager rm = ast.rm;
416-
functions.put(key, BuiltInFunctions.generateGFunction(key, rm));
430+
AviatorFunction aviatorFunction = BuiltInFunctions.generateGFunctionClass.generateGFunction(key, rm);
431+
gFunctions.put(key, aviatorFunction);
432+
433+
BuiltInFunctions.generateGFunctionClass.updateGFunctionCache(key);
417434
}
418435
}
419-
AviatorEvaluatorInstance aviatorEval = AviatorEvaluator.newInstance();
420-
for (AviatorFunction f : functions.values()) {
421-
if (aviatorEval.containsFunction(f.getName())) {
422-
aviatorEval.removeFunction(f.getName());
436+
for (AviatorFunction f : gFunctions.values()) {
437+
if (!aviatorEval.containsFunction(f.getName())) {
438+
aviatorEval.addFunction(f);
439+
compileCached = false;
423440
}
424-
aviatorEval.addFunction(f);
425441
}
426442
fm.setAviatorEval(aviatorEval);
427443

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

447463
expString = Util.convertInSyntax(expString);
448-
Expression expression = aviatorEval.compile(expString, true);
464+
// Use md5 encryption as cacheKey to prevent expString from being too long
465+
Expression expression = aviatorEval.compile(Util.md5(expString),expString, compileCached);
449466

450467
StreamEffector streamEffector = null;
451468
try {

src/main/java/org/casbin/jcasbin/model/FunctionMap.java

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ public class FunctionMap {
3030
*/
3131
public Map<String, AviatorFunction> fm;
3232

33+
public boolean isModify = false;
34+
3335
/**
3436
* addFunction adds an expression function.
3537
*
@@ -38,6 +40,7 @@ public class FunctionMap {
3840
*/
3941
public void addFunction(String name, AviatorFunction function) {
4042
fm.put(name, function);
43+
isModify=true;
4144
}
4245

4346
/**

src/main/java/org/casbin/jcasbin/util/BuiltInFunctions.java

+87-77
Original file line numberDiff line numberDiff line change
@@ -333,98 +333,108 @@ public static boolean allMatch(String key1, String key2) {
333333
return key1.equals(key2);
334334
}
335335

336-
/**
337-
* generateGFunction is the factory method of the g(_, _) function.
338-
*
339-
* @param name the name of the g(_, _) function, can be "g", "g2", ..
340-
* @param rm the role manager used by the function.
341-
* @return the function.
342-
*/
343-
public static AviatorFunction generateGFunction(String name, RoleManager rm) {
344336

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

347-
return new AbstractVariadicFunction() {
348-
@Override
349-
public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
350-
int len = args.length;
351-
if(len < 2){
352-
return AviatorBoolean.valueOf(false);
353-
}
354-
Object name1Obj = FunctionUtils.getJavaObject(args[0], env);
355-
String name2 = FunctionUtils.getStringValue(args[1], env);
356-
Sequence name1List = null;
357-
String name1 = null;
358-
if (name1Obj instanceof java.util.List) {
359-
name1List = RuntimeUtils.seq(name1Obj,env);
360-
} else{
361-
name1 = (String) name1Obj;
362-
}
341+
public static void updateGFunctionCache(String name){
342+
Map<String, AviatorBoolean> memorized = memorizedMap.get(name);
343+
memorized = new HashMap<>();
344+
}
363345

364-
String key = "";
365-
for (int i = 0; i < len; i++) {
366-
Object nameObj = FunctionUtils.getJavaObject(args[i], env);
367-
if (nameObj instanceof java.util.List) {
368-
Sequence nameList = RuntimeUtils.seq(name, env);
369-
for (Object obj : nameList) {
370-
key += ";" + obj;
346+
/**
347+
* generateGFunction is the factory method of the g(_, _) function.
348+
*
349+
* @param name the name of the g(_, _) function, can be "g", "g2", ..
350+
* @param rm the role manager used by the function.
351+
* @return the function.
352+
*/
353+
public static AviatorFunction generateGFunction(String name, RoleManager rm) {
354+
memorizedMap.put(name,new HashMap<>());
355+
356+
return new AbstractVariadicFunction() {
357+
@Override
358+
public AviatorObject variadicCall(Map<String, Object> env, AviatorObject... args) {
359+
Map<String, AviatorBoolean> memorized = memorizedMap.get(name);
360+
int len = args.length;
361+
if(len < 2){
362+
return AviatorBoolean.valueOf(false);
363+
}
364+
Object name1Obj = FunctionUtils.getJavaObject(args[0], env);
365+
String name2 = FunctionUtils.getStringValue(args[1], env);
366+
Sequence name1List = null;
367+
String name1 = null;
368+
if (name1Obj instanceof java.util.List) {
369+
name1List = RuntimeUtils.seq(name1Obj,env);
370+
} else{
371+
name1 = (String) name1Obj;
372+
}
373+
374+
String key = "";
375+
for (int i = 0; i < len; i++) {
376+
Object nameObj = FunctionUtils.getJavaObject(args[i], env);
377+
if (nameObj instanceof java.util.List) {
378+
Sequence nameList = RuntimeUtils.seq(name, env);
379+
for (Object obj : nameList) {
380+
key += ";" + obj;
381+
}
382+
} else {
383+
key += ";" + nameObj;
371384
}
372-
} else {
373-
key += ";" + nameObj;
374385
}
375-
}
376386

377-
AviatorBoolean value = memorized.get(key);
378-
if (value != null) {
379-
return value;
380-
}
387+
AviatorBoolean value = memorized.get(key);
388+
if (value != null) {
389+
return value;
390+
}
381391

382-
if (rm == null) {
383-
value = AviatorBoolean.valueOf(name1.equals(name2));
384-
} else if (len == 2) {
385-
if (name1List!=null) {
386-
boolean res = false;
387-
for (Object obj : name1List) {
388-
if (rm.hasLink((String) obj, name2)){
389-
res = true;
390-
break;
392+
if (rm == null) {
393+
value = AviatorBoolean.valueOf(name1.equals(name2));
394+
} else if (len == 2) {
395+
if (name1List!=null) {
396+
boolean res = false;
397+
for (Object obj : name1List) {
398+
if (rm.hasLink((String) obj, name2)){
399+
res = true;
400+
break;
401+
}
391402
}
403+
value = AviatorBoolean.valueOf(res);
392404
}
393-
value = AviatorBoolean.valueOf(res);
394-
}
395-
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2));
396-
} else if (len == 3) {
397-
String domain = FunctionUtils.getStringValue(args[2], env);
398-
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2, domain));
399-
} else if (len == 4) {
400-
String p_dom = FunctionUtils.getStringValue(args[3], env);
401-
Object domainObj = FunctionUtils.getJavaObject(args[2], env);
402-
403-
boolean res = false;
404-
if (domainObj instanceof java.util.List){
405-
Sequence domainSeq = RuntimeUtils.seq(domainObj,env);
406-
for (Object r_dom : domainSeq) {
407-
if (r_dom.equals(p_dom) && rm.hasLink(name1, name2, (String) r_dom)){
408-
res = true;
409-
break;
405+
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2));
406+
} else if (len == 3) {
407+
String domain = FunctionUtils.getStringValue(args[2], env);
408+
value = AviatorBoolean.valueOf(rm.hasLink(name1, name2, domain));
409+
} else if (len == 4) {
410+
String p_dom = FunctionUtils.getStringValue(args[3], env);
411+
Object domainObj = FunctionUtils.getJavaObject(args[2], env);
412+
413+
boolean res = false;
414+
if (domainObj instanceof java.util.List){
415+
Sequence domainSeq = RuntimeUtils.seq(domainObj,env);
416+
for (Object r_dom : domainSeq) {
417+
if (r_dom.equals(p_dom) && rm.hasLink(name1, name2, (String) r_dom)){
418+
res = true;
419+
break;
420+
}
410421
}
411422
}
423+
value = AviatorBoolean.valueOf(res);
424+
} else {
425+
value = AviatorBoolean.valueOf(false);
412426
}
413-
value = AviatorBoolean.valueOf(res);
414-
} else {
415-
value = AviatorBoolean.valueOf(false);
427+
memorized.put(key, value);
428+
return value;
416429
}
417-
memorized.put(key, value);
418-
return value;
419-
}
420430

421-
@Override
422-
public String getName() {
423-
return name;
424-
}
425-
};
431+
@Override
432+
public String getName() {
433+
return name;
434+
}
435+
};
436+
}
426437
}
427-
428438
/**
429439
* eval calculates the stringified boolean expression and return its result.
430440
*

src/main/java/org/casbin/jcasbin/util/Util.java

+12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
package org.casbin.jcasbin.util;
1616

17+
import com.google.common.hash.HashCode;
18+
import com.google.common.hash.HashFunction;
19+
import com.google.common.hash.Hashing;
1720
import org.apache.commons.csv.CSVFormat;
1821
import org.apache.commons.csv.CSVParser;
1922
import org.apache.commons.csv.CSVRecord;
@@ -22,6 +25,7 @@
2225

2326
import java.io.IOException;
2427
import java.io.StringReader;
28+
import java.nio.charset.Charset;
2529
import java.util.ArrayList;
2630
import java.util.Collections;
2731
import java.util.List;
@@ -34,6 +38,9 @@ public class Util {
3438

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

41+
private static HashFunction hf = Hashing.md5();
42+
private static Charset defaultCharset = Charset.forName("UTF-8");
43+
3744
/**
3845
* logPrint prints the log.
3946
*
@@ -283,4 +290,9 @@ public static boolean hasEval(String exp) {
283290
public static String replaceEval(String s, String replacement) {
284291
return evalReg.matcher(s).replaceAll("(" + replacement + ")");
285292
}
293+
294+
public static String md5(String data) {
295+
HashCode hash = hf.newHasher().putString(data, defaultCharset).hash();
296+
return hash.toString();
297+
}
286298
}

0 commit comments

Comments
 (0)