lease: delete items when the lease is revoked.

Add minimum KV interface and implmement the deleting mechanism for
revoking lease.
This commit is contained in:
Xiang Li 2015-11-09 13:33:12 -08:00
parent bf70b5127a
commit bf3bc0ed6b
2 changed files with 52 additions and 7 deletions

View File

@ -26,6 +26,15 @@ var (
minLeaseTerm = 5 * time.Second minLeaseTerm = 5 * time.Second
) )
// DeleteableRange defines an interface with DeleteRange method.
// We define this interface only for lessor to limit the number
// of methods of storage.KV to what lessor actually needs.
//
// Having a minimum interface makes testing easy.
type DeleteableRange interface {
DeleteRange(key, end []byte) (int64, int64)
}
// a lessor is the owner of leases. It can grant, revoke, // a lessor is the owner of leases. It can grant, revoke,
// renew and modify leases for lessee. // renew and modify leases for lessee.
// TODO: persist lease on to stable backend for failure recovery. // TODO: persist lease on to stable backend for failure recovery.
@ -40,12 +49,18 @@ type lessor struct {
// FindExpired and Renew should be the most frequent operations. // FindExpired and Renew should be the most frequent operations.
leaseMap map[uint64]*lease leaseMap map[uint64]*lease
// A DeleteableRange the lessor operates on.
// When a lease expires, the lessor will delete the
// leased range (or key) from the DeleteableRange.
dr DeleteableRange
idgen *idutil.Generator idgen *idutil.Generator
} }
func NewLessor(lessorID uint8) *lessor { func NewLessor(lessorID uint8, dr DeleteableRange) *lessor {
return &lessor{ return &lessor{
leaseMap: make(map[uint64]*lease), leaseMap: make(map[uint64]*lease),
dr: dr,
idgen: idutil.NewGenerator(lessorID, time.Now()), idgen: idutil.NewGenerator(lessorID, time.Now()),
} }
} }
@ -62,7 +77,7 @@ func (le *lessor) Grant(expiry time.Time) *lease {
le.mu.Lock() le.mu.Lock()
defer le.mu.Unlock() defer le.mu.Unlock()
l := &lease{id: id, expiry: expiry} l := &lease{id: id, expiry: expiry, itemSet: make(map[leaseItem]struct{})}
if _, ok := le.leaseMap[id]; ok { if _, ok := le.leaseMap[id]; ok {
panic("lease: unexpected duplicate ID!") panic("lease: unexpected duplicate ID!")
} }
@ -85,7 +100,10 @@ func (le *lessor) Revoke(id uint64) error {
delete(le.leaseMap, l.id) delete(le.leaseMap, l.id)
// TODO: remove attached items for item := range l.itemSet {
le.dr.DeleteRange([]byte(item.key), []byte(item.endRange))
}
return nil return nil
} }

View File

@ -24,7 +24,7 @@ import (
// The granted lease should have a unique ID with a term // The granted lease should have a unique ID with a term
// that is greater than minLeaseTerm. // that is greater than minLeaseTerm.
func TestLessorGrant(t *testing.T) { func TestLessorGrant(t *testing.T) {
le := NewLessor(1) le := NewLessor(1, &fakeDeleteable{})
l := le.Grant(time.Now().Add(time.Second)) l := le.Grant(time.Now().Add(time.Second))
gl := le.get(l.id) gl := le.get(l.id)
@ -43,15 +43,28 @@ func TestLessorGrant(t *testing.T) {
} }
// TestLessorRevoke ensures Lessor can revoke a lease. // TestLessorRevoke ensures Lessor can revoke a lease.
// The items in the revoked lease should be removed from
// the DeleteableKV.
// The revoked lease cannot be got from Lessor again. // The revoked lease cannot be got from Lessor again.
func TestLessorRevoke(t *testing.T) { func TestLessorRevoke(t *testing.T) {
le := NewLessor(1) fd := &fakeDeleteable{}
le := NewLessor(1, fd)
// grant a lease with long term (100 seconds) to // grant a lease with long term (100 seconds) to
// avoid early termination during the test. // avoid early termination during the test.
l := le.Grant(time.Now().Add(100 * time.Second)) l := le.Grant(time.Now().Add(100 * time.Second))
err := le.Revoke(l.id) items := []leaseItem{
{"foo", ""},
{"bar", "zar"},
}
err := le.Attach(l.id, items)
if err != nil {
t.Fatalf("failed to attach items to the lease: %v", err)
}
err = le.Revoke(l.id)
if err != nil { if err != nil {
t.Fatal("failed to revoke lease:", err) t.Fatal("failed to revoke lease:", err)
} }
@ -59,11 +72,16 @@ func TestLessorRevoke(t *testing.T) {
if le.get(l.id) != nil { if le.get(l.id) != nil {
t.Errorf("got revoked lease %x", l.id) t.Errorf("got revoked lease %x", l.id)
} }
wdeleted := []string{"foo_", "bar_zar"}
if !reflect.DeepEqual(fd.deleted, wdeleted) {
t.Errorf("deleted= %v, want %v", fd.deleted, wdeleted)
}
} }
// TestLessorRenew ensures Lessor can renew an existing lease. // TestLessorRenew ensures Lessor can renew an existing lease.
func TestLessorRenew(t *testing.T) { func TestLessorRenew(t *testing.T) {
le := NewLessor(1) le := NewLessor(1, &fakeDeleteable{})
l := le.Grant(time.Now().Add(5 * time.Second)) l := le.Grant(time.Now().Add(5 * time.Second))
le.Renew(l.id, time.Now().Add(100*time.Second)) le.Renew(l.id, time.Now().Add(100*time.Second))
@ -73,3 +91,12 @@ func TestLessorRenew(t *testing.T) {
t.Errorf("failed to renew the lease for 100 seconds") t.Errorf("failed to renew the lease for 100 seconds")
} }
} }
type fakeDeleteable struct {
deleted []string
}
func (fd *fakeDeleteable) DeleteRange(key, end []byte) (int64, int64) {
fd.deleted = append(fd.deleted, string(key)+"_"+string(end))
return 0, 0
}