This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin.git
The following commit(s) were added to refs/heads/master by this push:
new aca1f8f perf: optimize batch policy removal (#1729)
aca1f8f is described below
commit aca1f8f096cc78ba53c726d4a560754cec0cc272
Author: Nhan (Nolan) Huynh <[email protected]>
AuthorDate: Tue Aug 4 14:56:39 2026 +0700
perf: optimize batch policy removal (#1729)
---
management_api_b_test.go | 33 +++++++++++++++++++++++++++++++++
model/policy.go | 39 +++++++++++++++++++++++++++++++--------
2 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/management_api_b_test.go b/management_api_b_test.go
index 1bc534c..debd27b 100644
--- a/management_api_b_test.go
+++ b/management_api_b_test.go
@@ -176,3 +176,36 @@ func BenchmarkRemovePolicyLarge(b *testing.B) {
_, _ = e.RemovePolicy(fmt.Sprintf("user%d", rand.Intn(10000)),
fmt.Sprintf("data%d", rand.Intn(10000)/10), "read")
}
}
+
+func BenchmarkRemovePoliciesLarge(b *testing.B) {
+ e, _ := NewEnforcer("examples/basic_model.conf")
+
+ const batchSize = 100
+
+ for i := 0; i < b.N; i++ {
+ b.StopTimer()
+ rules := make([][]string, 0, batchSize)
+ for j := 0; j < batchSize; j++ {
+ id := i*batchSize + j
+ rules = append(rules, []string{fmt.Sprintf("user%d",
id), fmt.Sprintf("data%d", id/10), "read"})
+ }
+
+ added, err := e.AddPolicies(rules)
+ if err != nil {
+ b.Fatal(err)
+ }
+ if !added {
+ b.Fatal("expected AddPolicies to add rules")
+ }
+
+ b.StartTimer()
+ removed, err := e.RemovePolicies(rules)
+ b.StopTimer()
+ if err != nil {
+ b.Fatal(err)
+ }
+ if !removed {
+ b.Fatal("expected RemovePolicies to remove rules")
+ }
+ }
+}
diff --git a/model/policy.go b/model/policy.go
index 1d153b7..426ddee 100644
--- a/model/policy.go
+++ b/model/policy.go
@@ -346,24 +346,47 @@ func (model Model) RemovePolicies(sec string, ptype
string, rules [][]string) (b
// RemovePoliciesWithAffected removes policy rules from the model, and returns
affected rules.
func (model Model) RemovePoliciesWithAffected(sec string, ptype string, rules
[][]string) ([][]string, error) {
- _, err := model.GetAssertion(sec, ptype)
+ assertion, err := model.GetAssertion(sec, ptype)
if err != nil {
return nil, err
}
+
var affected [][]string
+ removeSet := make(map[string]struct{}, len(rules))
+
for _, rule := range rules {
- index, ok := model[sec][ptype].PolicyMap[strings.Join(rule,
DefaultSep)]
- if !ok {
+ key := strings.Join(rule, DefaultSep)
+ if _, ok := assertion.PolicyMap[key]; !ok {
continue
}
-
+ if _, exists := removeSet[key]; exists {
+ continue
+ }
+ if affected == nil {
+ affected = make([][]string, 0, len(rules))
+ }
affected = append(affected, rule)
- model[sec][ptype].Policy =
append(model[sec][ptype].Policy[:index], model[sec][ptype].Policy[index+1:]...)
- delete(model[sec][ptype].PolicyMap, strings.Join(rule,
DefaultSep))
- for i := index; i < len(model[sec][ptype].Policy); i++ {
-
model[sec][ptype].PolicyMap[strings.Join(model[sec][ptype].Policy[i],
DefaultSep)] = i
+ removeSet[key] = struct{}{}
+ }
+
+ if len(removeSet) == 0 {
+ return affected, nil
+ }
+
+ compactPolicy := assertion.Policy[:0]
+ compactPolicyMap := make(map[string]int,
len(assertion.Policy)-len(removeSet))
+ for _, policyRule := range assertion.Policy {
+ key := strings.Join(policyRule, DefaultSep)
+ if _, ok := removeSet[key]; ok {
+ continue
}
+ compactPolicyMap[key] = len(compactPolicy)
+ compactPolicy = append(compactPolicy, policyRule)
}
+
+ assertion.Policy = compactPolicy
+ assertion.PolicyMap = compactPolicyMap
+
return affected, nil
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]