...

Source file src/go.etcd.io/etcd/client/pkg/v3/fileutil/purge.go

Documentation: go.etcd.io/etcd/client/pkg/v3/fileutil

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fileutil
    16  
    17  import (
    18  	"os"
    19  	"path/filepath"
    20  	"sort"
    21  	"strings"
    22  	"time"
    23  
    24  	"go.uber.org/zap"
    25  )
    26  
    27  func PurgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) <-chan error {
    28  	return purgeFile(lg, dirname, suffix, max, interval, stop, nil, nil, true)
    29  }
    30  
    31  func PurgeFileWithDoneNotify(lg *zap.Logger, dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) (<-chan struct{}, <-chan error) {
    32  	doneC := make(chan struct{})
    33  	errC := purgeFile(lg, dirname, suffix, max, interval, stop, nil, doneC, true)
    34  	return doneC, errC
    35  }
    36  
    37  func PurgeFileWithoutFlock(lg *zap.Logger, dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}) (<-chan struct{}, <-chan error) {
    38  	doneC := make(chan struct{})
    39  	errC := purgeFile(lg, dirname, suffix, max, interval, stop, nil, doneC, false)
    40  	return doneC, errC
    41  }
    42  
    43  // purgeFile is the internal implementation for PurgeFile which can post purged files to purgec if non-nil.
    44  // if donec is non-nil, the function closes it to notify its exit.
    45  func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval time.Duration, stop <-chan struct{}, purgec chan<- string, donec chan<- struct{}, flock bool) <-chan error {
    46  	if lg == nil {
    47  		lg = zap.NewNop()
    48  	}
    49  	errC := make(chan error, 1)
    50  	lg.Info("started to purge file",
    51  		zap.String("dir", dirname),
    52  		zap.String("suffix", suffix),
    53  		zap.Uint("max", max),
    54  		zap.Duration("interval", interval))
    55  
    56  	go func() {
    57  		if donec != nil {
    58  			defer close(donec)
    59  		}
    60  		for {
    61  			fnames, err := ReadDir(dirname)
    62  			if err != nil {
    63  				errC <- err
    64  				return
    65  			}
    66  			newfnames := make([]string, 0)
    67  			for _, fname := range fnames {
    68  				if strings.HasSuffix(fname, suffix) {
    69  					newfnames = append(newfnames, fname)
    70  				}
    71  			}
    72  			sort.Strings(newfnames)
    73  			fnames = newfnames
    74  			for len(newfnames) > int(max) {
    75  				f := filepath.Join(dirname, newfnames[0])
    76  				var l *LockedFile
    77  				if flock {
    78  					l, err = TryLockFile(f, os.O_WRONLY, PrivateFileMode)
    79  					if err != nil {
    80  						lg.Warn("failed to lock file", zap.String("path", f), zap.Error(err))
    81  						break
    82  					}
    83  				}
    84  				if err = os.Remove(f); err != nil {
    85  					lg.Error("failed to remove file", zap.String("path", f), zap.Error(err))
    86  					errC <- err
    87  					return
    88  				}
    89  				if flock {
    90  					if err = l.Close(); err != nil {
    91  						lg.Error("failed to unlock/close", zap.String("path", l.Name()), zap.Error(err))
    92  						errC <- err
    93  						return
    94  					}
    95  				}
    96  				lg.Info("purged", zap.String("path", f))
    97  				newfnames = newfnames[1:]
    98  			}
    99  			if purgec != nil {
   100  				for i := 0; i < len(fnames)-len(newfnames); i++ {
   101  					purgec <- fnames[i]
   102  				}
   103  			}
   104  			select {
   105  			case <-time.After(interval):
   106  			case <-stop:
   107  				return
   108  			}
   109  		}
   110  	}()
   111  	return errC
   112  }
   113  

View as plain text