mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 17:57:51 +00:00
Add vendor folder to git
This commit is contained in:
parent
66cf5eaafb
commit
183585f56f
6916 changed files with 2629581 additions and 1 deletions
16
vendor/github.com/coreos/etcd/lease/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/lease/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package lease provides an interface and implemetation for time-limited leases over arbitrary resources.
|
||||
package lease
|
||||
16
vendor/github.com/coreos/etcd/lease/leasehttp/doc.go
generated
vendored
Normal file
16
vendor/github.com/coreos/etcd/lease/leasehttp/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package leasehttp serves lease renewals made through HTTP requests.
|
||||
package leasehttp
|
||||
260
vendor/github.com/coreos/etcd/lease/leasehttp/http.go
generated
vendored
Normal file
260
vendor/github.com/coreos/etcd/lease/leasehttp/http.go
generated
vendored
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package leasehttp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||
"github.com/coreos/etcd/lease"
|
||||
"github.com/coreos/etcd/lease/leasepb"
|
||||
"github.com/coreos/etcd/pkg/httputil"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
LeasePrefix = "/leases"
|
||||
LeaseInternalPrefix = "/leases/internal"
|
||||
applyTimeout = time.Second
|
||||
ErrLeaseHTTPTimeout = errors.New("waiting for node to catch up its applied index has timed out")
|
||||
)
|
||||
|
||||
// NewHandler returns an http Handler for lease renewals
|
||||
func NewHandler(l lease.Lessor, waitch func() <-chan struct{}) http.Handler {
|
||||
return &leaseHandler{l, waitch}
|
||||
}
|
||||
|
||||
type leaseHandler struct {
|
||||
l lease.Lessor
|
||||
waitch func() <-chan struct{}
|
||||
}
|
||||
|
||||
func (h *leaseHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "error reading body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var v []byte
|
||||
switch r.URL.Path {
|
||||
case LeasePrefix:
|
||||
lreq := pb.LeaseKeepAliveRequest{}
|
||||
if err := lreq.Unmarshal(b); err != nil {
|
||||
http.Error(w, "error unmarshalling request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-h.waitch():
|
||||
case <-time.After(applyTimeout):
|
||||
http.Error(w, ErrLeaseHTTPTimeout.Error(), http.StatusRequestTimeout)
|
||||
return
|
||||
}
|
||||
ttl, err := h.l.Renew(lease.LeaseID(lreq.ID))
|
||||
if err != nil {
|
||||
if err == lease.ErrLeaseNotFound {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// TODO: fill out ResponseHeader
|
||||
resp := &pb.LeaseKeepAliveResponse{ID: lreq.ID, TTL: ttl}
|
||||
v, err = resp.Marshal()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
case LeaseInternalPrefix:
|
||||
lreq := leasepb.LeaseInternalRequest{}
|
||||
if err := lreq.Unmarshal(b); err != nil {
|
||||
http.Error(w, "error unmarshalling request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-h.waitch():
|
||||
case <-time.After(applyTimeout):
|
||||
http.Error(w, ErrLeaseHTTPTimeout.Error(), http.StatusRequestTimeout)
|
||||
return
|
||||
}
|
||||
l := h.l.Lookup(lease.LeaseID(lreq.LeaseTimeToLiveRequest.ID))
|
||||
if l == nil {
|
||||
http.Error(w, lease.ErrLeaseNotFound.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
// TODO: fill out ResponseHeader
|
||||
resp := &leasepb.LeaseInternalResponse{
|
||||
LeaseTimeToLiveResponse: &pb.LeaseTimeToLiveResponse{
|
||||
Header: &pb.ResponseHeader{},
|
||||
ID: lreq.LeaseTimeToLiveRequest.ID,
|
||||
TTL: int64(l.Remaining().Seconds()),
|
||||
GrantedTTL: l.TTL(),
|
||||
},
|
||||
}
|
||||
if lreq.LeaseTimeToLiveRequest.Keys {
|
||||
ks := l.Keys()
|
||||
kbs := make([][]byte, len(ks))
|
||||
for i := range ks {
|
||||
kbs[i] = []byte(ks[i])
|
||||
}
|
||||
resp.LeaseTimeToLiveResponse.Keys = kbs
|
||||
}
|
||||
|
||||
v, err = resp.Marshal()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
default:
|
||||
http.Error(w, fmt.Sprintf("unknown request path %q", r.URL.Path), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/protobuf")
|
||||
w.Write(v)
|
||||
}
|
||||
|
||||
// RenewHTTP renews a lease at a given primary server.
|
||||
// TODO: Batch request in future?
|
||||
func RenewHTTP(ctx context.Context, id lease.LeaseID, url string, rt http.RoundTripper) (int64, error) {
|
||||
// will post lreq protobuf to leader
|
||||
lreq, err := (&pb.LeaseKeepAliveRequest{ID: int64(id)}).Marshal()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
cc := &http.Client{Transport: rt}
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(lreq))
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/protobuf")
|
||||
req.Cancel = ctx.Done()
|
||||
|
||||
resp, err := cc.Do(req)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
b, err := readResponse(resp)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusRequestTimeout {
|
||||
return -1, ErrLeaseHTTPTimeout
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return -1, lease.ErrLeaseNotFound
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return -1, fmt.Errorf("lease: unknown error(%s)", string(b))
|
||||
}
|
||||
|
||||
lresp := &pb.LeaseKeepAliveResponse{}
|
||||
if err := lresp.Unmarshal(b); err != nil {
|
||||
return -1, fmt.Errorf(`lease: %v. data = "%s"`, err, string(b))
|
||||
}
|
||||
if lresp.ID != int64(id) {
|
||||
return -1, fmt.Errorf("lease: renew id mismatch")
|
||||
}
|
||||
return lresp.TTL, nil
|
||||
}
|
||||
|
||||
// TimeToLiveHTTP retrieves lease information of the given lease ID.
|
||||
func TimeToLiveHTTP(ctx context.Context, id lease.LeaseID, keys bool, url string, rt http.RoundTripper) (*leasepb.LeaseInternalResponse, error) {
|
||||
// will post lreq protobuf to leader
|
||||
lreq, err := (&leasepb.LeaseInternalRequest{&pb.LeaseTimeToLiveRequest{ID: int64(id), Keys: keys}}).Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(lreq))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/protobuf")
|
||||
|
||||
cancel := httputil.RequestCanceler(req)
|
||||
|
||||
cc := &http.Client{Transport: rt}
|
||||
var b []byte
|
||||
// buffer errc channel so that errc don't block inside the go routinue
|
||||
errc := make(chan error, 2)
|
||||
go func() {
|
||||
resp, err := cc.Do(req)
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
b, err = readResponse(resp)
|
||||
if err != nil {
|
||||
errc <- err
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusRequestTimeout {
|
||||
errc <- ErrLeaseHTTPTimeout
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
errc <- lease.ErrLeaseNotFound
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
errc <- fmt.Errorf("lease: unknown error(%s)", string(b))
|
||||
return
|
||||
}
|
||||
errc <- nil
|
||||
}()
|
||||
select {
|
||||
case derr := <-errc:
|
||||
if derr != nil {
|
||||
return nil, derr
|
||||
}
|
||||
case <-ctx.Done():
|
||||
cancel()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
lresp := &leasepb.LeaseInternalResponse{}
|
||||
if err := lresp.Unmarshal(b); err != nil {
|
||||
return nil, fmt.Errorf(`lease: %v. data = "%s"`, err, string(b))
|
||||
}
|
||||
if lresp.LeaseTimeToLiveResponse.ID != int64(id) {
|
||||
return nil, fmt.Errorf("lease: renew id mismatch")
|
||||
}
|
||||
return lresp, nil
|
||||
}
|
||||
|
||||
func readResponse(resp *http.Response) (b []byte, err error) {
|
||||
b, err = ioutil.ReadAll(resp.Body)
|
||||
httputil.GracefulClose(resp)
|
||||
return
|
||||
}
|
||||
127
vendor/github.com/coreos/etcd/lease/leasehttp/http_test.go
generated
vendored
Normal file
127
vendor/github.com/coreos/etcd/lease/leasehttp/http_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2016 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package leasehttp
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/lease"
|
||||
"github.com/coreos/etcd/mvcc/backend"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
func TestRenewHTTP(t *testing.T) {
|
||||
be, tmpPath := backend.NewTmpBackend(time.Hour, 10000)
|
||||
defer os.Remove(tmpPath)
|
||||
defer be.Close()
|
||||
|
||||
le := lease.NewLessor(be, int64(5))
|
||||
le.Promote(time.Second)
|
||||
l, err := le.Grant(1, int64(5))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create lease: %v", err)
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(NewHandler(le, waitReady))
|
||||
defer ts.Close()
|
||||
|
||||
ttl, err := RenewHTTP(context.TODO(), l.ID, ts.URL+LeasePrefix, http.DefaultTransport)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if ttl != 5 {
|
||||
t.Fatalf("ttl expected 5, got %d", ttl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeToLiveHTTP(t *testing.T) {
|
||||
be, tmpPath := backend.NewTmpBackend(time.Hour, 10000)
|
||||
defer os.Remove(tmpPath)
|
||||
defer be.Close()
|
||||
|
||||
le := lease.NewLessor(be, int64(5))
|
||||
le.Promote(time.Second)
|
||||
l, err := le.Grant(1, int64(5))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create lease: %v", err)
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(NewHandler(le, waitReady))
|
||||
defer ts.Close()
|
||||
|
||||
resp, err := TimeToLiveHTTP(context.TODO(), l.ID, true, ts.URL+LeaseInternalPrefix, http.DefaultTransport)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.LeaseTimeToLiveResponse.ID != 1 {
|
||||
t.Fatalf("lease id expected 1, got %d", resp.LeaseTimeToLiveResponse.ID)
|
||||
}
|
||||
if resp.LeaseTimeToLiveResponse.GrantedTTL != 5 {
|
||||
t.Fatalf("granted TTL expected 5, got %d", resp.LeaseTimeToLiveResponse.GrantedTTL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenewHTTPTimeout(t *testing.T) {
|
||||
testApplyTimeout(t, func(l *lease.Lease, serverURL string) error {
|
||||
_, err := RenewHTTP(context.TODO(), l.ID, serverURL+LeasePrefix, http.DefaultTransport)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func TestTimeToLiveHTTPTimeout(t *testing.T) {
|
||||
testApplyTimeout(t, func(l *lease.Lease, serverURL string) error {
|
||||
_, err := TimeToLiveHTTP(context.TODO(), l.ID, true, serverURL+LeaseInternalPrefix, http.DefaultTransport)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func testApplyTimeout(t *testing.T, f func(*lease.Lease, string) error) {
|
||||
be, tmpPath := backend.NewTmpBackend(time.Hour, 10000)
|
||||
defer os.Remove(tmpPath)
|
||||
defer be.Close()
|
||||
|
||||
le := lease.NewLessor(be, int64(5))
|
||||
le.Promote(time.Second)
|
||||
l, err := le.Grant(1, int64(5))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create lease: %v", err)
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(NewHandler(le, waitNotReady))
|
||||
defer ts.Close()
|
||||
err = f(l, ts.URL)
|
||||
if err == nil {
|
||||
t.Fatalf("expected timeout error, got nil")
|
||||
}
|
||||
if strings.Compare(err.Error(), ErrLeaseHTTPTimeout.Error()) != 0 {
|
||||
t.Fatalf("expected (%v), got (%v)", ErrLeaseHTTPTimeout.Error(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func waitReady() <-chan struct{} {
|
||||
ch := make(chan struct{})
|
||||
close(ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
func waitNotReady() <-chan struct{} {
|
||||
return nil
|
||||
}
|
||||
608
vendor/github.com/coreos/etcd/lease/leasepb/lease.pb.go
generated
vendored
Normal file
608
vendor/github.com/coreos/etcd/lease/leasepb/lease.pb.go
generated
vendored
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
// Code generated by protoc-gen-gogo.
|
||||
// source: lease.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package leasepb is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
lease.proto
|
||||
|
||||
It has these top-level messages:
|
||||
Lease
|
||||
LeaseInternalRequest
|
||||
LeaseInternalResponse
|
||||
*/
|
||||
package leasepb
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
|
||||
math "math"
|
||||
|
||||
etcdserverpb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
||||
|
||||
io "io"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
type Lease struct {
|
||||
ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||
TTL int64 `protobuf:"varint,2,opt,name=TTL,proto3" json:"TTL,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Lease) Reset() { *m = Lease{} }
|
||||
func (m *Lease) String() string { return proto.CompactTextString(m) }
|
||||
func (*Lease) ProtoMessage() {}
|
||||
func (*Lease) Descriptor() ([]byte, []int) { return fileDescriptorLease, []int{0} }
|
||||
|
||||
type LeaseInternalRequest struct {
|
||||
LeaseTimeToLiveRequest *etcdserverpb.LeaseTimeToLiveRequest `protobuf:"bytes,1,opt,name=LeaseTimeToLiveRequest" json:"LeaseTimeToLiveRequest,omitempty"`
|
||||
}
|
||||
|
||||
func (m *LeaseInternalRequest) Reset() { *m = LeaseInternalRequest{} }
|
||||
func (m *LeaseInternalRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*LeaseInternalRequest) ProtoMessage() {}
|
||||
func (*LeaseInternalRequest) Descriptor() ([]byte, []int) { return fileDescriptorLease, []int{1} }
|
||||
|
||||
type LeaseInternalResponse struct {
|
||||
LeaseTimeToLiveResponse *etcdserverpb.LeaseTimeToLiveResponse `protobuf:"bytes,1,opt,name=LeaseTimeToLiveResponse" json:"LeaseTimeToLiveResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (m *LeaseInternalResponse) Reset() { *m = LeaseInternalResponse{} }
|
||||
func (m *LeaseInternalResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*LeaseInternalResponse) ProtoMessage() {}
|
||||
func (*LeaseInternalResponse) Descriptor() ([]byte, []int) { return fileDescriptorLease, []int{2} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Lease)(nil), "leasepb.Lease")
|
||||
proto.RegisterType((*LeaseInternalRequest)(nil), "leasepb.LeaseInternalRequest")
|
||||
proto.RegisterType((*LeaseInternalResponse)(nil), "leasepb.LeaseInternalResponse")
|
||||
}
|
||||
func (m *Lease) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *Lease) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.ID != 0 {
|
||||
dAtA[i] = 0x8
|
||||
i++
|
||||
i = encodeVarintLease(dAtA, i, uint64(m.ID))
|
||||
}
|
||||
if m.TTL != 0 {
|
||||
dAtA[i] = 0x10
|
||||
i++
|
||||
i = encodeVarintLease(dAtA, i, uint64(m.TTL))
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *LeaseInternalRequest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *LeaseInternalRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.LeaseTimeToLiveRequest != nil {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintLease(dAtA, i, uint64(m.LeaseTimeToLiveRequest.Size()))
|
||||
n1, err := m.LeaseTimeToLiveRequest.MarshalTo(dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n1
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *LeaseInternalResponse) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *LeaseInternalResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.LeaseTimeToLiveResponse != nil {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintLease(dAtA, i, uint64(m.LeaseTimeToLiveResponse.Size()))
|
||||
n2, err := m.LeaseTimeToLiveResponse.MarshalTo(dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n2
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func encodeFixed64Lease(dAtA []byte, offset int, v uint64) int {
|
||||
dAtA[offset] = uint8(v)
|
||||
dAtA[offset+1] = uint8(v >> 8)
|
||||
dAtA[offset+2] = uint8(v >> 16)
|
||||
dAtA[offset+3] = uint8(v >> 24)
|
||||
dAtA[offset+4] = uint8(v >> 32)
|
||||
dAtA[offset+5] = uint8(v >> 40)
|
||||
dAtA[offset+6] = uint8(v >> 48)
|
||||
dAtA[offset+7] = uint8(v >> 56)
|
||||
return offset + 8
|
||||
}
|
||||
func encodeFixed32Lease(dAtA []byte, offset int, v uint32) int {
|
||||
dAtA[offset] = uint8(v)
|
||||
dAtA[offset+1] = uint8(v >> 8)
|
||||
dAtA[offset+2] = uint8(v >> 16)
|
||||
dAtA[offset+3] = uint8(v >> 24)
|
||||
return offset + 4
|
||||
}
|
||||
func encodeVarintLease(dAtA []byte, offset int, v uint64) int {
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return offset + 1
|
||||
}
|
||||
func (m *Lease) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
if m.ID != 0 {
|
||||
n += 1 + sovLease(uint64(m.ID))
|
||||
}
|
||||
if m.TTL != 0 {
|
||||
n += 1 + sovLease(uint64(m.TTL))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *LeaseInternalRequest) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
if m.LeaseTimeToLiveRequest != nil {
|
||||
l = m.LeaseTimeToLiveRequest.Size()
|
||||
n += 1 + l + sovLease(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *LeaseInternalResponse) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
if m.LeaseTimeToLiveResponse != nil {
|
||||
l = m.LeaseTimeToLiveResponse.Size()
|
||||
n += 1 + l + sovLease(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovLease(x uint64) (n int) {
|
||||
for {
|
||||
n++
|
||||
x >>= 7
|
||||
if x == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
func sozLease(x uint64) (n int) {
|
||||
return sovLease(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *Lease) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Lease: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Lease: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
|
||||
}
|
||||
m.ID = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.ID |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field TTL", wireType)
|
||||
}
|
||||
m.TTL = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.TTL |= (int64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipLease(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthLease
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *LeaseInternalRequest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: LeaseInternalRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: LeaseInternalRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LeaseTimeToLiveRequest", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthLease
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.LeaseTimeToLiveRequest == nil {
|
||||
m.LeaseTimeToLiveRequest = &etcdserverpb.LeaseTimeToLiveRequest{}
|
||||
}
|
||||
if err := m.LeaseTimeToLiveRequest.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipLease(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthLease
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *LeaseInternalResponse) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: LeaseInternalResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: LeaseInternalResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field LeaseTimeToLiveResponse", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthLease
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.LeaseTimeToLiveResponse == nil {
|
||||
m.LeaseTimeToLiveResponse = &etcdserverpb.LeaseTimeToLiveResponse{}
|
||||
}
|
||||
if err := m.LeaseTimeToLiveResponse.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipLease(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthLease
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipLease(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
iNdEx += length
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthLease
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowLease
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipLease(dAtA[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthLease = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowLease = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
func init() { proto.RegisterFile("lease.proto", fileDescriptorLease) }
|
||||
|
||||
var fileDescriptorLease = []byte{
|
||||
// 233 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x49, 0x4d, 0x2c,
|
||||
0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x07, 0x73, 0x0a, 0x92, 0xa4, 0x44, 0xd2,
|
||||
0xf3, 0xd3, 0xf3, 0xc1, 0x62, 0xfa, 0x20, 0x16, 0x44, 0x5a, 0x4a, 0x2d, 0xb5, 0x24, 0x39, 0x45,
|
||||
0x1f, 0x44, 0x14, 0xa7, 0x16, 0x95, 0xa5, 0x16, 0x21, 0x31, 0x0b, 0x92, 0xf4, 0x8b, 0x0a, 0x92,
|
||||
0x21, 0xea, 0x94, 0x34, 0xb9, 0x58, 0x7d, 0x40, 0x06, 0x09, 0xf1, 0x71, 0x31, 0x79, 0xba, 0x48,
|
||||
0x30, 0x2a, 0x30, 0x6a, 0x30, 0x07, 0x31, 0x79, 0xba, 0x08, 0x09, 0x70, 0x31, 0x87, 0x84, 0xf8,
|
||||
0x48, 0x30, 0x81, 0x05, 0x40, 0x4c, 0xa5, 0x12, 0x2e, 0x11, 0xb0, 0x52, 0xcf, 0xbc, 0x92, 0xd4,
|
||||
0xa2, 0xbc, 0xc4, 0x9c, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0xa1, 0x18, 0x2e, 0x31, 0xb0,
|
||||
0x78, 0x48, 0x66, 0x6e, 0x6a, 0x48, 0xbe, 0x4f, 0x66, 0x59, 0x2a, 0x54, 0x06, 0x6c, 0x1a, 0xb7,
|
||||
0x91, 0x8a, 0x1e, 0xb2, 0xdd, 0x7a, 0xd8, 0xd5, 0x06, 0xe1, 0x30, 0x43, 0xa9, 0x82, 0x4b, 0x14,
|
||||
0xcd, 0xd6, 0xe2, 0x82, 0xfc, 0xbc, 0xe2, 0x54, 0xa1, 0x78, 0x2e, 0x71, 0x0c, 0x2d, 0x10, 0x29,
|
||||
0xa8, 0xbd, 0xaa, 0x04, 0xec, 0x85, 0x28, 0x0e, 0xc2, 0x65, 0x8a, 0x93, 0xc4, 0x89, 0x87, 0x72,
|
||||
0x0c, 0x17, 0x1e, 0xca, 0x31, 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47,
|
||||
0x72, 0x8c, 0x33, 0x1e, 0xcb, 0x31, 0x24, 0xb1, 0x81, 0xc3, 0xce, 0x18, 0x10, 0x00, 0x00, 0xff,
|
||||
0xff, 0x9f, 0xf2, 0x42, 0xe0, 0x91, 0x01, 0x00, 0x00,
|
||||
}
|
||||
24
vendor/github.com/coreos/etcd/lease/leasepb/lease.proto
generated
vendored
Normal file
24
vendor/github.com/coreos/etcd/lease/leasepb/lease.proto
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
syntax = "proto3";
|
||||
package leasepb;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "etcd/etcdserver/etcdserverpb/rpc.proto";
|
||||
|
||||
option (gogoproto.marshaler_all) = true;
|
||||
option (gogoproto.sizer_all) = true;
|
||||
option (gogoproto.unmarshaler_all) = true;
|
||||
option (gogoproto.goproto_getters_all) = false;
|
||||
option (gogoproto.goproto_enum_prefix_all) = false;
|
||||
|
||||
message Lease {
|
||||
int64 ID = 1;
|
||||
int64 TTL = 2;
|
||||
}
|
||||
|
||||
message LeaseInternalRequest {
|
||||
etcdserverpb.LeaseTimeToLiveRequest LeaseTimeToLiveRequest = 1;
|
||||
}
|
||||
|
||||
message LeaseInternalResponse {
|
||||
etcdserverpb.LeaseTimeToLiveResponse LeaseTimeToLiveResponse = 1;
|
||||
}
|
||||
602
vendor/github.com/coreos/etcd/lease/lessor.go
generated
vendored
Normal file
602
vendor/github.com/coreos/etcd/lease/lessor.go
generated
vendored
Normal file
|
|
@ -0,0 +1,602 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package lease
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/lease/leasepb"
|
||||
"github.com/coreos/etcd/mvcc/backend"
|
||||
"github.com/coreos/etcd/pkg/monotime"
|
||||
)
|
||||
|
||||
const (
|
||||
// NoLease is a special LeaseID representing the absence of a lease.
|
||||
NoLease = LeaseID(0)
|
||||
)
|
||||
|
||||
var (
|
||||
leaseBucketName = []byte("lease")
|
||||
|
||||
forever = monotime.Time(math.MaxInt64)
|
||||
|
||||
ErrNotPrimary = errors.New("not a primary lessor")
|
||||
ErrLeaseNotFound = errors.New("lease not found")
|
||||
ErrLeaseExists = errors.New("lease already exists")
|
||||
)
|
||||
|
||||
type LeaseID int64
|
||||
|
||||
// RangeDeleter defines an interface with Txn and DeleteRange method.
|
||||
// We define this interface only for lessor to limit the number
|
||||
// of methods of mvcc.KV to what lessor actually needs.
|
||||
//
|
||||
// Having a minimum interface makes testing easy.
|
||||
type RangeDeleter interface {
|
||||
// TxnBegin see comments on mvcc.KV
|
||||
TxnBegin() int64
|
||||
// TxnEnd see comments on mvcc.KV
|
||||
TxnEnd(txnID int64) error
|
||||
// TxnDeleteRange see comments on mvcc.KV
|
||||
TxnDeleteRange(txnID int64, key, end []byte) (n, rev int64, err error)
|
||||
}
|
||||
|
||||
// Lessor owns leases. It can grant, revoke, renew and modify leases for lessee.
|
||||
type Lessor interface {
|
||||
// SetRangeDeleter sets the RangeDeleter to the Lessor.
|
||||
// Lessor deletes the items in the revoked or expired lease from the
|
||||
// the set RangeDeleter.
|
||||
SetRangeDeleter(dr RangeDeleter)
|
||||
|
||||
// Grant grants a lease that expires at least after TTL seconds.
|
||||
Grant(id LeaseID, ttl int64) (*Lease, error)
|
||||
// Revoke revokes a lease with given ID. The item attached to the
|
||||
// given lease will be removed. If the ID does not exist, an error
|
||||
// will be returned.
|
||||
Revoke(id LeaseID) error
|
||||
|
||||
// Attach attaches given leaseItem to the lease with given LeaseID.
|
||||
// If the lease does not exist, an error will be returned.
|
||||
Attach(id LeaseID, items []LeaseItem) error
|
||||
|
||||
// GetLease returns LeaseID for given item.
|
||||
// If no lease found, NoLease value will be returned.
|
||||
GetLease(item LeaseItem) LeaseID
|
||||
|
||||
// Detach detaches given leaseItem from the lease with given LeaseID.
|
||||
// If the lease does not exist, an error will be returned.
|
||||
Detach(id LeaseID, items []LeaseItem) error
|
||||
|
||||
// Promote promotes the lessor to be the primary lessor. Primary lessor manages
|
||||
// the expiration and renew of leases.
|
||||
// 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()
|
||||
|
||||
// Renew renews a lease with given ID. It returns the renewed TTL. If the ID does not exist,
|
||||
// an error will be returned.
|
||||
Renew(id LeaseID) (int64, error)
|
||||
|
||||
// Lookup gives the lease at a given lease id, if any
|
||||
Lookup(id LeaseID) *Lease
|
||||
|
||||
// ExpiredLeasesC returns a chan that is used to receive expired leases.
|
||||
ExpiredLeasesC() <-chan []*Lease
|
||||
|
||||
// Recover recovers the lessor state from the given backend and RangeDeleter.
|
||||
Recover(b backend.Backend, rd RangeDeleter)
|
||||
|
||||
// Stop stops the lessor for managing leases. The behavior of calling Stop multiple
|
||||
// times is undefined.
|
||||
Stop()
|
||||
}
|
||||
|
||||
// lessor implements Lessor interface.
|
||||
// TODO: use clockwork for testability.
|
||||
type lessor struct {
|
||||
mu sync.Mutex
|
||||
|
||||
// demotec is set when the lessor is the primary.
|
||||
// demotec will be closed if the lessor is demoted.
|
||||
demotec chan struct{}
|
||||
|
||||
// TODO: probably this should be a heap with a secondary
|
||||
// id index.
|
||||
// Now it is O(N) to loop over the leases to find expired ones.
|
||||
// We want to make Grant, Revoke, and findExpiredLeases all O(logN) and
|
||||
// Renew O(1).
|
||||
// findExpiredLeases and Renew should be the most frequent operations.
|
||||
leaseMap map[LeaseID]*Lease
|
||||
|
||||
itemMap map[LeaseItem]LeaseID
|
||||
|
||||
// When a lease expires, the lessor will delete the
|
||||
// leased range (or key) by the RangeDeleter.
|
||||
rd RangeDeleter
|
||||
|
||||
// backend to persist leases. We only persist lease ID and expiry for now.
|
||||
// The leased items can be recovered by iterating all the keys in kv.
|
||||
b backend.Backend
|
||||
|
||||
// minLeaseTTL is the minimum lease TTL that can be granted for a lease. Any
|
||||
// requests for shorter TTLs are extended to the minimum TTL.
|
||||
minLeaseTTL int64
|
||||
|
||||
expiredC chan []*Lease
|
||||
// stopC is a channel whose closure indicates that the lessor should be stopped.
|
||||
stopC chan struct{}
|
||||
// doneC is a channel whose closure indicates that the lessor is stopped.
|
||||
doneC chan struct{}
|
||||
}
|
||||
|
||||
func NewLessor(b backend.Backend, minLeaseTTL int64) Lessor {
|
||||
return newLessor(b, minLeaseTTL)
|
||||
}
|
||||
|
||||
func newLessor(b backend.Backend, minLeaseTTL int64) *lessor {
|
||||
l := &lessor{
|
||||
leaseMap: make(map[LeaseID]*Lease),
|
||||
itemMap: make(map[LeaseItem]LeaseID),
|
||||
b: b,
|
||||
minLeaseTTL: minLeaseTTL,
|
||||
// expiredC is a small buffered chan to avoid unnecessary blocking.
|
||||
expiredC: make(chan []*Lease, 16),
|
||||
stopC: make(chan struct{}),
|
||||
doneC: make(chan struct{}),
|
||||
}
|
||||
l.initAndRecover()
|
||||
|
||||
go l.runLoop()
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
// isPrimary indicates if this lessor is the primary lessor. The primary
|
||||
// lessor manages lease expiration and renew.
|
||||
//
|
||||
// in etcd, raft leader is the primary. Thus there might be two primary
|
||||
// leaders at the same time (raft allows concurrent leader but with different term)
|
||||
// for at most a leader election timeout.
|
||||
// The old primary leader cannot affect the correctness since its proposal has a
|
||||
// smaller term and will not be committed.
|
||||
//
|
||||
// TODO: raft follower do not forward lease management proposals. There might be a
|
||||
// very small window (within second normally which depends on go scheduling) that
|
||||
// a raft follow is the primary between the raft leader demotion and lessor demotion.
|
||||
// Usually this should not be a problem. Lease should not be that sensitive to timing.
|
||||
func (le *lessor) isPrimary() bool {
|
||||
return le.demotec != nil
|
||||
}
|
||||
|
||||
func (le *lessor) SetRangeDeleter(rd RangeDeleter) {
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
|
||||
le.rd = rd
|
||||
}
|
||||
|
||||
func (le *lessor) Grant(id LeaseID, ttl int64) (*Lease, error) {
|
||||
if id == NoLease {
|
||||
return nil, ErrLeaseNotFound
|
||||
}
|
||||
|
||||
// TODO: when lessor is under high load, it should give out lease
|
||||
// with longer TTL to reduce renew load.
|
||||
l := &Lease{
|
||||
ID: id,
|
||||
ttl: ttl,
|
||||
itemSet: make(map[LeaseItem]struct{}),
|
||||
revokec: make(chan struct{}),
|
||||
}
|
||||
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
|
||||
if _, ok := le.leaseMap[id]; ok {
|
||||
return nil, ErrLeaseExists
|
||||
}
|
||||
|
||||
if l.ttl < le.minLeaseTTL {
|
||||
l.ttl = le.minLeaseTTL
|
||||
}
|
||||
|
||||
if le.isPrimary() {
|
||||
l.refresh(0)
|
||||
} else {
|
||||
l.forever()
|
||||
}
|
||||
|
||||
le.leaseMap[id] = l
|
||||
l.persistTo(le.b)
|
||||
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (le *lessor) Revoke(id LeaseID) error {
|
||||
le.mu.Lock()
|
||||
|
||||
l := le.leaseMap[id]
|
||||
if l == nil {
|
||||
le.mu.Unlock()
|
||||
return ErrLeaseNotFound
|
||||
}
|
||||
defer close(l.revokec)
|
||||
// unlock before doing external work
|
||||
le.mu.Unlock()
|
||||
|
||||
if le.rd == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
tid := le.rd.TxnBegin()
|
||||
|
||||
// sort keys so deletes are in same order among all members,
|
||||
// otherwise the backened hashes will be different
|
||||
keys := l.Keys()
|
||||
sort.StringSlice(keys).Sort()
|
||||
for _, key := range keys {
|
||||
_, _, err := le.rd.TxnDeleteRange(tid, []byte(key), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
delete(le.leaseMap, l.ID)
|
||||
// lease deletion needs to be in the same backend transaction with the
|
||||
// kv deletion. Or we might end up with not executing the revoke or not
|
||||
// deleting the keys if etcdserver fails in between.
|
||||
le.b.BatchTx().UnsafeDelete(leaseBucketName, int64ToBytes(int64(l.ID)))
|
||||
|
||||
err := le.rd.TxnEnd(tid)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Renew renews an existing lease. If the given lease does not exist or
|
||||
// has expired, an error will be returned.
|
||||
func (le *lessor) Renew(id LeaseID) (int64, error) {
|
||||
le.mu.Lock()
|
||||
|
||||
unlock := func() { le.mu.Unlock() }
|
||||
defer func() { unlock() }()
|
||||
|
||||
if !le.isPrimary() {
|
||||
// forward renew request to primary instead of returning error.
|
||||
return -1, ErrNotPrimary
|
||||
}
|
||||
|
||||
demotec := le.demotec
|
||||
|
||||
l := le.leaseMap[id]
|
||||
if l == nil {
|
||||
return -1, ErrLeaseNotFound
|
||||
}
|
||||
|
||||
if l.expired() {
|
||||
le.mu.Unlock()
|
||||
unlock = func() {}
|
||||
select {
|
||||
// A expired lease might be pending for revoking or going through
|
||||
// quorum to be revoked. To be accurate, renew request must wait for the
|
||||
// deletion to complete.
|
||||
case <-l.revokec:
|
||||
return -1, ErrLeaseNotFound
|
||||
// The expired lease might fail to be revoked if the primary changes.
|
||||
// The caller will retry on ErrNotPrimary.
|
||||
case <-demotec:
|
||||
return -1, ErrNotPrimary
|
||||
case <-le.stopC:
|
||||
return -1, ErrNotPrimary
|
||||
}
|
||||
}
|
||||
|
||||
l.refresh(0)
|
||||
return l.ttl, nil
|
||||
}
|
||||
|
||||
func (le *lessor) Lookup(id LeaseID) *Lease {
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
return le.leaseMap[id]
|
||||
}
|
||||
|
||||
func (le *lessor) Promote(extend time.Duration) {
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
|
||||
le.demotec = make(chan struct{})
|
||||
|
||||
// refresh the expiries of all leases.
|
||||
for _, l := range le.leaseMap {
|
||||
l.refresh(extend)
|
||||
}
|
||||
}
|
||||
|
||||
func (le *lessor) Demote() {
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
|
||||
// set the expiries of all leases to forever
|
||||
for _, l := range le.leaseMap {
|
||||
l.forever()
|
||||
}
|
||||
|
||||
if le.demotec != nil {
|
||||
close(le.demotec)
|
||||
le.demotec = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Attach attaches items to the lease with given ID. When the lease
|
||||
// expires, the attached items will be automatically removed.
|
||||
// If the given lease does not exist, an error will be returned.
|
||||
func (le *lessor) Attach(id LeaseID, items []LeaseItem) error {
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
|
||||
l := le.leaseMap[id]
|
||||
if l == nil {
|
||||
return ErrLeaseNotFound
|
||||
}
|
||||
|
||||
l.mu.Lock()
|
||||
for _, it := range items {
|
||||
l.itemSet[it] = struct{}{}
|
||||
le.itemMap[it] = id
|
||||
}
|
||||
l.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (le *lessor) GetLease(item LeaseItem) LeaseID {
|
||||
le.mu.Lock()
|
||||
id := le.itemMap[item]
|
||||
le.mu.Unlock()
|
||||
return id
|
||||
}
|
||||
|
||||
// Detach detaches items from the lease with given ID.
|
||||
// If the given lease does not exist, an error will be returned.
|
||||
func (le *lessor) Detach(id LeaseID, items []LeaseItem) error {
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
|
||||
l := le.leaseMap[id]
|
||||
if l == nil {
|
||||
return ErrLeaseNotFound
|
||||
}
|
||||
|
||||
l.mu.Lock()
|
||||
for _, it := range items {
|
||||
delete(l.itemSet, it)
|
||||
delete(le.itemMap, it)
|
||||
}
|
||||
l.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (le *lessor) Recover(b backend.Backend, rd RangeDeleter) {
|
||||
le.mu.Lock()
|
||||
defer le.mu.Unlock()
|
||||
|
||||
le.b = b
|
||||
le.rd = rd
|
||||
le.leaseMap = make(map[LeaseID]*Lease)
|
||||
le.itemMap = make(map[LeaseItem]LeaseID)
|
||||
le.initAndRecover()
|
||||
}
|
||||
|
||||
func (le *lessor) ExpiredLeasesC() <-chan []*Lease {
|
||||
return le.expiredC
|
||||
}
|
||||
|
||||
func (le *lessor) Stop() {
|
||||
close(le.stopC)
|
||||
<-le.doneC
|
||||
}
|
||||
|
||||
func (le *lessor) runLoop() {
|
||||
defer close(le.doneC)
|
||||
|
||||
for {
|
||||
var ls []*Lease
|
||||
|
||||
le.mu.Lock()
|
||||
if le.isPrimary() {
|
||||
ls = le.findExpiredLeases()
|
||||
}
|
||||
le.mu.Unlock()
|
||||
|
||||
if len(ls) != 0 {
|
||||
select {
|
||||
case <-le.stopC:
|
||||
return
|
||||
case le.expiredC <- ls:
|
||||
default:
|
||||
// the receiver of expiredC is probably busy handling
|
||||
// other stuff
|
||||
// let's try this next time after 500ms
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(500 * time.Millisecond):
|
||||
case <-le.stopC:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// findExpiredLeases loops all the leases in the leaseMap and returns the expired
|
||||
// leases that needed to be revoked.
|
||||
func (le *lessor) findExpiredLeases() []*Lease {
|
||||
leases := make([]*Lease, 0, 16)
|
||||
|
||||
for _, l := range le.leaseMap {
|
||||
// TODO: probably should change to <= 100-500 millisecond to
|
||||
// make up committing latency.
|
||||
if l.expired() {
|
||||
leases = append(leases, l)
|
||||
}
|
||||
}
|
||||
|
||||
return leases
|
||||
}
|
||||
|
||||
func (le *lessor) initAndRecover() {
|
||||
tx := le.b.BatchTx()
|
||||
tx.Lock()
|
||||
|
||||
tx.UnsafeCreateBucket(leaseBucketName)
|
||||
_, vs := tx.UnsafeRange(leaseBucketName, int64ToBytes(0), int64ToBytes(math.MaxInt64), 0)
|
||||
// TODO: copy vs and do decoding outside tx lock if lock contention becomes an issue.
|
||||
for i := range vs {
|
||||
var lpb leasepb.Lease
|
||||
err := lpb.Unmarshal(vs[i])
|
||||
if err != nil {
|
||||
tx.Unlock()
|
||||
panic("failed to unmarshal lease proto item")
|
||||
}
|
||||
ID := LeaseID(lpb.ID)
|
||||
if lpb.TTL < le.minLeaseTTL {
|
||||
lpb.TTL = le.minLeaseTTL
|
||||
}
|
||||
le.leaseMap[ID] = &Lease{
|
||||
ID: ID,
|
||||
ttl: lpb.TTL,
|
||||
// itemSet will be filled in when recover key-value pairs
|
||||
// set expiry to forever, refresh when promoted
|
||||
itemSet: make(map[LeaseItem]struct{}),
|
||||
expiry: forever,
|
||||
revokec: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
tx.Unlock()
|
||||
|
||||
le.b.ForceCommit()
|
||||
}
|
||||
|
||||
type Lease struct {
|
||||
ID LeaseID
|
||||
ttl int64 // time to live in seconds
|
||||
// expiry is time when lease should expire; must be 64-bit aligned.
|
||||
expiry monotime.Time
|
||||
|
||||
// mu protects concurrent accesses to itemSet
|
||||
mu sync.RWMutex
|
||||
itemSet map[LeaseItem]struct{}
|
||||
revokec chan struct{}
|
||||
}
|
||||
|
||||
func (l *Lease) expired() bool {
|
||||
return l.Remaining() <= 0
|
||||
}
|
||||
|
||||
func (l *Lease) persistTo(b backend.Backend) {
|
||||
key := int64ToBytes(int64(l.ID))
|
||||
|
||||
lpb := leasepb.Lease{ID: int64(l.ID), TTL: int64(l.ttl)}
|
||||
val, err := lpb.Marshal()
|
||||
if err != nil {
|
||||
panic("failed to marshal lease proto item")
|
||||
}
|
||||
|
||||
b.BatchTx().Lock()
|
||||
b.BatchTx().UnsafePut(leaseBucketName, key, val)
|
||||
b.BatchTx().Unlock()
|
||||
}
|
||||
|
||||
// TTL returns the TTL of the Lease.
|
||||
func (l *Lease) TTL() int64 {
|
||||
return l.ttl
|
||||
}
|
||||
|
||||
// refresh refreshes the expiry of the lease.
|
||||
func (l *Lease) refresh(extend time.Duration) {
|
||||
t := monotime.Now().Add(extend + time.Duration(l.ttl)*time.Second)
|
||||
atomic.StoreUint64((*uint64)(&l.expiry), uint64(t))
|
||||
}
|
||||
|
||||
// forever sets the expiry of lease to be forever.
|
||||
func (l *Lease) forever() { atomic.StoreUint64((*uint64)(&l.expiry), uint64(forever)) }
|
||||
|
||||
// Keys returns all the keys attached to the lease.
|
||||
func (l *Lease) Keys() []string {
|
||||
l.mu.RLock()
|
||||
keys := make([]string, 0, len(l.itemSet))
|
||||
for k := range l.itemSet {
|
||||
keys = append(keys, k.Key)
|
||||
}
|
||||
l.mu.RUnlock()
|
||||
return keys
|
||||
}
|
||||
|
||||
// Remaining returns the remaining time of the lease.
|
||||
func (l *Lease) Remaining() time.Duration {
|
||||
t := monotime.Time(atomic.LoadUint64((*uint64)(&l.expiry)))
|
||||
return time.Duration(t - monotime.Now())
|
||||
}
|
||||
|
||||
type LeaseItem struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func int64ToBytes(n int64) []byte {
|
||||
bytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(bytes, uint64(n))
|
||||
return bytes
|
||||
}
|
||||
|
||||
// FakeLessor is a fake implementation of Lessor interface.
|
||||
// Used for testing only.
|
||||
type FakeLessor struct{}
|
||||
|
||||
func (fl *FakeLessor) SetRangeDeleter(dr RangeDeleter) {}
|
||||
|
||||
func (fl *FakeLessor) Grant(id LeaseID, ttl int64) (*Lease, error) { return nil, nil }
|
||||
|
||||
func (fl *FakeLessor) Revoke(id LeaseID) error { return nil }
|
||||
|
||||
func (fl *FakeLessor) Attach(id LeaseID, items []LeaseItem) error { return nil }
|
||||
|
||||
func (fl *FakeLessor) GetLease(item LeaseItem) LeaseID { return 0 }
|
||||
func (fl *FakeLessor) Detach(id LeaseID, items []LeaseItem) error { return nil }
|
||||
|
||||
func (fl *FakeLessor) Promote(extend time.Duration) {}
|
||||
|
||||
func (fl *FakeLessor) Demote() {}
|
||||
|
||||
func (fl *FakeLessor) Renew(id LeaseID) (int64, error) { return 10, nil }
|
||||
|
||||
func (le *FakeLessor) Lookup(id LeaseID) *Lease { return nil }
|
||||
|
||||
func (fl *FakeLessor) ExpiredLeasesC() <-chan []*Lease { return nil }
|
||||
|
||||
func (fl *FakeLessor) Recover(b backend.Backend, rd RangeDeleter) {}
|
||||
|
||||
func (fl *FakeLessor) Stop() {}
|
||||
404
vendor/github.com/coreos/etcd/lease/lessor_test.go
generated
vendored
Normal file
404
vendor/github.com/coreos/etcd/lease/lessor_test.go
generated
vendored
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
// Copyright 2015 The etcd Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package lease
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/mvcc/backend"
|
||||
)
|
||||
|
||||
const (
|
||||
minLeaseTTL = int64(5)
|
||||
minLeaseTTLDuration = time.Duration(minLeaseTTL) * time.Second
|
||||
)
|
||||
|
||||
// TestLessorGrant ensures Lessor can grant wanted lease.
|
||||
// The granted lease should have a unique ID with a term
|
||||
// that is greater than minLeaseTTL.
|
||||
func TestLessorGrant(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer os.RemoveAll(dir)
|
||||
defer be.Close()
|
||||
|
||||
le := newLessor(be, minLeaseTTL)
|
||||
le.Promote(0)
|
||||
|
||||
l, err := le.Grant(1, 1)
|
||||
if err != nil {
|
||||
t.Fatalf("could not grant lease 1 (%v)", err)
|
||||
}
|
||||
gl := le.Lookup(l.ID)
|
||||
|
||||
if !reflect.DeepEqual(gl, l) {
|
||||
t.Errorf("lease = %v, want %v", gl, l)
|
||||
}
|
||||
if l.Remaining() < minLeaseTTLDuration-time.Second {
|
||||
t.Errorf("term = %v, want at least %v", l.Remaining(), minLeaseTTLDuration-time.Second)
|
||||
}
|
||||
|
||||
nl, err := le.Grant(1, 1)
|
||||
if err == nil {
|
||||
t.Errorf("allocated the same lease")
|
||||
}
|
||||
|
||||
nl, err = le.Grant(2, 1)
|
||||
if err != nil {
|
||||
t.Errorf("could not grant lease 2 (%v)", err)
|
||||
}
|
||||
if nl.ID == l.ID {
|
||||
t.Errorf("new lease.id = %x, want != %x", nl.ID, l.ID)
|
||||
}
|
||||
|
||||
be.BatchTx().Lock()
|
||||
_, vs := be.BatchTx().UnsafeRange(leaseBucketName, int64ToBytes(int64(l.ID)), nil, 0)
|
||||
if len(vs) != 1 {
|
||||
t.Errorf("len(vs) = %d, want 1", len(vs))
|
||||
}
|
||||
be.BatchTx().Unlock()
|
||||
}
|
||||
|
||||
// TestLeaseConcurrentKeys ensures Lease.Keys method calls are guarded
|
||||
// from concurrent map writes on 'itemSet'.
|
||||
func TestLeaseConcurrentKeys(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer os.RemoveAll(dir)
|
||||
defer be.Close()
|
||||
|
||||
fd := &fakeDeleter{}
|
||||
|
||||
le := newLessor(be, minLeaseTTL)
|
||||
le.SetRangeDeleter(fd)
|
||||
|
||||
// grant a lease with long term (100 seconds) to
|
||||
// avoid early termination during the test.
|
||||
l, err := le.Grant(1, 100)
|
||||
if err != nil {
|
||||
t.Fatalf("could not grant lease for 100s ttl (%v)", err)
|
||||
}
|
||||
|
||||
itemn := 10
|
||||
items := make([]LeaseItem, itemn)
|
||||
for i := 0; i < itemn; i++ {
|
||||
items[i] = LeaseItem{Key: fmt.Sprintf("foo%d", i)}
|
||||
}
|
||||
if err = le.Attach(l.ID, items); err != nil {
|
||||
t.Fatalf("failed to attach items to the lease: %v", err)
|
||||
}
|
||||
|
||||
donec := make(chan struct{})
|
||||
go func() {
|
||||
le.Detach(l.ID, items)
|
||||
close(donec)
|
||||
}()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(itemn)
|
||||
for i := 0; i < itemn; i++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
l.Keys()
|
||||
}()
|
||||
}
|
||||
|
||||
<-donec
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// TestLessorRevoke ensures Lessor can revoke a lease.
|
||||
// The items in the revoked lease should be removed from
|
||||
// the backend.
|
||||
// The revoked lease cannot be got from Lessor again.
|
||||
func TestLessorRevoke(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer os.RemoveAll(dir)
|
||||
defer be.Close()
|
||||
|
||||
fd := &fakeDeleter{}
|
||||
|
||||
le := newLessor(be, minLeaseTTL)
|
||||
le.SetRangeDeleter(fd)
|
||||
|
||||
// grant a lease with long term (100 seconds) to
|
||||
// avoid early termination during the test.
|
||||
l, err := le.Grant(1, 100)
|
||||
if err != nil {
|
||||
t.Fatalf("could not grant lease for 100s ttl (%v)", err)
|
||||
}
|
||||
|
||||
items := []LeaseItem{
|
||||
{"foo"},
|
||||
{"bar"},
|
||||
}
|
||||
|
||||
if err = le.Attach(l.ID, items); err != nil {
|
||||
t.Fatalf("failed to attach items to the lease: %v", err)
|
||||
}
|
||||
|
||||
if err = le.Revoke(l.ID); err != nil {
|
||||
t.Fatal("failed to revoke lease:", err)
|
||||
}
|
||||
|
||||
if le.Lookup(l.ID) != nil {
|
||||
t.Errorf("got revoked lease %x", l.ID)
|
||||
}
|
||||
|
||||
wdeleted := []string{"bar_", "foo_"}
|
||||
sort.Sort(sort.StringSlice(fd.deleted))
|
||||
if !reflect.DeepEqual(fd.deleted, wdeleted) {
|
||||
t.Errorf("deleted= %v, want %v", fd.deleted, wdeleted)
|
||||
}
|
||||
|
||||
be.BatchTx().Lock()
|
||||
_, vs := be.BatchTx().UnsafeRange(leaseBucketName, int64ToBytes(int64(l.ID)), nil, 0)
|
||||
if len(vs) != 0 {
|
||||
t.Errorf("len(vs) = %d, want 0", len(vs))
|
||||
}
|
||||
be.BatchTx().Unlock()
|
||||
}
|
||||
|
||||
// TestLessorRenew ensures Lessor can renew an existing lease.
|
||||
func TestLessorRenew(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer be.Close()
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
le := newLessor(be, minLeaseTTL)
|
||||
le.Promote(0)
|
||||
|
||||
l, err := le.Grant(1, minLeaseTTL)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to grant lease (%v)", err)
|
||||
}
|
||||
|
||||
// manually change the ttl field
|
||||
le.mu.Lock()
|
||||
l.ttl = 10
|
||||
le.mu.Unlock()
|
||||
ttl, err := le.Renew(l.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to renew lease (%v)", err)
|
||||
}
|
||||
if ttl != l.ttl {
|
||||
t.Errorf("ttl = %d, want %d", ttl, l.ttl)
|
||||
}
|
||||
|
||||
l = le.Lookup(l.ID)
|
||||
if l.Remaining() < 9*time.Second {
|
||||
t.Errorf("failed to renew the lease")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLessorDetach(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer os.RemoveAll(dir)
|
||||
defer be.Close()
|
||||
|
||||
fd := &fakeDeleter{}
|
||||
|
||||
le := newLessor(be, minLeaseTTL)
|
||||
le.SetRangeDeleter(fd)
|
||||
|
||||
// grant a lease with long term (100 seconds) to
|
||||
// avoid early termination during the test.
|
||||
l, err := le.Grant(1, 100)
|
||||
if err != nil {
|
||||
t.Fatalf("could not grant lease for 100s ttl (%v)", err)
|
||||
}
|
||||
|
||||
items := []LeaseItem{
|
||||
{"foo"},
|
||||
{"bar"},
|
||||
}
|
||||
|
||||
if err := le.Attach(l.ID, items); err != nil {
|
||||
t.Fatalf("failed to attach items to the lease: %v", err)
|
||||
}
|
||||
|
||||
if err := le.Detach(l.ID, items[0:1]); err != nil {
|
||||
t.Fatalf("failed to de-attach items to the lease: %v", err)
|
||||
}
|
||||
|
||||
l = le.Lookup(l.ID)
|
||||
if len(l.itemSet) != 1 {
|
||||
t.Fatalf("len(l.itemSet) = %d, failed to de-attach items", len(l.itemSet))
|
||||
}
|
||||
if _, ok := l.itemSet[LeaseItem{"bar"}]; !ok {
|
||||
t.Fatalf("de-attached wrong item, want %q exists", "bar")
|
||||
}
|
||||
}
|
||||
|
||||
// TestLessorRecover ensures Lessor recovers leases from
|
||||
// persist backend.
|
||||
func TestLessorRecover(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer os.RemoveAll(dir)
|
||||
defer be.Close()
|
||||
|
||||
le := newLessor(be, minLeaseTTL)
|
||||
l1, err1 := le.Grant(1, 10)
|
||||
l2, err2 := le.Grant(2, 20)
|
||||
if err1 != nil || err2 != nil {
|
||||
t.Fatalf("could not grant initial leases (%v, %v)", err1, err2)
|
||||
}
|
||||
|
||||
// Create a new lessor with the same backend
|
||||
nle := newLessor(be, minLeaseTTL)
|
||||
nl1 := nle.Lookup(l1.ID)
|
||||
if nl1 == nil || nl1.ttl != l1.ttl {
|
||||
t.Errorf("nl1 = %v, want nl1.ttl= %d", nl1.ttl, l1.ttl)
|
||||
}
|
||||
|
||||
nl2 := nle.Lookup(l2.ID)
|
||||
if nl2 == nil || nl2.ttl != l2.ttl {
|
||||
t.Errorf("nl2 = %v, want nl2.ttl= %d", nl2.ttl, l2.ttl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLessorExpire(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer os.RemoveAll(dir)
|
||||
defer be.Close()
|
||||
|
||||
testMinTTL := int64(1)
|
||||
|
||||
le := newLessor(be, testMinTTL)
|
||||
defer le.Stop()
|
||||
|
||||
le.Promote(1 * time.Second)
|
||||
l, err := le.Grant(1, testMinTTL)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create lease: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case el := <-le.ExpiredLeasesC():
|
||||
if el[0].ID != l.ID {
|
||||
t.Fatalf("expired id = %x, want %x", el[0].ID, l.ID)
|
||||
}
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatalf("failed to receive expired lease")
|
||||
}
|
||||
|
||||
donec := make(chan struct{})
|
||||
go func() {
|
||||
// expired lease cannot be renewed
|
||||
if _, err := le.Renew(l.ID); err != ErrLeaseNotFound {
|
||||
t.Fatalf("unexpected renew")
|
||||
}
|
||||
donec <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-donec:
|
||||
t.Fatalf("renew finished before lease revocation")
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
}
|
||||
|
||||
// expired lease can be revoked
|
||||
if err := le.Revoke(l.ID); err != nil {
|
||||
t.Fatalf("failed to revoke expired lease: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-donec:
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatalf("renew has not returned after lease revocation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLessorExpireAndDemote(t *testing.T) {
|
||||
dir, be := NewTestBackend(t)
|
||||
defer os.RemoveAll(dir)
|
||||
defer be.Close()
|
||||
|
||||
testMinTTL := int64(1)
|
||||
|
||||
le := newLessor(be, testMinTTL)
|
||||
defer le.Stop()
|
||||
|
||||
le.Promote(1 * time.Second)
|
||||
l, err := le.Grant(1, testMinTTL)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create lease: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case el := <-le.ExpiredLeasesC():
|
||||
if el[0].ID != l.ID {
|
||||
t.Fatalf("expired id = %x, want %x", el[0].ID, l.ID)
|
||||
}
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatalf("failed to receive expired lease")
|
||||
}
|
||||
|
||||
donec := make(chan struct{})
|
||||
go func() {
|
||||
// expired lease cannot be renewed
|
||||
if _, err := le.Renew(l.ID); err != ErrNotPrimary {
|
||||
t.Fatalf("unexpected renew: %v", err)
|
||||
}
|
||||
donec <- struct{}{}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-donec:
|
||||
t.Fatalf("renew finished before demotion")
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
}
|
||||
|
||||
// demote will cause the renew request to fail with ErrNotPrimary
|
||||
le.Demote()
|
||||
|
||||
select {
|
||||
case <-donec:
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatalf("renew has not returned after lessor demotion")
|
||||
}
|
||||
}
|
||||
|
||||
type fakeDeleter struct {
|
||||
deleted []string
|
||||
}
|
||||
|
||||
func (fd *fakeDeleter) TxnBegin() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fd *fakeDeleter) TxnEnd(txnID int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fd *fakeDeleter) TxnDeleteRange(tid int64, key, end []byte) (int64, int64, error) {
|
||||
fd.deleted = append(fd.deleted, string(key)+"_"+string(end))
|
||||
return 0, 0, nil
|
||||
}
|
||||
|
||||
func NewTestBackend(t *testing.T) (string, backend.Backend) {
|
||||
tmpPath, err := ioutil.TempDir("", "lease")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tmpdir (%v)", err)
|
||||
}
|
||||
|
||||
return tmpPath, backend.New(filepath.Join(tmpPath, "be"), time.Second, 10000)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue