Skip to content

Commit

Permalink
log: don't sort all the old file, only remove one file once
Browse files Browse the repository at this point in the history
  • Loading branch information
zlacfzy committed Jan 29, 2024
1 parent 29f2ba0 commit 3fd5f12
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 89 deletions.
91 changes: 9 additions & 82 deletions log/async_file_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@ package log
import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"sync/atomic"
"time"
Expand Down Expand Up @@ -235,92 +232,22 @@ func (w *AsyncFileWriter) timeFilePath(filePath string) string {
return filePath + "." + time.Now().Format(backupTimeFormat)
}

func (w *AsyncFileWriter) dir() string {
return filepath.Dir(w.filePath)
}

// oldLogFiles returns the list of backup log files stored in the same
// directory as the current log file, sorted by ModTime
func (w *AsyncFileWriter) oldLogFiles() ([]logInfo, error) {
files, err := os.ReadDir(w.dir())
if err != nil {
return nil, fmt.Errorf("can't read log file directory: %s", err)
}
logFiles := []logInfo{}

prefix := filepath.Base(w.filePath)

for _, f := range files {
if f.IsDir() {
continue
}
k := f.Name()
if t, err := w.timeFromName(k, prefix); err == nil {
logFiles = append(logFiles, logInfo{t, f})
}
}

sort.Sort(byFormatTime(logFiles))

return logFiles, nil
}

// logInfo is a convenience struct to return the filename and its embedded
// timestamp.
type logInfo struct {
timestamp time.Time
fs.DirEntry
}

// byFormatTime sorts by newest time formatted in the name.
type byFormatTime []logInfo

func (b byFormatTime) Less(i, j int) bool {
return b[i].timestamp.After(b[j].timestamp)
}

func (b byFormatTime) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}

func (b byFormatTime) Len() int {
return len(b)
}

func (w *AsyncFileWriter) timeFromName(filename, prefix string) (time.Time, error) {
if !strings.HasPrefix(filename, prefix) || len(filename) == len(prefix) {
return time.Time{}, errors.New("mismatched prefix")
}
ts := filename[len(prefix)+1:]
a, _ := time.Parse(backupTimeFormat, ts)
return a, nil
func (w *AsyncFileWriter) oldFile(filePath string, maxBackups int) string {
return filePath + "." + time.Now().Add(-time.Hour*time.Duration(maxBackups)).Format(backupTimeFormat)
}

func (w *AsyncFileWriter) clearBackups() error {
if w.maxBackups == 0 {
return nil
}
files, err := w.oldLogFiles()
if err != nil {
return err
}
var remove []logInfo
if w.maxBackups > 0 && w.maxBackups < len(files) {
preserved := make(map[string]bool)
for _, f := range files {
fn := f.Name()
preserved[fn] = true

if len(preserved) > w.maxBackups {
remove = append(remove, f)
}
}
oldFilepath := w.oldFile(w.filePath, w.maxBackups)
_, err := os.Stat(oldFilepath)
if os.IsNotExist(err) {
return nil
}
for _, f := range remove {
errRemove := os.Remove(filepath.Join(w.dir(), f.Name()))
if err == nil && errRemove != nil {
err = errRemove
}
errRemove := os.Remove(oldFilepath)
if err != nil {
return errRemove
}
return err
}
11 changes: 4 additions & 7 deletions log/async_file_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package log

import (
"os"
"path/filepath"
"strconv"
"strings"
"testing"
Expand Down Expand Up @@ -82,12 +81,10 @@ func TestClearBackups(t *testing.T) {
for i := 0; i < 5; i++ {
name = w.filePath + "." + fakeCurrentTime.Format(backupTimeFormat)
_ = os.WriteFile(name, data, 0700)
fakeCurrentTime = fakeCurrentTime.Add(time.Hour * 1)
fakeCurrentTime = fakeCurrentTime.Add(-time.Hour * 1)
}
oldFiles, _ := w.oldLogFiles()
assert.True(t, len(oldFiles) == 5)
oldFile := w.oldFile(w.filePath, w.maxBackups)
w.clearBackups()
remainFiles, _ := w.oldLogFiles()
assert.True(t, len(remainFiles) == 1)
assert.Equal(t, remainFiles[0].Name(), filepath.Base(name))
_, err := os.Stat(oldFile)
assert.True(t, os.IsNotExist(err))
}

0 comments on commit 3fd5f12

Please sign in to comment.