mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
增加policy缓存,降低日志量和计算量
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
package appsrv
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
c := NewCache(1024)
|
||||
c.Set("123", 123)
|
||||
c.Set("456", 456)
|
||||
v := c.Get("123")
|
||||
if v == nil || v.(int) != 123 {
|
||||
t.Error("Key 123 not found")
|
||||
}
|
||||
v = c.Get("456")
|
||||
if v == nil || v.(int) != 456 {
|
||||
t.Error("Key 456 not found")
|
||||
}
|
||||
c.Set("456", 789)
|
||||
v = c.Get("456")
|
||||
if v == nil || v.(int) != 789 {
|
||||
t.Error("Key 456 not changed")
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/appctx"
|
||||
"yunion.io/x/onecloud/pkg/util/hashcache"
|
||||
)
|
||||
|
||||
func AppContextDB(ctx context.Context) *sql.DB {
|
||||
@@ -15,12 +16,12 @@ func AppContextDB(ctx context.Context) *sql.DB {
|
||||
return val.(*sql.DB)
|
||||
}
|
||||
|
||||
func AppContextCache(ctx context.Context) *Cache {
|
||||
func AppContextCache(ctx context.Context) *hashcache.Cache {
|
||||
val := ctx.Value(appctx.APP_CONTEXT_KEY_CACHE)
|
||||
if val == nil {
|
||||
return nil
|
||||
}
|
||||
return val.(*Cache)
|
||||
return val.(*hashcache.Cache)
|
||||
}
|
||||
|
||||
func AppContextApp(ctx context.Context) *Application {
|
||||
|
||||
@@ -2,6 +2,8 @@ package policy
|
||||
|
||||
import (
|
||||
"time"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
@@ -13,6 +15,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/util/conditionparser"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
"yunion.io/x/onecloud/pkg/util/hashcache"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -135,6 +138,8 @@ type SPolicyManager struct {
|
||||
|
||||
failedRetryInterval time.Duration
|
||||
refreshInterval time.Duration
|
||||
|
||||
cache *hashcache.Cache // policy cache
|
||||
}
|
||||
|
||||
func parseJsonPolicy(obj jsonutils.JSONObject) (string, rbacutils.SRbacPolicy, error) {
|
||||
@@ -214,6 +219,8 @@ func (manager *SPolicyManager) start(refreshInterval time.Duration, retryInterva
|
||||
Rules: rbacutils.CompactRules(defaultRules),
|
||||
}
|
||||
}
|
||||
|
||||
manager.cache = hashcache.NewCache(2048, time.Second*5)
|
||||
manager.sync()
|
||||
}
|
||||
|
||||
@@ -232,6 +239,38 @@ func (manager *SPolicyManager) sync() {
|
||||
}
|
||||
|
||||
func (manager *SPolicyManager) Allow(isAdmin bool, userCred mcclient.TokenCredential, service string, resource string, action string, extra ...string) rbacutils.TRbacResult {
|
||||
if manager.cache != nil {
|
||||
isAdminStr := fmt.Sprintf("%v", isAdmin)
|
||||
queryKeys := []string{isAdminStr, userCred.String()}
|
||||
if rbacutils.WILD_MATCH == service || len(service) == 0 {
|
||||
queryKeys = append(queryKeys, rbacutils.WILD_MATCH)
|
||||
}
|
||||
if rbacutils.WILD_MATCH == resource || len(resource) == 0 {
|
||||
queryKeys = append(queryKeys, rbacutils.WILD_MATCH)
|
||||
}
|
||||
if rbacutils.WILD_MATCH == action || len(action) == 0 {
|
||||
queryKeys = append(queryKeys, rbacutils.WILD_MATCH)
|
||||
}
|
||||
if len(extra) > 0 {
|
||||
queryKeys = append(queryKeys, extra...)
|
||||
}
|
||||
key := strings.Join(queryKeys, "-")
|
||||
log.Debugf("%s", key)
|
||||
val := manager.cache.Get(key)
|
||||
if val != nil {
|
||||
log.Debugf("cache hit")
|
||||
return val.(rbacutils.TRbacResult)
|
||||
}
|
||||
log.Debugf("cache miss!!")
|
||||
result := manager.allowWithoutCache(isAdmin, userCred, service, resource, action, extra...)
|
||||
manager.cache.Set(key, result)
|
||||
return result
|
||||
} else {
|
||||
return manager.allowWithoutCache(isAdmin, userCred, service, resource, action, extra...)
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SPolicyManager) allowWithoutCache(isAdmin bool, userCred mcclient.TokenCredential, service string, resource string, action string, extra ...string) rbacutils.TRbacResult {
|
||||
var policies map[string]rbacutils.SRbacPolicy
|
||||
if isAdmin {
|
||||
policies = manager.adminPolicies
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
package appsrv
|
||||
package hashcache
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type cacheNode struct {
|
||||
key string
|
||||
value interface{}
|
||||
key string
|
||||
expire time.Time
|
||||
value interface{}
|
||||
}
|
||||
|
||||
type Cache struct {
|
||||
table []cacheNode
|
||||
lock *sync.Mutex
|
||||
size uint32
|
||||
table []cacheNode
|
||||
lock *sync.Mutex
|
||||
size uint32
|
||||
defaultTtl time.Duration
|
||||
}
|
||||
|
||||
func NewCache(size uint32) *Cache {
|
||||
ca := &Cache{table: make([]cacheNode, size), lock: &sync.Mutex{}, size: size}
|
||||
func NewCache(size uint32, defaultTTL time.Duration) *Cache {
|
||||
ca := &Cache{table: make([]cacheNode, size), lock: &sync.Mutex{}, size: size, defaultTtl: defaultTTL}
|
||||
return ca
|
||||
}
|
||||
|
||||
const (
|
||||
HASH_ALG_MD5 int = iota
|
||||
HASH_ALG_MD5 int = iota
|
||||
HASH_ALG_SHA1
|
||||
HASH_ALG_SHA256
|
||||
)
|
||||
@@ -51,10 +54,14 @@ func checksum(alg int, key string) uint32 {
|
||||
|
||||
func (c *Cache) find(key string) (bool, uint32) {
|
||||
var idx uint32
|
||||
now := time.Now()
|
||||
for _, alg := range []int{HASH_ALG_MD5, HASH_ALG_SHA1, HASH_ALG_SHA256} {
|
||||
idx = checksum(alg, key) % c.size
|
||||
if c.table[idx].key == key {
|
||||
return true, idx
|
||||
if c.table[idx].expire.IsZero() || c.table[idx].expire.After(now) {
|
||||
return true, idx
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return false, idx
|
||||
@@ -74,13 +81,18 @@ func (c *Cache) AtomicGet(key string) interface{} {
|
||||
return c.Get(key)
|
||||
}
|
||||
|
||||
func (c *Cache) Set(key string, val interface{}) {
|
||||
func (c *Cache) Set(key string, val interface{}, expire ...time.Time) {
|
||||
find, idx := c.find(key)
|
||||
if find {
|
||||
c.table[idx].value = val
|
||||
} else {
|
||||
if !find {
|
||||
c.table[idx].key = key
|
||||
c.table[idx].value = val
|
||||
}
|
||||
c.table[idx].value = val
|
||||
if len(expire) > 0 && ! expire[0].IsZero() {
|
||||
c.table[idx].expire = expire[0]
|
||||
} else if c.defaultTtl > time.Millisecond {
|
||||
c.table[idx].expire = time.Now().Add(c.defaultTtl)
|
||||
} else {
|
||||
c.table[idx].expire = time.Time{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package hashcache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
c := NewCache(1024, time.Second)
|
||||
c.Set("123", 123)
|
||||
c.Set("456", 456)
|
||||
v := c.Get("123")
|
||||
if v == nil || v.(int) != 123 {
|
||||
t.Error("Key 123 not found")
|
||||
}
|
||||
v = c.Get("456")
|
||||
if v == nil || v.(int) != 456 {
|
||||
t.Error("Key 456 not found")
|
||||
}
|
||||
c.Set("456", 789)
|
||||
v = c.Get("456")
|
||||
if v == nil || v.(int) != 789 {
|
||||
t.Error("Key 456 not changed")
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
v = c.Get("123")
|
||||
if v != nil {
|
||||
t.Errorf("key 123 shoud expire")
|
||||
}
|
||||
c.Set("123", 1234)
|
||||
c.Set("456", 4567)
|
||||
v = c.Get("123")
|
||||
if v == nil || v.(int) != 1234 {
|
||||
t.Error("Key 123 not found")
|
||||
}
|
||||
v = c.Get("456")
|
||||
if v == nil || v.(int) != 4567 {
|
||||
t.Error("Key 456 not found")
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
v = c.Get("123")
|
||||
if v != nil {
|
||||
t.Errorf("key 123 shoud expire")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user