Lock down Context. #116

This commit is contained in:
Andrey Smirnov
2015-02-16 00:33:10 +03:00
parent 76ee53e9f8
commit 87cecac4ea
+93 -15
View File
@@ -18,11 +18,14 @@ import (
"runtime" "runtime"
"runtime/pprof" "runtime/pprof"
"strings" "strings"
"sync"
"time" "time"
) )
// AptlyContext is a common context shared by all commands // AptlyContext is a common context shared by all commands
type AptlyContext struct { type AptlyContext struct {
sync.Mutex
flags, globalFlags *flag.FlagSet flags, globalFlags *flag.FlagSet
configLoaded bool configLoaded bool
@@ -61,6 +64,13 @@ func Fatal(err error) {
// Config loads and returns current configuration // Config loads and returns current configuration
func (context *AptlyContext) Config() *utils.ConfigStructure { func (context *AptlyContext) Config() *utils.ConfigStructure {
context.Lock()
defer context.Unlock()
return context.config()
}
func (context *AptlyContext) config() *utils.ConfigStructure {
if !context.configLoaded { if !context.configLoaded {
var err error var err error
@@ -102,6 +112,13 @@ func (context *AptlyContext) Config() *utils.ConfigStructure {
// LookupOption checks boolean flag with default (usually config) and command-line // LookupOption checks boolean flag with default (usually config) and command-line
// setting // setting
func (context *AptlyContext) LookupOption(defaultValue bool, name string) (result bool) { func (context *AptlyContext) LookupOption(defaultValue bool, name string) (result bool) {
context.Lock()
defer context.Unlock()
return context.lookupOption(defaultValue, name)
}
func (context *AptlyContext) lookupOption(defaultValue bool, name string) (result bool) {
result = defaultValue result = defaultValue
if context.globalFlags.IsSet(name) { if context.globalFlags.IsSet(name) {
@@ -113,18 +130,21 @@ func (context *AptlyContext) LookupOption(defaultValue bool, name string) (resul
// DependencyOptions calculates options related to dependecy handling // DependencyOptions calculates options related to dependecy handling
func (context *AptlyContext) DependencyOptions() int { func (context *AptlyContext) DependencyOptions() int {
context.Lock()
defer context.Unlock()
if context.dependencyOptions == -1 { if context.dependencyOptions == -1 {
context.dependencyOptions = 0 context.dependencyOptions = 0
if context.LookupOption(context.Config().DepFollowSuggests, "dep-follow-suggests") { if context.lookupOption(context.config().DepFollowSuggests, "dep-follow-suggests") {
context.dependencyOptions |= deb.DepFollowSuggests context.dependencyOptions |= deb.DepFollowSuggests
} }
if context.LookupOption(context.Config().DepFollowRecommends, "dep-follow-recommends") { if context.lookupOption(context.config().DepFollowRecommends, "dep-follow-recommends") {
context.dependencyOptions |= deb.DepFollowRecommends context.dependencyOptions |= deb.DepFollowRecommends
} }
if context.LookupOption(context.Config().DepFollowAllVariants, "dep-follow-all-variants") { if context.lookupOption(context.config().DepFollowAllVariants, "dep-follow-all-variants") {
context.dependencyOptions |= deb.DepFollowAllVariants context.dependencyOptions |= deb.DepFollowAllVariants
} }
if context.LookupOption(context.Config().DepFollowSource, "dep-follow-source") { if context.lookupOption(context.config().DepFollowSource, "dep-follow-source") {
context.dependencyOptions |= deb.DepFollowSource context.dependencyOptions |= deb.DepFollowSource
} }
} }
@@ -134,8 +154,11 @@ func (context *AptlyContext) DependencyOptions() int {
// ArchitecturesList returns list of architectures fixed via command line or config // ArchitecturesList returns list of architectures fixed via command line or config
func (context *AptlyContext) ArchitecturesList() []string { func (context *AptlyContext) ArchitecturesList() []string {
context.Lock()
defer context.Unlock()
if context.architecturesList == nil { if context.architecturesList == nil {
context.architecturesList = context.Config().Architectures context.architecturesList = context.config().Architectures
optionArchitectures := context.globalFlags.Lookup("architectures").Value.String() optionArchitectures := context.globalFlags.Lookup("architectures").Value.String()
if optionArchitectures != "" { if optionArchitectures != "" {
context.architecturesList = strings.Split(optionArchitectures, ",") context.architecturesList = strings.Split(optionArchitectures, ",")
@@ -147,6 +170,13 @@ func (context *AptlyContext) ArchitecturesList() []string {
// Progress creates or returns Progress object // Progress creates or returns Progress object
func (context *AptlyContext) Progress() aptly.Progress { func (context *AptlyContext) Progress() aptly.Progress {
context.Lock()
defer context.Unlock()
return context._progress()
}
func (context *AptlyContext) _progress() aptly.Progress {
if context.progress == nil { if context.progress == nil {
context.progress = console.NewProgress() context.progress = console.NewProgress()
context.progress.Start() context.progress.Start()
@@ -157,6 +187,9 @@ func (context *AptlyContext) Progress() aptly.Progress {
// Downloader returns instance of current downloader // Downloader returns instance of current downloader
func (context *AptlyContext) Downloader() aptly.Downloader { func (context *AptlyContext) Downloader() aptly.Downloader {
context.Lock()
defer context.Unlock()
if context.downloader == nil { if context.downloader == nil {
var downloadLimit int64 var downloadLimit int64
limitFlag := context.flags.Lookup("download-limit") limitFlag := context.flags.Lookup("download-limit")
@@ -164,10 +197,10 @@ func (context *AptlyContext) Downloader() aptly.Downloader {
downloadLimit = limitFlag.Value.Get().(int64) downloadLimit = limitFlag.Value.Get().(int64)
} }
if downloadLimit == 0 { if downloadLimit == 0 {
downloadLimit = context.Config().DownloadLimit downloadLimit = context.config().DownloadLimit
} }
context.downloader = http.NewDownloader(context.Config().DownloadConcurrency, context.downloader = http.NewDownloader(context.config().DownloadConcurrency,
downloadLimit*1024, context.Progress()) downloadLimit*1024, context._progress())
} }
return context.downloader return context.downloader
@@ -175,15 +208,30 @@ func (context *AptlyContext) Downloader() aptly.Downloader {
// DBPath builds path to database // DBPath builds path to database
func (context *AptlyContext) DBPath() string { func (context *AptlyContext) DBPath() string {
return filepath.Join(context.Config().RootDir, "db") context.Lock()
defer context.Unlock()
return context.dbPath()
}
// DBPath builds path to database
func (context *AptlyContext) dbPath() string {
return filepath.Join(context.config().RootDir, "db")
} }
// Database opens and returns current instance of database // Database opens and returns current instance of database
func (context *AptlyContext) Database() (database.Storage, error) { func (context *AptlyContext) Database() (database.Storage, error) {
context.Lock()
defer context.Unlock()
return context._database()
}
func (context *AptlyContext) _database() (database.Storage, error) {
if context.database == nil { if context.database == nil {
var err error var err error
context.database, err = database.OpenDB(context.DBPath()) context.database, err = database.OpenDB(context.dbPath())
if err != nil { if err != nil {
return nil, fmt.Errorf("can't open database: %s", err) return nil, fmt.Errorf("can't open database: %s", err)
} }
@@ -194,6 +242,9 @@ func (context *AptlyContext) Database() (database.Storage, error) {
// CloseDatabase closes the db temporarily // CloseDatabase closes the db temporarily
func (context *AptlyContext) CloseDatabase() error { func (context *AptlyContext) CloseDatabase() error {
context.Lock()
defer context.Unlock()
if context.database == nil { if context.database == nil {
return nil return nil
} }
@@ -203,6 +254,9 @@ func (context *AptlyContext) CloseDatabase() error {
// ReOpenDatabase reopens the db after close // ReOpenDatabase reopens the db after close
func (context *AptlyContext) ReOpenDatabase() error { func (context *AptlyContext) ReOpenDatabase() error {
context.Lock()
defer context.Unlock()
if context.database == nil { if context.database == nil {
return nil return nil
} }
@@ -215,7 +269,7 @@ func (context *AptlyContext) ReOpenDatabase() error {
if err == nil || strings.Index(err.Error(), "resource temporarily unavailable") == -1 { if err == nil || strings.Index(err.Error(), "resource temporarily unavailable") == -1 {
return err return err
} }
context.Progress().Printf("Unable to reopen database, sleeping %s\n", Delay) context._progress().Printf("Unable to reopen database, sleeping %s\n", Delay)
<-time.After(Delay) <-time.After(Delay)
} }
@@ -224,8 +278,11 @@ func (context *AptlyContext) ReOpenDatabase() error {
// CollectionFactory builds factory producing all kinds of collections // CollectionFactory builds factory producing all kinds of collections
func (context *AptlyContext) CollectionFactory() *deb.CollectionFactory { func (context *AptlyContext) CollectionFactory() *deb.CollectionFactory {
context.Lock()
defer context.Unlock()
if context.collectionFactory == nil { if context.collectionFactory == nil {
db, err := context.Database() db, err := context._database()
if err != nil { if err != nil {
Fatal(err) Fatal(err)
} }
@@ -237,8 +294,11 @@ func (context *AptlyContext) CollectionFactory() *deb.CollectionFactory {
// PackagePool returns instance of PackagePool // PackagePool returns instance of PackagePool
func (context *AptlyContext) PackagePool() aptly.PackagePool { func (context *AptlyContext) PackagePool() aptly.PackagePool {
context.Lock()
defer context.Unlock()
if context.packagePool == nil { if context.packagePool == nil {
context.packagePool = files.NewPackagePool(context.Config().RootDir) context.packagePool = files.NewPackagePool(context.config().RootDir)
} }
return context.packagePool return context.packagePool
@@ -246,12 +306,15 @@ func (context *AptlyContext) PackagePool() aptly.PackagePool {
// GetPublishedStorage returns instance of PublishedStorage // GetPublishedStorage returns instance of PublishedStorage
func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedStorage { func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedStorage {
context.Lock()
defer context.Unlock()
publishedStorage, ok := context.publishedStorages[name] publishedStorage, ok := context.publishedStorages[name]
if !ok { if !ok {
if name == "" { if name == "" {
publishedStorage = files.NewPublishedStorage(context.Config().RootDir) publishedStorage = files.NewPublishedStorage(context.config().RootDir)
} else if strings.HasPrefix(name, "s3:") { } else if strings.HasPrefix(name, "s3:") {
params, ok := context.Config().S3PublishRoots[name[3:]] params, ok := context.config().S3PublishRoots[name[3:]]
if !ok { if !ok {
Fatal(fmt.Errorf("published S3 storage %v not configured", name[3:])) Fatal(fmt.Errorf("published S3 storage %v not configured", name[3:]))
} }
@@ -279,21 +342,33 @@ func (context *AptlyContext) UploadPath() string {
// UpdateFlags sets internal copy of flags in the context // UpdateFlags sets internal copy of flags in the context
func (context *AptlyContext) UpdateFlags(flags *flag.FlagSet) { func (context *AptlyContext) UpdateFlags(flags *flag.FlagSet) {
context.Lock()
defer context.Unlock()
context.flags = flags context.flags = flags
} }
// Flags returns current command flags // Flags returns current command flags
func (context *AptlyContext) Flags() *flag.FlagSet { func (context *AptlyContext) Flags() *flag.FlagSet {
context.Lock()
defer context.Unlock()
return context.flags return context.flags
} }
// GlobalFlags returns flags passed to all commands // GlobalFlags returns flags passed to all commands
func (context *AptlyContext) GlobalFlags() *flag.FlagSet { func (context *AptlyContext) GlobalFlags() *flag.FlagSet {
context.Lock()
defer context.Unlock()
return context.globalFlags return context.globalFlags
} }
// Shutdown shuts context down // Shutdown shuts context down
func (context *AptlyContext) Shutdown() { func (context *AptlyContext) Shutdown() {
context.Lock()
defer context.Unlock()
if aptly.EnableDebug { if aptly.EnableDebug {
if context.fileMemProfile != nil { if context.fileMemProfile != nil {
pprof.WriteHeapProfile(context.fileMemProfile) pprof.WriteHeapProfile(context.fileMemProfile)
@@ -326,6 +401,9 @@ func (context *AptlyContext) Shutdown() {
// Cleanup does partial shutdown of context // Cleanup does partial shutdown of context
func (context *AptlyContext) Cleanup() { func (context *AptlyContext) Cleanup() {
context.Lock()
defer context.Unlock()
if context.downloader != nil { if context.downloader != nil {
context.downloader.Shutdown() context.downloader.Shutdown()
context.downloader = nil context.downloader = nil