Skip to content

Commit

Permalink
fix config data race
Browse files Browse the repository at this point in the history
This fixes a data-race in the config.

This does not fix #4942 as there's still a
logical race: parallel config updates clobber each other.

License: MIT
Signed-off-by: Steven Allen <steven@stebalien.com>
  • Loading branch information
Stebalien committed Dec 20, 2018
1 parent 5894291 commit 56b6277
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 9 deletions.
15 changes: 9 additions & 6 deletions core/commands/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,15 +401,18 @@ func transformConfig(configRoot string, configName string, transformer config.Tr
}
defer r.Close()

cfg, err := r.Config()
oldCfg, err := r.Config()
if err != nil {
return nil, nil, err
}

// make a copy to avoid updating repo's config unintentionally
oldCfg := *cfg
newCfg := oldCfg
err = transformer(&newCfg)
newCfg, err := oldCfg.Clone()
if err != nil {
return nil, nil, err
}

err = transformer(newCfg)
if err != nil {
return nil, nil, err
}
Expand All @@ -420,13 +423,13 @@ func transformConfig(configRoot string, configName string, transformer config.Tr
return nil, nil, err
}

err = r.SetConfig(&newCfg)
err = r.SetConfig(newCfg)
if err != nil {
return nil, nil, err
}
}

return &oldCfg, &newCfg, nil
return oldCfg, newCfg, nil
}

func getConfig(r repo.Repo, key string) (*ConfigField, error) {
Expand Down
11 changes: 8 additions & 3 deletions repo/fsrepo/fsrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,11 @@ func (r *FSRepo) Close() error {
return r.lockfile.Close()
}

// Config the current config. This function DOES NOT copy the config. The caller
// MUST NOT modify it without first calling `Clone`.
//
// Result when not Open is undefined. The method may panic if it pleases.
func (r *FSRepo) Config() (*config.Config, error) {

// It is not necessary to hold the package lock since the repo is in an
// opened state. The package lock is _not_ meant to ensure that the repo is
// thread-safe. The package lock is only meant to guard against removal and
Expand Down Expand Up @@ -546,11 +548,14 @@ func (r *FSRepo) setConfigUnsynced(updated *config.Config) error {
if err := serialize.WriteConfigFile(configFilename, mapconf); err != nil {
return err
}
*r.config = *updated // copy so caller cannot modify this private config
// Do not use `*r.config = ...`. This will modify the *shared* config
// returned by `r.Config`.
r.config = updated
return nil
}

// SetConfig updates the FSRepo's config.
// SetConfig updates the FSRepo's config. The user must not modify the config
// object after calling this method.
func (r *FSRepo) SetConfig(updated *config.Config) error {

// packageLock is held to provide thread-safety.
Expand Down

0 comments on commit 56b6277

Please sign in to comment.