From ca8feb385c9bf1ad4bf884a0b8a4defd9e707a0b Mon Sep 17 00:00:00 2001 From: Dan Willemsen Date: Wed, 18 Oct 2017 13:18:41 -0700 Subject: [PATCH 1/2] Synchronize file rotation Create a lock file during log rotation so that multiple processes won't step on each other. Test: Run `while true; do get_build_var TARGET_PRODUCT; done` in parallel Test: m blueprint_tools Change-Id: I7144cd42aca47c694487ddae44713f82665ed81e --- ui/logger/logger.go | 16 +++++++++++++--- ui/logger/logger_test.go | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ui/logger/logger.go b/ui/logger/logger.go index 7d9687bec..15c413dd5 100644 --- a/ui/logger/logger.go +++ b/ui/logger/logger.go @@ -38,6 +38,7 @@ import ( "path/filepath" "strconv" "sync" + "syscall" ) type Logger interface { @@ -93,10 +94,19 @@ func fileRotation(from, baseName, ext string, cur, max int) error { // existing files to .#., keeping up to maxCount files. // .1. is the most recent backup, .2. is the // second most recent backup, etc. -// -// TODO: This function is not guaranteed to be atomic, if there are multiple -// users attempting to do the same operation, the result is undefined. func CreateFileWithRotation(filename string, maxCount int) (*os.File, error) { + lockFileName := filepath.Join(filepath.Dir(filename), ".lock_"+filepath.Base(filename)) + lockFile, err := os.OpenFile(lockFileName, os.O_RDWR|os.O_CREATE, 0666) + if err != nil { + return nil, err + } + defer lockFile.Close() + + err = syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX) + if err != nil { + return nil, err + } + if _, err := os.Lstat(filename); err == nil { ext := filepath.Ext(filename) basename := filename[:len(filename)-len(ext)] diff --git a/ui/logger/logger_test.go b/ui/logger/logger_test.go index 0f88ab374..dc6f2e918 100644 --- a/ui/logger/logger_test.go +++ b/ui/logger/logger_test.go @@ -67,7 +67,7 @@ func TestCreateFileWithRotation(t *testing.T) { t.Fatalf("Failed to read dir: %v", err) } sort.Strings(names) - expected := []string{"build.1.log", "build.2.log", "build.3.log", "build.log"} + expected := []string{".lock_build.log", "build.1.log", "build.2.log", "build.3.log", "build.log"} if !reflect.DeepEqual(names, expected) { t.Errorf("File list does not match.") t.Errorf(" got: %v", names) From 69b18ed1678ceceae9805258b5426f8470ec3901 Mon Sep 17 00:00:00 2001 From: Dan Willemsen Date: Wed, 18 Oct 2017 13:25:50 -0700 Subject: [PATCH 2/2] Silence error during microfactory trace import This may happen if there's been another call to microfactory before we've read the log file. Just ignore the error and continue. Test: Run `while true; do get_build_var TARGET_PRODUCT; done` in parallel Change-Id: I670144f4637281ebf1299dbd9151dd9819c363e3 --- ui/tracer/microfactory.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/tracer/microfactory.go b/ui/tracer/microfactory.go index 320d9d8e4..acb9be4c6 100644 --- a/ui/tracer/microfactory.go +++ b/ui/tracer/microfactory.go @@ -28,7 +28,7 @@ func (t *tracerImpl) ImportMicrofactoryLog(filename string) { f, err := os.Open(filename) if err != nil { - t.log.Println("Error opening microfactory trace:", err) + t.log.Verboseln("Error opening microfactory trace:", err) return } defer f.Close()