Skip to content

Commit

Permalink
Merge ef3e686 into 0a6c0b7
Browse files Browse the repository at this point in the history
  • Loading branch information
rgooch authored Jun 25, 2019
2 parents 0a6c0b7 + ef3e686 commit c29a1f2
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
1 change: 1 addition & 0 deletions fleetmanager/hypervisors/fsstorer/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ func (s *Storer) writeVm(hypervisor net.IP, ipAddr string,
defer writer.Close()
encoder := gob.NewEncoder(writer)
if err := encoder.Encode(vmInfo); err != nil {
writer.Abort()
return err
}
return writer.Close()
Expand Down
4 changes: 2 additions & 2 deletions fleetmanager/hypervisors/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ func (m *Manager) manageHypervisorLoop(h *hypervisorType, hostname string) {
for _, vmIpAddr := range vmList {
pVmInfo, err := m.storer.ReadVm(h.machine.HostIpAddress, vmIpAddr)
if err != nil {
h.logger.Printf("error reading VM: %s, not managing hypervisor: %s",
vmIpAddr, err)
h.logger.Printf("error reading VM: %s: %s", vmIpAddr, err)
continue
}
vmInfo := &vmInfoType{vmIpAddr, *pVmInfo, h}
h.vms[vmIpAddr] = vmInfo
Expand Down
14 changes: 14 additions & 0 deletions lib/fsutil/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,17 +200,31 @@ func (w *ChecksumWriter) WriteChecksum() error {
return w.writeChecksum()
}

// RenamingWriter is similar to a writable os.File, except that it attempts to
// ensure data integrity. A temporary file is used for writing, which is
// renamed during the Close method and an fsync(2) is attempted.
type RenamingWriter struct {
*os.File
filename string
abort bool
}

// CreateRenamingWriter will create a temporary file for writing and will rename
// the temporary file to filename in the Close method if there are no write
// errors.
func CreateRenamingWriter(filename string, perm os.FileMode) (
*RenamingWriter, error) {
return createRenamingWriter(filename, perm)
}

// Abort will prevent file renaming during a subsequent Close method call.
func (w *RenamingWriter) Abort() {
w.abort = true
}

// Close may attempt to fsync(2) the contents of the temporary file (if fsync(2)
// has not been called recently) and will then close and rename the temporary
// file if there were no Write errors or a call to the Abort method.
func (w *RenamingWriter) Close() error {
if err := recover(); err != nil {
w.abort = true
Expand Down
27 changes: 27 additions & 0 deletions lib/fsutil/renamingWriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package fsutil

import (
"os"
"time"
)

var fsyncSemaphore = make(chan struct{}, 1)

func createRenamingWriter(filename string, perm os.FileMode) (
*RenamingWriter, error) {
writer := &RenamingWriter{filename: filename}
Expand All @@ -17,9 +20,33 @@ func createRenamingWriter(filename string, perm os.FileMode) (
return writer, nil
}

// fsyncFile will call file.Sync if it has not been called recently. This
// attempts to reduce the performance problems of fsync(2) by potentially
// sacrificing some file-system consistency.
func fsyncFile(file *os.File) error {
select {
case fsyncSemaphore <- struct{}{}:
default:
return nil
}
startTime := time.Now()
err := file.Sync()
duration := time.Since(startTime)
go func() {
time.Sleep(duration)
<-fsyncSemaphore
}()
return err
}

func (w *RenamingWriter) close() error {
tmpFilename := w.filename + "~"
defer os.Remove(tmpFilename)
if !w.abort {
if err := fsyncFile(w.File); err != nil {
return err
}
}
if err := w.File.Close(); err != nil {
return err
}
Expand Down

0 comments on commit c29a1f2

Please sign in to comment.