Browse Source

*: refresh the lease TTL correctly when a leader is elected.

The new leader needs to refresh with an extened TTL to gracefully handle
the potential concurrent leader issue. Clients might still send keep alive
to old leader until the old leader itself gives up leadership at most after
an election timeout.
Xiang Li 9 years ago
parent
commit
e9a0a103e5
4 changed files with 16 additions and 11 deletions
  1. 4 0
      etcdserver/config.go
  2. 1 1
      etcdserver/raft.go
  3. 9 8
      lease/lessor.go
  4. 2 2
      lease/lessor_test.go

+ 4 - 0
etcdserver/config.go

@@ -134,6 +134,10 @@ func (c *ServerConfig) ReqTimeout() time.Duration {
 	return 5*time.Second + 2*time.Duration(c.ElectionTicks)*time.Duration(c.TickMs)*time.Millisecond
 	return 5*time.Second + 2*time.Duration(c.ElectionTicks)*time.Duration(c.TickMs)*time.Millisecond
 }
 }
 
 
+func (c *ServerConfig) electionTimeout() time.Duration {
+	return time.Duration(c.ElectionTicks) * time.Duration(c.TickMs) * time.Millisecond
+}
+
 func (c *ServerConfig) peerDialTimeout() time.Duration {
 func (c *ServerConfig) peerDialTimeout() time.Duration {
 	// 1s for queue wait and system delay
 	// 1s for queue wait and system delay
 	// + one RTT, which is smaller than 1/5 election timeout
 	// + one RTT, which is smaller than 1/5 election timeout

+ 1 - 1
etcdserver/raft.go

@@ -165,7 +165,7 @@ func (r *raftNode) start(s *EtcdServer) {
 						// it promotes or demotes instead of modifying server directly.
 						// it promotes or demotes instead of modifying server directly.
 						syncC = r.s.SyncTicker
 						syncC = r.s.SyncTicker
 						if r.s.lessor != nil {
 						if r.s.lessor != nil {
-							r.s.lessor.Promote()
+							r.s.lessor.Promote(r.s.cfg.electionTimeout())
 						}
 						}
 						// TODO: remove the nil checking
 						// TODO: remove the nil checking
 						// current test utility does not provide the stats
 						// current test utility does not provide the stats

+ 9 - 8
lease/lessor.go

@@ -78,7 +78,8 @@ type Lessor interface {
 
 
 	// Promote promotes the lessor to be the primary lessor. Primary lessor manages
 	// Promote promotes the lessor to be the primary lessor. Primary lessor manages
 	// the expiration and renew of leases.
 	// the expiration and renew of leases.
-	Promote()
+	// Newly promoted lessor renew the TTL of all lease to extend + previous TTL.
+	Promote(extend time.Duration)
 
 
 	// Demote demotes the lessor from being the primary lessor.
 	// Demote demotes the lessor from being the primary lessor.
 	Demote()
 	Demote()
@@ -188,7 +189,7 @@ func (le *lessor) Grant(id LeaseID, ttl int64) (*Lease, error) {
 	}
 	}
 
 
 	if le.primary {
 	if le.primary {
-		l.refresh()
+		l.refresh(0)
 	} else {
 	} else {
 		l.forever()
 		l.forever()
 	}
 	}
@@ -240,7 +241,7 @@ func (le *lessor) Renew(id LeaseID) (int64, error) {
 		return -1, ErrLeaseNotFound
 		return -1, ErrLeaseNotFound
 	}
 	}
 
 
-	l.refresh()
+	l.refresh(0)
 	return l.TTL, nil
 	return l.TTL, nil
 }
 }
 
 
@@ -253,7 +254,7 @@ func (le *lessor) Lookup(id LeaseID) *Lease {
 	return nil
 	return nil
 }
 }
 
 
-func (le *lessor) Promote() {
+func (le *lessor) Promote(extend time.Duration) {
 	le.mu.Lock()
 	le.mu.Lock()
 	defer le.mu.Unlock()
 	defer le.mu.Unlock()
 
 
@@ -261,7 +262,7 @@ func (le *lessor) Promote() {
 
 
 	// refresh the expiries of all leases.
 	// refresh the expiries of all leases.
 	for _, l := range le.leaseMap {
 	for _, l := range le.leaseMap {
-		l.refresh()
+		l.refresh(extend)
 	}
 	}
 }
 }
 
 
@@ -452,11 +453,11 @@ func (l Lease) removeFrom(b backend.Backend) {
 
 
 // refresh refreshes the expiry of the lease. It extends the expiry at least
 // refresh refreshes the expiry of the lease. It extends the expiry at least
 // minLeaseTTL second.
 // minLeaseTTL second.
-func (l *Lease) refresh() {
+func (l *Lease) refresh(extend time.Duration) {
 	if l.TTL < minLeaseTTL {
 	if l.TTL < minLeaseTTL {
 		l.TTL = minLeaseTTL
 		l.TTL = minLeaseTTL
 	}
 	}
-	l.expiry = time.Now().Add(time.Second * time.Duration(l.TTL))
+	l.expiry = time.Now().Add(extend + time.Second*time.Duration(l.TTL))
 }
 }
 
 
 // forever sets the expiry of lease to be forever.
 // forever sets the expiry of lease to be forever.
@@ -491,7 +492,7 @@ func (fl *FakeLessor) Attach(id LeaseID, items []LeaseItem) error { return nil }
 
 
 func (fl *FakeLessor) Detach(id LeaseID, items []LeaseItem) error { return nil }
 func (fl *FakeLessor) Detach(id LeaseID, items []LeaseItem) error { return nil }
 
 
-func (fl *FakeLessor) Promote() {}
+func (fl *FakeLessor) Promote(extend time.Duration) {}
 
 
 func (fl *FakeLessor) Demote() {}
 func (fl *FakeLessor) Demote() {}
 
 

+ 2 - 2
lease/lessor_test.go

@@ -34,7 +34,7 @@ func TestLessorGrant(t *testing.T) {
 	defer be.Close()
 	defer be.Close()
 
 
 	le := newLessor(be)
 	le := newLessor(be)
-	le.Promote()
+	le.Promote(0)
 
 
 	l, err := le.Grant(1, 1)
 	l, err := le.Grant(1, 1)
 	if err != nil {
 	if err != nil {
@@ -128,7 +128,7 @@ func TestLessorRenew(t *testing.T) {
 	defer os.RemoveAll(dir)
 	defer os.RemoveAll(dir)
 
 
 	le := newLessor(be)
 	le := newLessor(be)
-	le.Promote()
+	le.Promote(0)
 
 
 	l, err := le.Grant(1, 5)
 	l, err := le.Grant(1, 5)
 	if err != nil {
 	if err != nil {