snapshot of https://github.com/casbin/casbin.git (master, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
183
enforcer_cached_synced.go
Normal file
183
enforcer_cached_synced.go
Normal file
@@ -0,0 +1,183 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package casbin
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/casbin/casbin/v3/persist/cache"
|
||||
)
|
||||
|
||||
// SyncedCachedEnforcer wraps Enforcer and provides decision sync cache.
|
||||
type SyncedCachedEnforcer struct {
|
||||
*SyncedEnforcer
|
||||
expireTime time.Duration
|
||||
cache cache.Cache
|
||||
enableCache int32
|
||||
locker *sync.RWMutex
|
||||
}
|
||||
|
||||
// NewSyncedCachedEnforcer creates a sync cached enforcer via file or DB.
|
||||
func NewSyncedCachedEnforcer(params ...interface{}) (*SyncedCachedEnforcer, error) {
|
||||
e := &SyncedCachedEnforcer{}
|
||||
var err error
|
||||
e.SyncedEnforcer, err = NewSyncedEnforcer(params...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e.enableCache = 1
|
||||
e.cache, _ = cache.NewSyncCache()
|
||||
e.locker = new(sync.RWMutex)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// EnableCache determines whether to enable cache on Enforce(). When enableCache is enabled, cached result (true | false) will be returned for previous decisions.
|
||||
func (e *SyncedCachedEnforcer) EnableCache(enableCache bool) {
|
||||
var enabled int32
|
||||
if enableCache {
|
||||
enabled = 1
|
||||
}
|
||||
atomic.StoreInt32(&e.enableCache, enabled)
|
||||
}
|
||||
|
||||
// Enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act).
|
||||
// if rvals is not string , ignore the cache.
|
||||
func (e *SyncedCachedEnforcer) Enforce(rvals ...interface{}) (bool, error) {
|
||||
if atomic.LoadInt32(&e.enableCache) == 0 {
|
||||
return e.SyncedEnforcer.Enforce(rvals...)
|
||||
}
|
||||
|
||||
key, ok := e.getKey(rvals...)
|
||||
if !ok {
|
||||
return e.SyncedEnforcer.Enforce(rvals...)
|
||||
}
|
||||
|
||||
if res, err := e.getCachedResult(key); err == nil {
|
||||
return res, nil
|
||||
} else if err != cache.ErrNoSuchKey {
|
||||
return res, err
|
||||
}
|
||||
|
||||
res, err := e.SyncedEnforcer.Enforce(rvals...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = e.setCachedResult(key, res, e.expireTime)
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) LoadPolicy() error {
|
||||
if atomic.LoadInt32(&e.enableCache) != 0 {
|
||||
if err := e.cache.Clear(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.SyncedEnforcer.LoadPolicy()
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) AddPolicy(params ...interface{}) (bool, error) {
|
||||
if ok, err := e.checkOneAndRemoveCache(params...); !ok {
|
||||
return ok, err
|
||||
}
|
||||
return e.SyncedEnforcer.AddPolicy(params...)
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) AddPolicies(rules [][]string) (bool, error) {
|
||||
if ok, err := e.checkManyAndRemoveCache(rules); !ok {
|
||||
return ok, err
|
||||
}
|
||||
return e.SyncedEnforcer.AddPolicies(rules)
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) RemovePolicy(params ...interface{}) (bool, error) {
|
||||
if ok, err := e.checkOneAndRemoveCache(params...); !ok {
|
||||
return ok, err
|
||||
}
|
||||
return e.SyncedEnforcer.RemovePolicy(params...)
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) RemovePolicies(rules [][]string) (bool, error) {
|
||||
if ok, err := e.checkManyAndRemoveCache(rules); !ok {
|
||||
return ok, err
|
||||
}
|
||||
return e.SyncedEnforcer.RemovePolicies(rules)
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) getCachedResult(key string) (res bool, err error) {
|
||||
return e.cache.Get(key)
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) SetExpireTime(expireTime time.Duration) {
|
||||
e.locker.Lock()
|
||||
defer e.locker.Unlock()
|
||||
e.expireTime = expireTime
|
||||
}
|
||||
|
||||
// SetCache need to be sync cache.
|
||||
func (e *SyncedCachedEnforcer) SetCache(c cache.Cache) {
|
||||
e.locker.Lock()
|
||||
defer e.locker.Unlock()
|
||||
e.cache = c
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) setCachedResult(key string, res bool, extra ...interface{}) error {
|
||||
return e.cache.Set(key, res, extra...)
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) getKey(params ...interface{}) (string, bool) {
|
||||
return GetCacheKey(params...)
|
||||
}
|
||||
|
||||
// InvalidateCache deletes all the existing cached decisions.
|
||||
func (e *SyncedCachedEnforcer) InvalidateCache() error {
|
||||
return e.cache.Clear()
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) checkOneAndRemoveCache(params ...interface{}) (bool, error) {
|
||||
if atomic.LoadInt32(&e.enableCache) != 0 {
|
||||
key, ok := e.getKey(params...)
|
||||
if ok {
|
||||
if err := e.cache.Delete(key); err != nil && err != cache.ErrNoSuchKey {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (e *SyncedCachedEnforcer) checkManyAndRemoveCache(rules [][]string) (bool, error) {
|
||||
if len(rules) != 0 {
|
||||
if atomic.LoadInt32(&e.enableCache) != 0 {
|
||||
for _, rule := range rules {
|
||||
irule := make([]interface{}, len(rule))
|
||||
for i, param := range rule {
|
||||
irule[i] = param
|
||||
}
|
||||
key, _ := e.getKey(irule...)
|
||||
if err := e.cache.Delete(key); err != nil && err != cache.ErrNoSuchKey {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
Reference in New Issue
Block a user