-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This change-set does the following: - it introduces an MSP wrapper that intercepts the validation functions and cache their results. LRU caches are used. - adds tests to validate the implementation This change-set is a joint work with Senthil Nathan. Change-Id: I2027d6ab4331b4923bb00e961ef15a38ce4c8e8b Signed-off-by: Angelo De Caro <[email protected]>
- Loading branch information
Showing
10 changed files
with
850 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package cache | ||
|
||
import ( | ||
"fmt" | ||
|
||
"sync" | ||
|
||
"github.com/golang/groupcache/lru" | ||
"github.com/hyperledger/fabric/common/flogging" | ||
"github.com/hyperledger/fabric/msp" | ||
pmsp "github.com/hyperledger/fabric/protos/msp" | ||
) | ||
|
||
const ( | ||
deserializeIdentityCacheSize = 100 | ||
validateIdentityCacheSize = 100 | ||
satisfiesPrincipalCacheSize = 100 | ||
) | ||
|
||
var mspLogger = flogging.MustGetLogger("msp") | ||
|
||
func New(o msp.MSP) (msp.MSP, error) { | ||
mspLogger.Debugf("Creating Cache-MSP instance") | ||
if o == nil { | ||
return nil, fmt.Errorf("Invalid passed MSP. It must be different from nil.") | ||
} | ||
|
||
theMsp := &cachedMSP{MSP: o} | ||
theMsp.deserializeIdentityCache = lru.New(deserializeIdentityCacheSize) | ||
theMsp.satisfiesPrincipalCache = lru.New(satisfiesPrincipalCacheSize) | ||
theMsp.validateIdentityCache = lru.New(validateIdentityCacheSize) | ||
|
||
return theMsp, nil | ||
} | ||
|
||
type cachedMSP struct { | ||
msp.MSP | ||
|
||
// cache for DeserializeIdentity. | ||
deserializeIdentityCache *lru.Cache | ||
|
||
dicMutex sync.RWMutex // synchronize access to cache | ||
|
||
// cache for validateIdentity | ||
validateIdentityCache *lru.Cache | ||
|
||
vicMutex sync.RWMutex // synchronize access to cache | ||
|
||
// basically a map of principals=>identities=>stringified to booleans | ||
// specifying whether this identity satisfies this principal | ||
satisfiesPrincipalCache *lru.Cache | ||
|
||
spcMutex sync.RWMutex // synchronize access to cache | ||
} | ||
|
||
func (c *cachedMSP) DeserializeIdentity(serializedIdentity []byte) (msp.Identity, error) { | ||
c.dicMutex.RLock() | ||
cached, ok := c.deserializeIdentityCache.Get(string(serializedIdentity)) | ||
c.dicMutex.RUnlock() | ||
if ok { | ||
return cached.(msp.Identity), nil | ||
} | ||
|
||
id, err := c.MSP.DeserializeIdentity(serializedIdentity) | ||
if err == nil { | ||
c.dicMutex.Lock() | ||
defer c.dicMutex.Unlock() | ||
c.deserializeIdentityCache.Add(string(serializedIdentity), id) | ||
} | ||
return id, err | ||
} | ||
|
||
func (c *cachedMSP) Setup(config *pmsp.MSPConfig) error { | ||
c.cleanCash() | ||
|
||
return c.MSP.Setup(config) | ||
} | ||
|
||
func (c *cachedMSP) Validate(id msp.Identity) error { | ||
identifier := id.GetIdentifier() | ||
key := string(identifier.Mspid + ":" + identifier.Id) | ||
|
||
c.vicMutex.RLock() | ||
_, ok := c.validateIdentityCache.Get(key) | ||
c.vicMutex.RUnlock() | ||
if ok { | ||
// cache only stores if the identity is valid. | ||
return nil | ||
} | ||
|
||
err := c.MSP.Validate(id) | ||
if err == nil { | ||
c.vicMutex.Lock() | ||
defer c.vicMutex.Unlock() | ||
c.validateIdentityCache.Add(key, true) | ||
} | ||
|
||
return err | ||
} | ||
|
||
func (c *cachedMSP) SatisfiesPrincipal(id msp.Identity, principal *pmsp.MSPPrincipal) error { | ||
identifier := id.GetIdentifier() | ||
identityKey := string(identifier.Mspid + ":" + identifier.Id) | ||
principalKey := string(principal.PrincipalClassification) + string(principal.Principal) | ||
key := identityKey + principalKey | ||
|
||
c.spcMutex.RLock() | ||
v, ok := c.satisfiesPrincipalCache.Get(key) | ||
c.spcMutex.RUnlock() | ||
if ok { | ||
if v == nil { | ||
return nil | ||
} | ||
|
||
return v.(error) | ||
} | ||
|
||
err := c.MSP.SatisfiesPrincipal(id, principal) | ||
|
||
c.spcMutex.Lock() | ||
defer c.spcMutex.Unlock() | ||
c.satisfiesPrincipalCache.Add(key, err) | ||
return err | ||
} | ||
|
||
func (c *cachedMSP) cleanCash() error { | ||
c.deserializeIdentityCache = lru.New(deserializeIdentityCacheSize) | ||
c.satisfiesPrincipalCache = lru.New(satisfiesPrincipalCacheSize) | ||
c.validateIdentityCache = lru.New(validateIdentityCacheSize) | ||
|
||
return nil | ||
} |
Oops, something went wrong.