github.com/Cloud-Foundations/Dominator@v0.3.4/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 }