2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2021-11-16 18:04:01 +00:00
|
|
|
//go:build !consulent
|
2019-11-25 17:57:35 +00:00
|
|
|
// +build !consulent
|
|
|
|
|
2015-09-25 19:01:46 +00:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"time"
|
2022-04-05 21:10:06 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/acl"
|
2015-09-25 19:01:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Delay is used to mark certain locks as unacquirable. When a lock is
|
|
|
|
// forcefully released (failing health check, destroyed session, etc.), it is
|
2018-03-19 16:56:00 +00:00
|
|
|
// subject to the LockDelay imposed by the session. This prevents another
|
2015-09-25 19:01:46 +00:00
|
|
|
// session from acquiring the lock for some period of time as a protection
|
|
|
|
// against split-brains. This is inspired by the lock-delay in Chubby. Because
|
|
|
|
// this relies on wall-time, we cannot assume all peers perceive time as flowing
|
|
|
|
// uniformly. This means KVSLock MUST ignore lockDelay, since the lockDelay may
|
|
|
|
// have expired on the leader, but not on the follower. Rejecting the lock could
|
|
|
|
// result in inconsistencies in the FSMs due to the rate time progresses. Instead,
|
|
|
|
// only the opinion of the leader is respected, and the Raft log is never
|
|
|
|
// questioned.
|
|
|
|
type Delay struct {
|
|
|
|
// delay has the set of active delay expiration times, organized by key.
|
|
|
|
delay map[string]time.Time
|
|
|
|
|
|
|
|
// lock protects the delay map.
|
|
|
|
lock sync.RWMutex
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewDelay returns a new delay manager.
|
|
|
|
func NewDelay() *Delay {
|
|
|
|
return &Delay{delay: make(map[string]time.Time)}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetExpiration returns the expiration time of a key lock delay. This must be
|
|
|
|
// checked on the leader node, and not in KVSLock due to the variability of
|
|
|
|
// clocks.
|
2022-04-05 21:10:06 +00:00
|
|
|
func (d *Delay) GetExpiration(key string, entMeta *acl.EnterpriseMeta) time.Time {
|
2015-09-25 19:01:46 +00:00
|
|
|
d.lock.RLock()
|
|
|
|
expires := d.delay[key]
|
|
|
|
d.lock.RUnlock()
|
|
|
|
return expires
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetExpiration sets the expiration time for the lock delay to the given
|
|
|
|
// delay from the given now time.
|
2022-04-05 21:10:06 +00:00
|
|
|
func (d *Delay) SetExpiration(key string, now time.Time, delay time.Duration, entMeta *acl.EnterpriseMeta) {
|
2015-09-25 19:01:46 +00:00
|
|
|
d.lock.Lock()
|
|
|
|
defer d.lock.Unlock()
|
|
|
|
|
|
|
|
d.delay[key] = now.Add(delay)
|
|
|
|
time.AfterFunc(delay, func() {
|
|
|
|
d.lock.Lock()
|
|
|
|
delete(d.delay, key)
|
|
|
|
d.lock.Unlock()
|
|
|
|
})
|
|
|
|
}
|