blob: 8080e9ba5c6556301598fa65e4cbb81e4bd9248a [file] [log] [blame]
package main
import (
"context"
"time"
"github.com/golang/glog"
)
type lockCtrl struct {
getCurrent *lockCtrlGetCurrent
take *lockCtrlTake
release *lockCtrlRelease
subscribe *lockCtrlSubscribe
bump *lockCtrlBump
}
type lockCtrlGetCurrent struct {
res chan *lockResCurrent
}
type lockCtrlTake struct {
note string
addr string
prev string
res chan bool
}
type lockCtrlRelease struct {
addr string
force bool
res chan struct{}
}
type lockCtrlSubscribe struct {
subscriber chan *lockUpdate
}
type lockCtrlBump struct {
addr string
}
type lockResCurrent struct {
note string
addr string
deadline time.Time
}
type lockUpdate struct {
note string
addr string
}
func (s *service) runLocker(ctx context.Context, ctrlC chan *lockCtrl, ownershipDuration time.Duration) {
glog.Infof("Locker starting...")
var curNote string
var curAddr string
var curDeadline time.Time
var subscribers []chan *lockUpdate
notify := func() {
for _, sub := range subscribers {
go func() {
sub <- &lockUpdate{
note: curNote,
addr: curAddr,
}
}()
}
}
t := time.NewTicker(5 * time.Second)
defer t.Stop()
for {
select {
case <-ctx.Done():
err := ctx.Err()
glog.Errorf("Locker stoppped: %v", err)
return
case <-t.C:
if curAddr != "" && time.Now().After(curDeadline) {
glog.Infof("Expiring lock")
curAddr = ""
curNote = ""
notify()
}
case ctrl := <-ctrlC:
switch {
case ctrl.take != nil:
won := false
if curAddr == ctrl.take.prev {
won = true
curNote = ctrl.take.note
curAddr = ctrl.take.addr
curDeadline = time.Now().Add(ownershipDuration)
notify()
glog.Infof("Lock taken by %q %q", curNote, curAddr)
}
go func() {
ctrl.take.res <- won
}()
case ctrl.release != nil:
if curAddr == ctrl.release.addr || ctrl.release.force {
curAddr = ""
curNote = ""
notify()
glog.Infof("Lock relased")
}
go func() {
ctrl.release.res <- struct{}{}
}()
case ctrl.getCurrent != nil:
go func() {
ctrl.getCurrent.res <- &lockResCurrent{
note: curNote,
addr: curAddr,
deadline: curDeadline,
}
}()
case ctrl.bump != nil:
if curAddr != "" {
curDeadline = time.Now().Add(ownershipDuration)
}
case ctrl.subscribe != nil:
subscribers = append(subscribers, ctrl.subscribe.subscriber)
}
}
}
}