github.com/clly/consul@v1.4.5/agent/consul/state/delay.go (about)

     1  package state
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  // Delay is used to mark certain locks as unacquirable. When a lock is
     9  // forcefully released (failing health check, destroyed session, etc.), it is
    10  // subject to the LockDelay imposed by the session. This prevents another
    11  // session from acquiring the lock for some period of time as a protection
    12  // against split-brains. This is inspired by the lock-delay in Chubby. Because
    13  // this relies on wall-time, we cannot assume all peers perceive time as flowing
    14  // uniformly. This means KVSLock MUST ignore lockDelay, since the lockDelay may
    15  // have expired on the leader, but not on the follower. Rejecting the lock could
    16  // result in inconsistencies in the FSMs due to the rate time progresses. Instead,
    17  // only the opinion of the leader is respected, and the Raft log is never
    18  // questioned.
    19  type Delay struct {
    20  	// delay has the set of active delay expiration times, organized by key.
    21  	delay map[string]time.Time
    22  
    23  	// lock protects the delay map.
    24  	lock sync.RWMutex
    25  }
    26  
    27  // NewDelay returns a new delay manager.
    28  func NewDelay() *Delay {
    29  	return &Delay{delay: make(map[string]time.Time)}
    30  }
    31  
    32  // GetExpiration returns the expiration time of a key lock delay. This must be
    33  // checked on the leader node, and not in KVSLock due to the variability of
    34  // clocks.
    35  func (d *Delay) GetExpiration(key string) time.Time {
    36  	d.lock.RLock()
    37  	expires := d.delay[key]
    38  	d.lock.RUnlock()
    39  	return expires
    40  }
    41  
    42  // SetExpiration sets the expiration time for the lock delay to the given
    43  // delay from the given now time.
    44  func (d *Delay) SetExpiration(key string, now time.Time, delay time.Duration) {
    45  	d.lock.Lock()
    46  	defer d.lock.Unlock()
    47  
    48  	d.delay[key] = now.Add(delay)
    49  	time.AfterFunc(delay, func() {
    50  		d.lock.Lock()
    51  		delete(d.delay, key)
    52  		d.lock.Unlock()
    53  	})
    54  }