github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/log/log_gc.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package log
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"math"
    17  	"os"
    18  	"path/filepath"
    19  	"sync/atomic"
    20  )
    21  
    22  func init() {
    23  	mainLog.gcNotify = make(chan struct{}, 1)
    24  }
    25  
    26  // StartGCDaemon starts the log file GC -- this must be called after
    27  // command-line parsing has completed so that no data is lost when the
    28  // user configures larger max sizes than the defaults.
    29  //
    30  // The logger's GC daemon stops when the provided context is canceled.
    31  //
    32  // Note that secondary logger get their GC daemon started when
    33  // they are allocated (NewSecondaryLogger). This assumes that
    34  // secondary loggers are only allocated after command line parsing
    35  // has completed too.
    36  func StartGCDaemon(ctx context.Context) {
    37  	go mainLog.gcDaemon(ctx)
    38  }
    39  
    40  // gcDaemon runs the GC loop for the given logger.
    41  func (l *loggerT) gcDaemon(ctx context.Context) {
    42  	l.gcOldFiles()
    43  	for {
    44  		select {
    45  		case <-ctx.Done():
    46  			return
    47  		case <-l.gcNotify:
    48  		}
    49  
    50  		logging.mu.Lock()
    51  		doGC := !logging.mu.disableDaemons
    52  		logging.mu.Unlock()
    53  
    54  		if doGC {
    55  			l.gcOldFiles()
    56  		}
    57  	}
    58  }
    59  
    60  // gcOldFiles removes the "old" files that do not match
    61  // the configured size and number threshold.
    62  func (l *loggerT) gcOldFiles() {
    63  	dir, isSet := l.logDir.get()
    64  	if !isSet {
    65  		// No log directory configured. Nothing to do.
    66  		return
    67  	}
    68  
    69  	// This only lists the log files for the current logger (sharing the
    70  	// prefix).
    71  	allFiles, err := l.listLogFiles()
    72  	if err != nil {
    73  		fmt.Fprintf(OrigStderr, "unable to GC log files: %s\n", err)
    74  		return
    75  	}
    76  
    77  	logFilesCombinedMaxSize := atomic.LoadInt64(&LogFilesCombinedMaxSize)
    78  	files := selectFiles(allFiles, math.MaxInt64)
    79  	if len(files) == 0 {
    80  		return
    81  	}
    82  	// files is sorted with the newest log files first (which we want
    83  	// to keep). Note that we always keep the most recent log file.
    84  	sum := files[0].SizeBytes
    85  	for _, f := range files[1:] {
    86  		sum += f.SizeBytes
    87  		if sum < logFilesCombinedMaxSize {
    88  			continue
    89  		}
    90  		path := filepath.Join(dir, f.Name)
    91  		if err := os.Remove(path); err != nil {
    92  			fmt.Fprintln(OrigStderr, err)
    93  		}
    94  	}
    95  }