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
This commit is contained in:
Dan Willemsen 2017-10-18 13:18:41 -07:00
parent 31b59cf604
commit ca8feb385c
2 changed files with 14 additions and 4 deletions

View file

@ -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 <filename>.#.<ext>, keeping up to maxCount files.
// <filename>.1.<ext> is the most recent backup, <filename>.2.<ext> 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)]

View file

@ -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)