X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/baf7a940be8927278e3b4b87e7366cebfc16532f..80e348724041a694002fc38f57e8868b9b9a2be9:/syncer.go?ds=inline diff --git a/syncer.go b/syncer.go index 1549461..0784393 100644 --- a/syncer.go +++ b/syncer.go @@ -10,22 +10,6 @@ import ( "golang.org/x/sys/unix" ) -// openSyncer returns the syncer of the file system that holds dir. It syncs -// with syncfs, which writes back only that file system. -func openSyncer(dir string) (*Syncer, error) { - file, err := os.Open(dir) - if err != nil { - return nil, fmt.Errorf("open chat directory: %w", err) - } - - s := newSyncer(func() error { - return unix.Syncfs(int(file.Fd())) - }) - s.file = file - - return s, nil -} - // Syncer makes the writes of a chat durable by group commit. Each write goes to // the operating system at once, so a crash of the process loses nothing. After // each write, Written starts a background sync of the file system of the chat, @@ -48,6 +32,30 @@ type Syncer struct { workers sync.WaitGroup } +// openSyncer returns the syncer of the file system that holds dir. It syncs +// with syncfs, which writes back only that file system. +func openSyncer(dir string) (*Syncer, error) { + file, err := os.Open(dir) + if err != nil { + return nil, fmt.Errorf("open chat directory: %w", err) + } + + s := newSyncer(func() error { + return unix.Syncfs(int(file.Fd())) + }) + s.file = file + + return s, nil +} + +// newSyncer returns a syncer that makes the writes durable with sync. +func newSyncer(sync func() error) *Syncer { + return &Syncer{ + sync: sync, + done: make(chan struct{}), + } +} + // Written tells the syncer that a write went to the operating system, and // starts a sync when none runs. func (s *Syncer) Written() { @@ -61,11 +69,13 @@ func (s *Syncer) Written() { // Flush returns when every write before the call is durable. func (s *Syncer) Flush(ctx context.Context) error { s.mutex.Lock() + target := s.written s.mutex.Unlock() for { s.mutex.Lock() + reached := s.durable >= target failure := s.failure done := s.done @@ -92,6 +102,7 @@ func (s *Syncer) Flush(ctx context.Context) error { func (s *Syncer) Close() error { err := s.Flush(context.Background()) s.workers.Wait() + if s.file != nil { err = errors.Join(err, s.file.Close()) s.file = nil @@ -109,6 +120,7 @@ func (s *Syncer) start() { s.running = true s.workers.Add(1) + go s.run(s.written) } @@ -130,14 +142,7 @@ func (s *Syncer) run(target uint64) { } close(s.done) + s.done = make(chan struct{}) s.start() } - -// newSyncer returns a syncer that makes the writes durable with sync. -func newSyncer(sync func() error) *Syncer { - return &Syncer{ - sync: sync, - done: make(chan struct{}), - } -}