Store lease times suitable for export in pending (#4730)

* Store lease times suitable for export in pending

This essentially caches lease information for token lookups, preventing
going to disk over and over.

* Simplify logic
This commit is contained in:
Jeff Mitchell 2018-06-11 11:58:56 -04:00 committed by GitHub
parent b6b5f6437f
commit 45da5a45ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -52,6 +52,11 @@ const (
maxLeaseThreshold = 256000 maxLeaseThreshold = 256000
) )
type pendingInfo struct {
exportLeaseTimes *leaseEntry
timer *time.Timer
}
// ExpirationManager is used by the Core to manage leases. Secrets // ExpirationManager is used by the Core to manage leases. Secrets
// can provide a lease, meaning that they can be renewed or revoked. // can provide a lease, meaning that they can be renewed or revoked.
// If a secret is not renewed in timely manner, it may be expired, and // If a secret is not renewed in timely manner, it may be expired, and
@ -63,7 +68,7 @@ type ExpirationManager struct {
tokenStore *TokenStore tokenStore *TokenStore
logger log.Logger logger log.Logger
pending map[string]*time.Timer pending map[string]pendingInfo
pendingLock sync.RWMutex pendingLock sync.RWMutex
tidyLock *int32 tidyLock *int32
@ -91,7 +96,7 @@ func NewExpirationManager(c *Core, view *BarrierView, logger log.Logger) *Expira
tokenView: view.SubView(tokenViewPrefix), tokenView: view.SubView(tokenViewPrefix),
tokenStore: c.tokenStore, tokenStore: c.tokenStore,
logger: logger, logger: logger,
pending: make(map[string]*time.Timer), pending: make(map[string]pendingInfo),
tidyLock: new(int32), tidyLock: new(int32),
// new instances of the expiration manager will go immediately into // new instances of the expiration manager will go immediately into
@ -457,10 +462,10 @@ func (m *ExpirationManager) Stop() error {
close(m.quitCh) close(m.quitCh)
m.pendingLock.Lock() m.pendingLock.Lock()
for _, timer := range m.pending { for _, pending := range m.pending {
timer.Stop() pending.timer.Stop()
} }
m.pending = make(map[string]*time.Timer) m.pending = make(map[string]pendingInfo)
m.pendingLock.Unlock() m.pendingLock.Unlock()
if m.inRestoreMode() { if m.inRestoreMode() {
@ -525,8 +530,8 @@ func (m *ExpirationManager) revokeCommon(leaseID string, force, skipToken bool)
// Clear the expiration handler // Clear the expiration handler
m.pendingLock.Lock() m.pendingLock.Lock()
if timer, ok := m.pending[leaseID]; ok { if pending, ok := m.pending[leaseID]; ok {
timer.Stop() pending.timer.Stop()
delete(m.pending, leaseID) delete(m.pending, leaseID)
} }
m.pendingLock.Unlock() m.pendingLock.Unlock()
@ -950,6 +955,14 @@ func (m *ExpirationManager) FetchLeaseTimesByToken(source, token string) (*lease
func (m *ExpirationManager) FetchLeaseTimes(leaseID string) (*leaseEntry, error) { func (m *ExpirationManager) FetchLeaseTimes(leaseID string) (*leaseEntry, error) {
defer metrics.MeasureSince([]string{"expire", "fetch-lease-times"}, time.Now()) defer metrics.MeasureSince([]string{"expire", "fetch-lease-times"}, time.Now())
m.pendingLock.RLock()
val := m.pending[leaseID]
m.pendingLock.RUnlock()
if val.exportLeaseTimes != nil {
return val.exportLeaseTimes, nil
}
// Load the entry // Load the entry
le, err := m.loadEntry(leaseID) le, err := m.loadEntry(leaseID)
if err != nil { if err != nil {
@ -959,6 +972,11 @@ func (m *ExpirationManager) FetchLeaseTimes(leaseID string) (*leaseEntry, error)
return nil, nil return nil, nil
} }
return m.leaseTimesForExport(le), nil
}
// Returns lease times for outside callers based on the full leaseEntry passed in
func (m *ExpirationManager) leaseTimesForExport(le *leaseEntry) *leaseEntry {
ret := &leaseEntry{ ret := &leaseEntry{
IssueTime: le.IssueTime, IssueTime: le.IssueTime,
ExpireTime: le.ExpireTime, ExpireTime: le.ExpireTime,
@ -975,42 +993,50 @@ func (m *ExpirationManager) FetchLeaseTimes(leaseID string) (*leaseEntry, error)
ret.Auth.TTL = le.Auth.TTL ret.Auth.TTL = le.Auth.TTL
} }
return ret, nil return ret
} }
// updatePending is used to update a pending invocation for a lease // updatePending is used to update a pending invocation for a lease
func (m *ExpirationManager) updatePending(le *leaseEntry, leaseTotal time.Duration) { func (m *ExpirationManager) updatePending(le *leaseEntry, leaseTotal time.Duration) {
m.pendingLock.Lock() m.pendingLock.Lock()
defer m.pendingLock.Unlock() defer m.pendingLock.Unlock()
m.updatePendingInternal(le, leaseTotal) m.updatePendingInternal(le, leaseTotal)
} }
// updatePendingInternal is the locked version of updatePending; do not call
// this without a write lock on m.pending
func (m *ExpirationManager) updatePendingInternal(le *leaseEntry, leaseTotal time.Duration) { func (m *ExpirationManager) updatePendingInternal(le *leaseEntry, leaseTotal time.Duration) {
// Check for an existing timer // Check for an existing timer
timer, ok := m.pending[le.LeaseID] pending, ok := m.pending[le.LeaseID]
// If there is no expiry time, don't do anything // If there is no expiry time, don't do anything
if le.ExpireTime.IsZero() { if le.ExpireTime.IsZero() {
// if the timer happened to exist, stop the time and delete it from the // if the timer happened to exist, stop the time and delete it from the
// pending timers. // pending timers.
if ok { if ok {
timer.Stop() pending.timer.Stop()
delete(m.pending, le.LeaseID) delete(m.pending, le.LeaseID)
} }
return return
} }
// Create entry if it does not exist // Create entry if it does not exist or reset if it does
if !ok { if ok {
pending.timer.Reset(leaseTotal)
} else {
timer := time.AfterFunc(leaseTotal, func() { timer := time.AfterFunc(leaseTotal, func() {
m.expireID(le.LeaseID) m.expireID(le.LeaseID)
}) })
m.pending[le.LeaseID] = timer pending = pendingInfo{
return timer: timer,
}
} }
// Extend the timer by the lease total // Extend the timer by the lease total
timer.Reset(leaseTotal) pending.exportLeaseTimes = m.leaseTimesForExport(le)
m.pending[le.LeaseID] = pending
} }
// expireID is invoked when a given ID is expired // expireID is invoked when a given ID is expired