acl: Adding additional tier of caching

This commit is contained in:
Armon Dadgar 2014-08-08 17:37:13 -07:00
parent db8f896c58
commit bee6e4e559
2 changed files with 39 additions and 17 deletions

View File

@ -19,10 +19,11 @@ type aclEntry struct {
// Cache is used to implement policy and ACL caching // Cache is used to implement policy and ACL caching
type Cache struct { type Cache struct {
aclCache *lru.Cache aclCache *lru.Cache // Cache id -> acl
faultfn FaultFunc faultfn FaultFunc
parent ACL parent ACL
policyCache *lru.Cache policyCache *lru.Cache // Cache policy -> acl
ruleCache *lru.Cache // Cache rules -> policy
} }
// NewCache contructs a new policy and ACL cache of a given size // NewCache contructs a new policy and ACL cache of a given size
@ -30,6 +31,7 @@ func NewCache(size int, parent ACL, faultfn FaultFunc) (*Cache, error) {
if size <= 0 { if size <= 0 {
return nil, fmt.Errorf("Must provide positive cache size") return nil, fmt.Errorf("Must provide positive cache size")
} }
rc, _ := lru.New(size)
pc, _ := lru.New(size) pc, _ := lru.New(size)
ac, _ := lru.New(size) ac, _ := lru.New(size)
c := &Cache{ c := &Cache{
@ -37,6 +39,7 @@ func NewCache(size int, parent ACL, faultfn FaultFunc) (*Cache, error) {
faultfn: faultfn, faultfn: faultfn,
parent: parent, parent: parent,
policyCache: pc, policyCache: pc,
ruleCache: rc,
} }
return c, nil return c, nil
} }
@ -50,7 +53,7 @@ func (c *Cache) GetPolicy(rules string) (*Policy, error) {
// getPolicy is an internal method to get a cached policy, // getPolicy is an internal method to get a cached policy,
// but it assumes a pre-computed ID // but it assumes a pre-computed ID
func (c *Cache) getPolicy(id, rules string) (*Policy, error) { func (c *Cache) getPolicy(id, rules string) (*Policy, error) {
raw, ok := c.policyCache.Get(id) raw, ok := c.ruleCache.Get(id)
if ok { if ok {
return raw.(*Policy), nil return raw.(*Policy), nil
} }
@ -59,7 +62,7 @@ func (c *Cache) getPolicy(id, rules string) (*Policy, error) {
return nil, err return nil, err
} }
policy.ID = id policy.ID = id
c.policyCache.Add(id, policy) c.ruleCache.Add(id, policy)
return policy, nil return policy, nil
} }
@ -75,7 +78,7 @@ func (c *Cache) GetACLPolicy(id string) (*Policy, error) {
// Check for a cached acl // Check for a cached acl
if raw, ok := c.aclCache.Get(id); ok { if raw, ok := c.aclCache.Get(id); ok {
cached := raw.(aclEntry) cached := raw.(aclEntry)
if raw, ok := c.policyCache.Get(cached.PolicyID); ok { if raw, ok := c.ruleCache.Get(cached.PolicyID); ok {
return raw.(*Policy), nil return raw.(*Policy), nil
} }
} }
@ -106,21 +109,31 @@ func (c *Cache) GetACL(id string) (ACL, error) {
} }
ruleID := c.ruleID(rules) ruleID := c.ruleID(rules)
// Get the policy // Check for a compiled ACL
policy, err := c.getPolicy(ruleID, rules) var compiled ACL
if err != nil { if raw, ok := c.policyCache.Get(ruleID); ok {
return nil, err compiled = raw.(ACL)
} } else {
// Get the policy
policy, err := c.getPolicy(ruleID, rules)
if err != nil {
return nil, err
}
// Get the ACL // Compile the ACL
acl, err := New(c.parent, policy) acl, err := New(c.parent, policy)
if err != nil { if err != nil {
return nil, err return nil, err
}
// Cache the compiled ACL
c.policyCache.Add(ruleID, acl)
compiled = acl
} }
// Cache and return the ACL // Cache and return the ACL
c.aclCache.Add(id, aclEntry{acl, ruleID}) c.aclCache.Add(id, aclEntry{compiled, ruleID})
return acl, nil return compiled, nil
} }
// ClearACL is used to clear the ACL cache if any // ClearACL is used to clear the ACL cache if any

View File

@ -43,7 +43,7 @@ func TestCache_GetPolicy(t *testing.T) {
func TestCache_GetACL(t *testing.T) { func TestCache_GetACL(t *testing.T) {
policies := map[string]string{ policies := map[string]string{
"foo": testSimplePolicy, "foo": testSimplePolicy,
"bar": testSimplePolicy, "bar": testSimplePolicy2,
} }
faultfn := func(id string) (string, error) { faultfn := func(id string) (string, error) {
return policies[id], nil return policies[id], nil
@ -113,6 +113,9 @@ func TestCache_ClearACL(t *testing.T) {
// Nuke the cache // Nuke the cache
c.ClearACL("foo") c.ClearACL("foo")
// Clear the policy cache
c.policyCache.Remove(c.ruleID(testSimplePolicy))
acl2, err := c.GetACL("foo") acl2, err := c.GetACL("foo")
if err != nil { if err != nil {
t.Fatalf("err: %v", err) t.Fatalf("err: %v", err)
@ -170,3 +173,9 @@ key "foo/" {
policy = "read" policy = "read"
} }
` `
var testSimplePolicy2 = `
key "bar/" {
policy = "read"
}
`