github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/fsutil/renamingWriter.go (about)

     1  package fsutil
     2  
     3  import (
     4  	"os"
     5  	"time"
     6  )
     7  
     8  var fsyncSemaphore = make(chan struct{}, 1)
     9  
    10  func createRenamingWriter(filename string, perm os.FileMode) (
    11  	*RenamingWriter, error) {
    12  	writer := &RenamingWriter{filename: filename}
    13  	tmpFilename := filename + "~"
    14  	var err error
    15  	writer.File, err = os.OpenFile(tmpFilename,
    16  		os.O_CREATE|os.O_TRUNC|os.O_WRONLY, perm)
    17  	if err != nil {
    18  		return nil, err
    19  	}
    20  	return writer, nil
    21  }
    22  
    23  func fsyncFile(file *os.File) error {
    24  	select {
    25  	case fsyncSemaphore <- struct{}{}:
    26  	default:
    27  		return nil
    28  	}
    29  	startTime := time.Now()
    30  	err := file.Sync()
    31  	duration := time.Since(startTime)
    32  	go func() {
    33  		time.Sleep(duration)
    34  		<-fsyncSemaphore
    35  	}()
    36  	return err
    37  }
    38  
    39  func (w *RenamingWriter) close() error {
    40  	tmpFilename := w.filename + "~"
    41  	defer os.Remove(tmpFilename)
    42  	if !w.abort {
    43  		if err := fsyncFile(w.File); err != nil {
    44  			return err
    45  		}
    46  	}
    47  	if err := w.File.Close(); err != nil {
    48  		return err
    49  	}
    50  	if w.abort {
    51  		return nil
    52  	}
    53  	return os.Rename(tmpFilename, w.filename)
    54  }
    55  
    56  func (w *RenamingWriter) write(p []byte) (int, error) {
    57  	if nWritten, err := w.File.Write(p); err != nil {
    58  		w.abort = true
    59  		return nWritten, err
    60  	} else {
    61  		return nWritten, nil
    62  	}
    63  }