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]

Reply via email to