Skip to content

Commit

Permalink
Disable file locking when DEPNOLOCK set (golang#1206)
Browse files Browse the repository at this point in the history
* Disable file locking when DEPNOLOCK set

* Add DisableLocking bool members to Ctx and gps.SourceManagerConfig structs.
  This effectively communicates DEPNOLOCK from the shell, to Ctx, to
  SourceManager.

  The member is named DisableLocking to make its zero-value useful.

* Add locker interface which implements TryLock(), Unlock(), and GetOwner()
  which lockfile.Lockfile alredy adheres to.  This interface replaces the new
  type for the lf member of the SourceMgr struct.

* Add a FalseLocker type which adheres to the Locker interface which does
  nothing.

* Conditionally set the lf member of SourceMgr to either an instance of
  lockfile.Lockfile or FalseLocker depending on the value of
  SourceManagerConfig.DisableLocking.

Signed-off-by: Ayan George <[email protected]>

* Revert stray edit.

Signed-off-by: Ayan George <[email protected]>

* Improve comment for DisableLocking

Signed-off-by: Ayan George <[email protected]>

* Fix comment type-os

* Fix comment type-os

Signed-off-by: Ayan George <[email protected]>

* Fix yet more type-os.

Signed-off-by: Ayan George <[email protected]>
  • Loading branch information
ayang64 authored and zknill committed Oct 6, 2017
1 parent c87c7b4 commit e4ac3c9
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 15 deletions.
7 changes: 4 additions & 3 deletions cmd/dep/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ func (c *Config) Run() (exitCode int) {

// Set up dep context.
ctx := &dep.Ctx{
Out: outLogger,
Err: errLogger,
Verbose: *verbose,
Out: outLogger,
Err: errLogger,
Verbose: *verbose,
DisableLocking: getEnv(c.Env, "DEPNOLOCK") != "",
}

GOPATHS := filepath.SplitList(getEnv(c.Env, "GOPATH"))
Expand Down
16 changes: 9 additions & 7 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ import (
// }
//
type Ctx struct {
WorkingDir string // Where to execute.
GOPATH string // Selected Go path, containing WorkingDir.
GOPATHs []string // Other Go paths.
Out, Err *log.Logger // Required loggers.
Verbose bool // Enables more verbose logging.
WorkingDir string // Where to execute.
GOPATH string // Selected Go path, containing WorkingDir.
GOPATHs []string // Other Go paths.
Out, Err *log.Logger // Required loggers.
Verbose bool // Enables more verbose logging.
DisableLocking bool // When set, no lock file will be created to protect against simultaneous dep processes.
}

// SetPaths sets the WorkingDir and GOPATHs fields. If GOPATHs is empty, then
Expand Down Expand Up @@ -87,8 +88,9 @@ func defaultGOPATH() string {
// initialized to log to the receiver's logger.
func (c *Ctx) SourceManager() (*gps.SourceMgr, error) {
return gps.NewSourceManager(gps.SourceManagerConfig{
Cachedir: filepath.Join(c.GOPATH, "pkg", "dep"),
Logger: c.Out,
Cachedir: filepath.Join(c.GOPATH, "pkg", "dep"),
Logger: c.Out,
DisableLocking: c.DisableLocking,
})
}

Expand Down
53 changes: 48 additions & 5 deletions internal/gps/source_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,41 @@ import (
// Used to compute a friendly filepath from a URL-shaped input.
var sanitizer = strings.NewReplacer("-", "--", ":", "-", "/", "-", "+", "-")

// A locker is responsible for preventing multiple instances of dep from
// interfering with one-another.
//
// Currently, anything that can either TryLock(), Unlock(), or GetOwner()
// satifies that need.
type locker interface {
TryLock() error
Unlock() error
GetOwner() (*os.Process, error)
}

// A falselocker adheres to the locker interface and its purpose is to quietly
// fail to lock when the DEPNOLOCK environment variable is set.
//
// This allows dep to run on systems where file locking doesn't work --
// particularly those that use union mount type filesystems that don't
// implement hard links or fnctl() style locking.
type falseLocker struct{}

// Always returns an error to indicate there's no current ower PID for our
// lock.
func (fl falseLocker) GetOwner() (*os.Process, error) {
return nil, fmt.Errorf("falseLocker always fails")
}

// Does nothing and returns a nil error so caller beleives locking succeeded.
func (fl falseLocker) TryLock() error {
return nil
}

// Does nothing and returns a nil error so caller beleives unlocking succeeded.
func (fl falseLocker) Unlock() error {
return nil
}

// A SourceManager is responsible for retrieving, managing, and interrogating
// source repositories. Its primary purpose is to serve the needs of a Solver,
// but it is handy for other purposes, as well.
Expand Down Expand Up @@ -122,7 +157,7 @@ func (p ProjectAnalyzerInfo) String() string {
// tools; control via dependency injection is intended to be sufficient.
type SourceMgr struct {
cachedir string // path to root of cache dir
lf *lockfile.Lockfile // handle for the sm lock file on disk
lf locker // handle for the sm lock file on disk
suprvsr *supervisor // subsystem that supervises running calls/io
cancelAll context.CancelFunc // cancel func to kill all running work
deduceCoord *deductionCoordinator // subsystem that manages import path deduction
Expand All @@ -143,8 +178,9 @@ var _ SourceManager = &SourceMgr{}

// SourceManagerConfig holds configuration information for creating SourceMgrs.
type SourceManagerConfig struct {
Cachedir string // Where to store local instances of upstream sources.
Logger *log.Logger // Optional info/warn logger. Discards if nil.
Cachedir string // Where to store local instances of upstream sources.
Logger *log.Logger // Optional info/warn logger. Discards if nil.
DisableLocking bool // True if the SourceManager should NOT use a lock file to protect the Cachedir from multiple processes.
}

// NewSourceManager produces an instance of gps's built-in SourceManager.
Expand Down Expand Up @@ -176,7 +212,14 @@ func NewSourceManager(c SourceManagerConfig) (*SourceMgr, error) {
// we can spin on.

glpath := filepath.Join(c.Cachedir, "sm.lock")
lockfile, err := lockfile.New(glpath)

lockfile, err := func() (locker, error) {
if c.DisableLocking {
return falseLocker{}, nil
}
return lockfile.New(glpath)
}()

if err != nil {
return nil, CouldNotCreateLockError{
Path: glpath,
Expand Down Expand Up @@ -239,7 +282,7 @@ func NewSourceManager(c SourceManagerConfig) (*SourceMgr, error) {

sm := &SourceMgr{
cachedir: c.Cachedir,
lf: &lockfile,
lf: lockfile,
suprvsr: superv,
cancelAll: cf,
deduceCoord: deducer,
Expand Down

0 comments on commit e4ac3c9

Please sign in to comment.