diff --git a/cmd/micro/micro.go b/cmd/micro/micro.go index 70b940bf..775301ee 100644 --- a/cmd/micro/micro.go +++ b/cmd/micro/micro.go @@ -489,8 +489,6 @@ func DoEvent() { } case f := <-timerChan: f() - case b := <-buffer.BackupCompleteChan: - b.RequestedBackup = false case <-sighup: exit(0) case <-util.Sigterm: diff --git a/internal/buffer/backup.go b/internal/buffer/backup.go index 941ac04f..8b728ec6 100644 --- a/internal/buffer/backup.go +++ b/internal/buffer/backup.go @@ -34,20 +34,49 @@ Options: [r]ecover, [i]gnore, [a]bort: ` const backupSeconds = 8 -var BackupCompleteChan chan *SharedBuffer +type backupRequestType int + +const ( + backupCreate = iota + backupRemove +) + +type backupRequest struct { + buf *SharedBuffer + reqType backupRequestType +} + +var requestedBackups map[*SharedBuffer]bool func init() { - BackupCompleteChan = make(chan *SharedBuffer, 10) + requestedBackups = make(map[*SharedBuffer]bool) } func (b *SharedBuffer) RequestBackup() { - if !b.RequestedBackup { - select { - case backupRequestChan <- b: - default: - // channel is full + backupRequestChan <- backupRequest{buf: b, reqType: backupCreate} +} + +func (b *SharedBuffer) CancelBackup() { + backupRequestChan <- backupRequest{buf: b, reqType: backupRemove} +} + +func handleBackupRequest(br backupRequest) { + switch br.reqType { + case backupCreate: + // schedule periodic backup + requestedBackups[br.buf] = true + case backupRemove: + br.buf.RemoveBackup() + delete(requestedBackups, br.buf) + } +} + +func periodicBackup() { + for buf := range requestedBackups { + err := buf.Backup() + if err == nil { + delete(requestedBackups, buf) } - b.RequestedBackup = true } } @@ -77,9 +106,6 @@ func (b *SharedBuffer) Backup() error { name := util.DetermineEscapePath(backupdir, b.AbsPath) if _, err := os.Stat(name); errors.Is(err, fs.ErrNotExist) { _, err = b.overwriteFile(name) - if err == nil { - BackupCompleteChan <- b - } return err } @@ -95,8 +121,6 @@ func (b *SharedBuffer) Backup() error { return err } - BackupCompleteChan <- b - return err } diff --git a/internal/buffer/buffer.go b/internal/buffer/buffer.go index 9bd7ecfa..bc33abfd 100644 --- a/internal/buffer/buffer.go +++ b/internal/buffer/buffer.go @@ -13,7 +13,6 @@ import ( "strconv" "strings" "sync" - "sync/atomic" "time" luar "layeh.com/gopher-luar" @@ -101,7 +100,6 @@ type SharedBuffer struct { diffLock sync.RWMutex diff map[int]DiffStatus - RequestedBackup bool forceKeepBackup bool // ReloadDisabled allows the user to disable reloads if they @@ -123,8 +121,6 @@ type SharedBuffer struct { // Hash of the original buffer -- empty if fastdirty is on origHash [md5.Size]byte - - fini int32 } func (b *SharedBuffer) insert(pos Loc, value []byte) { @@ -495,13 +491,11 @@ func (b *Buffer) Fini() { if !b.Modified() { b.Serialize() } - b.RemoveBackup() + b.CancelBackup() if b.Type == BTStdout { fmt.Fprint(util.Stdout, string(b.Bytes())) } - - atomic.StoreInt32(&(b.fini), int32(1)) } // GetName returns the name that should be displayed in the statusline diff --git a/internal/buffer/save.go b/internal/buffer/save.go index aaab39ba..d2cd3533 100644 --- a/internal/buffer/save.go +++ b/internal/buffer/save.go @@ -11,7 +11,6 @@ import ( "os/signal" "path/filepath" "runtime" - "sync/atomic" "time" "unicode" @@ -47,11 +46,14 @@ type saveRequest struct { } var saveRequestChan chan saveRequest -var backupRequestChan chan *SharedBuffer +var backupRequestChan chan backupRequest func init() { - saveRequestChan = make(chan saveRequest, 10) - backupRequestChan = make(chan *SharedBuffer, 10) + // Both saveRequestChan and backupRequestChan need to be non-buffered + // so the save/backup goroutine receives both save and backup requests + // in the same order the main goroutine sends them. + saveRequestChan = make(chan saveRequest) + backupRequestChan = make(chan backupRequest) go func() { duration := backupSeconds * float64(time.Second) @@ -62,14 +64,10 @@ func init() { case sr := <-saveRequestChan: size, err := sr.buf.safeWrite(sr.path, sr.withSudo, sr.newFile) sr.saveResponseChan <- saveResponse{size, err} + case br := <-backupRequestChan: + handleBackupRequest(br) case <-backupTicker.C: - for len(backupRequestChan) > 0 { - b := <-backupRequestChan - bfini := atomic.LoadInt32(&(b.fini)) != 0 - if !bfini { - b.Backup() - } - } + periodicBackup() } } }() @@ -380,6 +378,9 @@ func (b *SharedBuffer) safeWrite(path string, withSudo bool, newFile bool) (int, return 0, err } + // Backup saved, so cancel pending periodic backup, if any + delete(requestedBackups, b) + b.forceKeepBackup = true size := 0 {