|
@@ -29,7 +29,7 @@ var (
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
type Election struct {
|
|
type Election struct {
|
|
|
- client *v3.Client
|
|
|
|
|
|
|
+ session *Session
|
|
|
|
|
|
|
|
keyPrefix string
|
|
keyPrefix string
|
|
|
|
|
|
|
@@ -39,20 +39,18 @@ type Election struct {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// NewElection returns a new election on a given key prefix.
|
|
// NewElection returns a new election on a given key prefix.
|
|
|
-func NewElection(client *v3.Client, pfx string) *Election {
|
|
|
|
|
- return &Election{client: client, keyPrefix: pfx}
|
|
|
|
|
|
|
+func NewElection(s *Session, pfx string) *Election {
|
|
|
|
|
+ return &Election{session: s, keyPrefix: pfx}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Campaign puts a value as eligible for the election. It blocks until
|
|
// Campaign puts a value as eligible for the election. It blocks until
|
|
|
// it is elected, an error occurs, or the context is cancelled.
|
|
// it is elected, an error occurs, or the context is cancelled.
|
|
|
func (e *Election) Campaign(ctx context.Context, val string) error {
|
|
func (e *Election) Campaign(ctx context.Context, val string) error {
|
|
|
- s, serr := NewSession(e.client)
|
|
|
|
|
- if serr != nil {
|
|
|
|
|
- return serr
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ s := e.session
|
|
|
|
|
+ client := e.session.Client()
|
|
|
|
|
|
|
|
k := fmt.Sprintf("%s/%x", e.keyPrefix, s.Lease())
|
|
k := fmt.Sprintf("%s/%x", e.keyPrefix, s.Lease())
|
|
|
- txn := e.client.Txn(ctx).If(v3.Compare(v3.CreateRevision(k), "=", 0))
|
|
|
|
|
|
|
+ txn := client.Txn(ctx).If(v3.Compare(v3.CreateRevision(k), "=", 0))
|
|
|
txn = txn.Then(v3.OpPut(k, val, v3.WithLease(s.Lease())))
|
|
txn = txn.Then(v3.OpPut(k, val, v3.WithLease(s.Lease())))
|
|
|
txn = txn.Else(v3.OpGet(k))
|
|
txn = txn.Else(v3.OpGet(k))
|
|
|
resp, err := txn.Commit()
|
|
resp, err := txn.Commit()
|
|
@@ -72,12 +70,12 @@ func (e *Election) Campaign(ctx context.Context, val string) error {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- err = waitDeletes(ctx, e.client, e.keyPrefix, v3.WithPrefix(), v3.WithRev(e.leaderRev-1))
|
|
|
|
|
|
|
+ err = waitDeletes(ctx, client, e.keyPrefix, v3.WithPrefix(), v3.WithRev(e.leaderRev-1))
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
// clean up in case of context cancel
|
|
// clean up in case of context cancel
|
|
|
select {
|
|
select {
|
|
|
case <-ctx.Done():
|
|
case <-ctx.Done():
|
|
|
- e.Resign(e.client.Ctx())
|
|
|
|
|
|
|
+ e.Resign(client.Ctx())
|
|
|
default:
|
|
default:
|
|
|
e.leaderSession = nil
|
|
e.leaderSession = nil
|
|
|
}
|
|
}
|
|
@@ -92,8 +90,9 @@ func (e *Election) Proclaim(ctx context.Context, val string) error {
|
|
|
if e.leaderSession == nil {
|
|
if e.leaderSession == nil {
|
|
|
return ErrElectionNotLeader
|
|
return ErrElectionNotLeader
|
|
|
}
|
|
}
|
|
|
|
|
+ client := e.session.Client()
|
|
|
cmp := v3.Compare(v3.CreateRevision(e.leaderKey), "=", e.leaderRev)
|
|
cmp := v3.Compare(v3.CreateRevision(e.leaderKey), "=", e.leaderRev)
|
|
|
- txn := e.client.Txn(ctx).If(cmp)
|
|
|
|
|
|
|
+ txn := client.Txn(ctx).If(cmp)
|
|
|
txn = txn.Then(v3.OpPut(e.leaderKey, val, v3.WithLease(e.leaderSession.Lease())))
|
|
txn = txn.Then(v3.OpPut(e.leaderKey, val, v3.WithLease(e.leaderSession.Lease())))
|
|
|
tresp, terr := txn.Commit()
|
|
tresp, terr := txn.Commit()
|
|
|
if terr != nil {
|
|
if terr != nil {
|
|
@@ -111,7 +110,8 @@ func (e *Election) Resign(ctx context.Context) (err error) {
|
|
|
if e.leaderSession == nil {
|
|
if e.leaderSession == nil {
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
- _, err = e.client.Delete(ctx, e.leaderKey)
|
|
|
|
|
|
|
+ client := e.session.Client()
|
|
|
|
|
+ _, err = client.Delete(ctx, e.leaderKey)
|
|
|
e.leaderKey = ""
|
|
e.leaderKey = ""
|
|
|
e.leaderSession = nil
|
|
e.leaderSession = nil
|
|
|
return err
|
|
return err
|
|
@@ -119,7 +119,8 @@ func (e *Election) Resign(ctx context.Context) (err error) {
|
|
|
|
|
|
|
|
// Leader returns the leader value for the current election.
|
|
// Leader returns the leader value for the current election.
|
|
|
func (e *Election) Leader(ctx context.Context) (string, error) {
|
|
func (e *Election) Leader(ctx context.Context) (string, error) {
|
|
|
- resp, err := e.client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...)
|
|
|
|
|
|
|
+ client := e.session.Client()
|
|
|
|
|
+ resp, err := client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return "", err
|
|
return "", err
|
|
|
} else if len(resp.Kvs) == 0 {
|
|
} else if len(resp.Kvs) == 0 {
|
|
@@ -139,9 +140,11 @@ func (e *Election) Observe(ctx context.Context) <-chan v3.GetResponse {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
|
|
func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
|
|
|
|
|
+ client := e.session.Client()
|
|
|
|
|
+
|
|
|
defer close(ch)
|
|
defer close(ch)
|
|
|
for {
|
|
for {
|
|
|
- resp, err := e.client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...)
|
|
|
|
|
|
|
+ resp, err := client.Get(ctx, e.keyPrefix, v3.WithFirstCreate()...)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
@@ -152,7 +155,7 @@ func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
|
|
|
if len(resp.Kvs) == 0 {
|
|
if len(resp.Kvs) == 0 {
|
|
|
// wait for first key put on prefix
|
|
// wait for first key put on prefix
|
|
|
opts := []v3.OpOption{v3.WithRev(resp.Header.Revision), v3.WithPrefix()}
|
|
opts := []v3.OpOption{v3.WithRev(resp.Header.Revision), v3.WithPrefix()}
|
|
|
- wch := e.client.Watch(cctx, e.keyPrefix, opts...)
|
|
|
|
|
|
|
+ wch := client.Watch(cctx, e.keyPrefix, opts...)
|
|
|
|
|
|
|
|
for kv == nil {
|
|
for kv == nil {
|
|
|
wr, ok := <-wch
|
|
wr, ok := <-wch
|
|
@@ -172,7 +175,7 @@ func (e *Election) observe(ctx context.Context, ch chan<- v3.GetResponse) {
|
|
|
kv = resp.Kvs[0]
|
|
kv = resp.Kvs[0]
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- wch := e.client.Watch(cctx, string(kv.Key), v3.WithRev(kv.ModRevision))
|
|
|
|
|
|
|
+ wch := client.Watch(cctx, string(kv.Key), v3.WithRev(kv.ModRevision))
|
|
|
keyDeleted := false
|
|
keyDeleted := false
|
|
|
for !keyDeleted {
|
|
for !keyDeleted {
|
|
|
wr, ok := <-wch
|
|
wr, ok := <-wch
|