From 2b8d8a3c6ad503381000ca70232d04753809e883 Mon Sep 17 00:00:00 2001 From: Violet Hynes Date: Thu, 22 Sep 2022 15:59:53 -0400 Subject: [PATCH] VAULT-8630 Fix goroutine leak from RLQ initialize (#17281) * VAULT-8630 Fix goroutine leak from RLQ initialize * VAULT-8630 Changelog * VAULT-8630 additional nil check --- changelog/17281.txt | 3 +++ vault/quotas/quotas.go | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 changelog/17281.txt diff --git a/changelog/17281.txt b/changelog/17281.txt new file mode 100644 index 000000000..8711283ad --- /dev/null +++ b/changelog/17281.txt @@ -0,0 +1,3 @@ +```release-note:bug +core/quotas: Fix goroutine leak caused by the seal process not fully cleaning up Rate Limit Quotas. +``` diff --git a/vault/quotas/quotas.go b/vault/quotas/quotas.go index 038fe54d6..2128d78ad 100644 --- a/vault/quotas/quotas.go +++ b/vault/quotas/quotas.go @@ -358,6 +358,11 @@ func (m *Manager) QuotaNames(qType Type) ([]string, error) { m.lock.RLock() defer m.lock.RUnlock() + return m.quotaNamesLocked(qType) +} + +// quotaNamesLocked returns the names of all the quota rules for a given type, and must be called with the lock +func (m *Manager) quotaNamesLocked(qType Type) ([]string, error) { txn := m.db.Txn(false) iter, err := txn.Get(qType.String(), indexID) if err != nil { @@ -393,6 +398,11 @@ func (m *Manager) QuotaByName(qType string, name string) (Quota, error) { m.lock.RLock() defer m.lock.RUnlock() + return m.quotaByNameLocked(qType, name) +} + +// quotaByNameLocked queries for a quota rule in the db for a given quota name, and must be called with the lock +func (m *Manager) quotaByNameLocked(qType string, name string) (Quota, error) { txn := m.db.Txn(false) quotaRaw, err := txn.First(qType, indexName, name) @@ -745,6 +755,23 @@ func (m *Manager) Reset() error { // Must be called with the lock held func (m *Manager) resetCache() error { + names, err := m.quotaNamesLocked(TypeRateLimit) + if err != nil { + return err + } + for _, name := range names { + quota, err := m.quotaByNameLocked(TypeRateLimit.String(), name) + if err != nil { + return err + } + if quota != nil { + rlq := quota.(*RateLimitQuota) + err = rlq.store.Close(context.Background()) + if err != nil { + return err + } + } + } db, err := memdb.NewMemDB(dbSchema()) if err != nil { return err