blob: ca89aa9f5ca91196ab71d74f48d235b3a6af12cb [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"fmt"
"math/rand"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/naming"
"v.io/v23/security"
"v.io/x/lib/vlog"
"v.io/x/lock/locklib"
)
var unclaimedLockNhSuffix = "unclaimed-lock-" + fmt.Sprintf("%d", rand.Intn(1000000))
// startServer checks whether the lock has been claimed and then appropriately
// starts the server.
//
// Returns the callback to be invoked to shutdown the server on success, or
// an error on failure
func startServer(ctx *context.T, configDir string) (func(), error) {
// The lock is claimed if and only if there exists a file in the
// config directory from a previous claim.
if isLockClaimed(configDir) {
return startLockServer(ctx, configDir)
}
claimed, stopUnclaimedLock, err := startUnclaimedLockServer(ctx, configDir)
if err != nil {
return nil, err
}
stop := make(chan struct{})
stopped := make(chan struct{})
go waitToBeClaimedAndStartLockServer(ctx, configDir, stopUnclaimedLock, claimed, stop, stopped)
return func() {
close(stop)
<-stopped
}, nil
}
func startUnclaimedLockServer(ctx *context.T, configDir string) (<-chan struct{}, func(), error) {
// Start a local mounttable where the unclaimed lock server would
// be mounted, and make this mounttable visible in the local
// neighborhood.
mtName, stopMT, err := locklib.StartMounttable(ctx, configDir, locklib.LockNhPrefix+unclaimedLockNhSuffix)
if err != nil {
return nil, nil, err
}
ctx, _, err = v23.WithNewNamespace(ctx, mtName)
if err != nil {
stopMT()
return nil, nil, err
}
claimed := make(chan struct{})
ctx, cancel := context.WithCancel(ctx)
_, server, err := v23.WithNewServer(ctx, lockObjectName(ctx), newUnclaimedLock(claimed, configDir), security.AllowEveryone())
if err != nil {
stopMT()
return nil, nil, err
}
stopUnclaimedLock := func() {
cancel()
vlog.Infof("Stopping unclaimed lock server...")
<-server.Closed()
vlog.Infof("Stopped unclaimed lock server...")
stopMT()
}
vlog.Infof("Started unclaimed lock server\n")
vlog.Infof("ENDPOINT: %v\n", server.Status().Endpoints[0].Name())
return claimed, stopUnclaimedLock, nil
}
func startLockServer(ctx *context.T, configDir string) (func(), error) {
blessings, _ := v23.GetPrincipal(ctx).BlessingStore().Default()
lockNhSuffix := fmt.Sprint(blessings)
// Start a local mounttable where the lock server would be
// mounted, and make this mounttable visible in the local
// neighborhood.
mtName, stopMT, err := locklib.StartMounttable(ctx, configDir, locklib.LockNhPrefix+lockNhSuffix)
if err != nil {
return nil, err
}
ctx, _, err = v23.WithNewNamespace(ctx, mtName)
if err != nil {
stopMT()
return nil, err
}
ctx, cancel := context.WithCancel(ctx)
_, server, err := v23.WithNewServer(ctx, lockObjectName(ctx), newLock(), security.DefaultAuthorizer())
if err != nil {
stopMT()
return nil, err
}
stopLock := func() {
cancel()
vlog.Infof("Stopping lock server...")
<-server.Closed()
vlog.Infof("Stopped lock server...")
stopMT()
}
vlog.Infof("Started lock server\n")
vlog.Infof("ENDPOINT: %v\n", server.Status().Endpoints[0].Name())
return stopLock, nil
}
func waitToBeClaimedAndStartLockServer(ctx *context.T, configDir string, stopUnclaimedLock func(), claimed, stop <-chan struct{}, stopped chan<- struct{}) {
defer close(stopped)
select {
case <-claimed:
stopUnclaimedLock()
case <-stop:
stopUnclaimedLock()
return
}
stopLock, err := startLockServer(ctx, configDir)
if err != nil {
vlog.Errorf("Failed to start lock server after it was claimed: %v", err)
return
}
defer stopLock()
<-stop // Wait to be stopped
}
func lockObjectName(ctx *context.T) string {
nsroots := v23.GetNamespace(ctx).Roots()
if len(nsroots) == 0 {
return ""
}
return naming.Join(nsroots[0], locklib.LockSuffix)
}