VAULT-7707 OSS portion of changes (#18019)

* VAULT-7707 OSS portion of changes

* Revert "VAULT-7707 OSS portion of changes"

This reverts commit 5b8cf3882fb7e2427593d59e1439d46b3a5c20a7.

* VAULT-7707 smarter locking behaviour

* VAULT-7707 typo

* VAULT-7707 typo
This commit is contained in:
Violet Hynes 2022-11-17 16:30:39 -05:00 committed by GitHub
parent 5c4e148ce2
commit bfeae1fe8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 62 additions and 38 deletions

View File

@ -165,7 +165,15 @@ type Manager struct {
logger log.Logger
metricSink *metricsutil.ClusterMetricSink
lock *sync.RWMutex
// quotaLock is a lock for manipulating quotas and anything not covered by a more specific lock
quotaLock *sync.RWMutex
// quotaConfigLock is a lock for accessing config items, such as RateLimitExemptPaths
quotaConfigLock *sync.RWMutex
// dbAndCacheLock is a lock for db and path caches that need to be reset during Reset()
dbAndCacheLock *sync.RWMutex
}
// QuotaLeaseInformation contains all of the information lease-count quotas require
@ -273,7 +281,9 @@ func NewManager(logger log.Logger, walkFunc leaseWalkFunc, ms *metricsutil.Clust
metricSink: ms,
rateLimitPathManager: pathmanager.New(),
config: new(Config),
lock: new(sync.RWMutex),
quotaLock: new(sync.RWMutex),
quotaConfigLock: new(sync.RWMutex),
dbAndCacheLock: new(sync.RWMutex),
}
manager.init(walkFunc)
@ -283,8 +293,10 @@ func NewManager(logger log.Logger, walkFunc leaseWalkFunc, ms *metricsutil.Clust
// SetQuota adds or updates a quota rule.
func (m *Manager) SetQuota(ctx context.Context, qType string, quota Quota, loading bool) error {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaLock.Lock()
m.dbAndCacheLock.RLock()
defer m.quotaLock.Unlock()
defer m.dbAndCacheLock.RUnlock()
return m.setQuotaLocked(ctx, qType, quota, loading)
}
@ -355,8 +367,8 @@ func (m *Manager) setQuotaLockedWithTxn(ctx context.Context, qType string, quota
// QuotaNames returns the names of all the quota rules for a given type
func (m *Manager) QuotaNames(qType Type) ([]string, error) {
m.lock.RLock()
defer m.lock.RUnlock()
m.dbAndCacheLock.RLock()
defer m.dbAndCacheLock.RUnlock()
return m.quotaNamesLocked(qType)
}
@ -377,8 +389,8 @@ func (m *Manager) quotaNamesLocked(qType Type) ([]string, error) {
// QuotaByID queries for a quota rule in the db for a given quota ID
func (m *Manager) QuotaByID(qType string, id string) (Quota, error) {
m.lock.RLock()
defer m.lock.RUnlock()
m.dbAndCacheLock.RLock()
defer m.dbAndCacheLock.RUnlock()
txn := m.db.Txn(false)
@ -395,8 +407,8 @@ func (m *Manager) QuotaByID(qType string, id string) (Quota, error) {
// QuotaByName queries for a quota rule in the db for a given quota name
func (m *Manager) QuotaByName(qType string, name string) (Quota, error) {
m.lock.RLock()
defer m.lock.RUnlock()
m.dbAndCacheLock.RLock()
defer m.dbAndCacheLock.RUnlock()
return m.quotaByNameLocked(qType, name)
}
@ -418,8 +430,8 @@ func (m *Manager) quotaByNameLocked(qType string, name string) (Quota, error) {
// QuotaByFactors returns the quota rule that matches the provided factors
func (m *Manager) QuotaByFactors(ctx context.Context, qType, nsPath, mountPath, pathSuffix, role string) (Quota, error) {
m.lock.RLock()
defer m.lock.RUnlock()
m.dbAndCacheLock.RLock()
defer m.dbAndCacheLock.RUnlock()
// nsPath would have been made non-empty during insertion. Use non-empty value
// during query as well.
@ -464,8 +476,8 @@ func (m *Manager) QuotaByFactors(ctx context.Context, qType, nsPath, mountPath,
// QueryQuota returns the most specific applicable quota for a given request.
func (m *Manager) QueryQuota(req *Request) (Quota, error) {
m.lock.RLock()
defer m.lock.RUnlock()
m.dbAndCacheLock.RLock()
defer m.dbAndCacheLock.RUnlock()
return m.queryQuota(nil, req)
}
@ -587,8 +599,10 @@ func (m *Manager) queryQuota(txn *memdb.Txn, req *Request) (Quota, error) {
// DeleteQuota removes a quota rule from the db for a given name
func (m *Manager) DeleteQuota(ctx context.Context, qType string, name string) error {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaLock.Lock()
m.dbAndCacheLock.RLock()
defer m.quotaLock.Unlock()
defer m.dbAndCacheLock.RUnlock()
txn := m.db.Txn(true)
defer txn.Abort()
@ -652,8 +666,8 @@ func (m *Manager) ApplyQuota(ctx context.Context, req *Request) (Response, error
// SetEnableRateLimitAuditLogging updates the operator preference regarding the
// audit logging behavior.
func (m *Manager) SetEnableRateLimitAuditLogging(val bool) {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaLock.Lock()
defer m.quotaLock.Unlock()
m.setEnableRateLimitAuditLoggingLocked(val)
}
@ -664,8 +678,8 @@ func (m *Manager) setEnableRateLimitAuditLoggingLocked(val bool) {
// SetEnableRateLimitResponseHeaders updates the operator preference regarding
// the rate limit quota HTTP header behavior.
func (m *Manager) SetEnableRateLimitResponseHeaders(val bool) {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaConfigLock.Lock()
defer m.quotaConfigLock.Unlock()
m.setEnableRateLimitResponseHeadersLocked(val)
}
@ -678,8 +692,8 @@ func (m *Manager) setEnableRateLimitResponseHeadersLocked(val bool) {
// SetRateLimitExemptPaths will wipe out the existing path manager and set the
// paths based on the provided argument.
func (m *Manager) SetRateLimitExemptPaths(vals []string) {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaConfigLock.Lock()
defer m.quotaConfigLock.Unlock()
m.setRateLimitExemptPathsLocked(vals)
}
@ -695,8 +709,8 @@ func (m *Manager) setRateLimitExemptPathsLocked(vals []string) {
// RateLimitAuditLoggingEnabled returns if the quota configuration allows audit
// logging of request rejections due to rate limiting quota rule violations.
func (m *Manager) RateLimitAuditLoggingEnabled() bool {
m.lock.RLock()
defer m.lock.RUnlock()
m.quotaConfigLock.RLock()
defer m.quotaConfigLock.RUnlock()
return m.config.EnableRateLimitAuditLogging
}
@ -704,8 +718,8 @@ func (m *Manager) RateLimitAuditLoggingEnabled() bool {
// RateLimitResponseHeadersEnabled returns if the quota configuration allows for
// rate limit quota HTTP headers to be added to responses.
func (m *Manager) RateLimitResponseHeadersEnabled() bool {
m.lock.RLock()
defer m.lock.RUnlock()
m.quotaConfigLock.RLock()
defer m.quotaConfigLock.RUnlock()
return m.config.EnableRateLimitResponseHeaders
}
@ -713,8 +727,8 @@ func (m *Manager) RateLimitResponseHeadersEnabled() bool {
// RateLimitExemptPaths returns the list of exempt paths from all rate limit
// resource quotas from the Manager's configuration.
func (m *Manager) RateLimitExemptPaths() []string {
m.lock.RLock()
defer m.lock.RUnlock()
m.quotaConfigLock.RLock()
defer m.quotaConfigLock.RUnlock()
return m.config.RateLimitExemptPaths
}
@ -723,8 +737,8 @@ func (m *Manager) RateLimitExemptPaths() []string {
// any rate limit quota. If not rate limit path manager is defined, false is
// returned.
func (m *Manager) RateLimitPathExempt(path string) bool {
m.lock.RLock()
defer m.lock.RUnlock()
m.quotaConfigLock.RLock()
defer m.quotaConfigLock.RUnlock()
if m.rateLimitPathManager == nil {
return false
@ -740,8 +754,10 @@ func (m *Manager) Config() *Config {
// Reset will clear all the quotas from the db and clear the lease path cache.
func (m *Manager) Reset() error {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaLock.Lock()
defer m.quotaLock.Unlock()
m.dbAndCacheLock.Lock()
defer m.dbAndCacheLock.Unlock()
err := m.resetCache()
if err != nil {
@ -1015,8 +1031,12 @@ func Load(ctx context.Context, storage logical.Storage, qType, name string) (Quo
// Setup loads the quota configuration and all the quota rules into the
// quota manager.
func (m *Manager) Setup(ctx context.Context, storage logical.Storage, isPerfStandby, isDRSecondary bool) error {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaLock.Lock()
m.quotaConfigLock.Lock()
m.dbAndCacheLock.Lock()
defer m.quotaLock.Unlock()
defer m.quotaConfigLock.Unlock()
defer m.dbAndCacheLock.Unlock()
m.storage = storage
m.ctx = ctx
@ -1104,8 +1124,10 @@ func QuotaStoragePath(quotaType, name string) string {
// took place. Quota manager will trigger the quota specific updates including
// the mount path update and the namespace update
func (m *Manager) HandleRemount(ctx context.Context, from, to namespace.MountPathDetails) error {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaLock.Lock()
m.dbAndCacheLock.RLock()
defer m.quotaLock.Unlock()
defer m.dbAndCacheLock.RUnlock()
// Grab a write transaction, as we want to save the updated quota in memdb
txn := m.db.Txn(true)
@ -1189,8 +1211,10 @@ func (m *Manager) HandleRemount(ctx context.Context, from, to namespace.MountPat
// or secret engine disabling. This should only be called on the primary cluster
// node.
func (m *Manager) HandleBackendDisabling(ctx context.Context, nsPath, mountPath string) error {
m.lock.Lock()
defer m.lock.Unlock()
m.quotaLock.Lock()
m.dbAndCacheLock.RLock()
defer m.quotaLock.Unlock()
defer m.dbAndCacheLock.RUnlock()
txn := m.db.Txn(true)
defer txn.Abort()