diff --git a/encode.go b/encode.go index de3cf83..f69876a 100644 --- a/encode.go +++ b/encode.go @@ -7,8 +7,7 @@ import ( "fmt" "io" "os" - - "github.com/google/renameio" + "path/filepath" ) // errorEncoder is a helper type to encode multiple values @@ -300,12 +299,22 @@ func LoadSavedGraph[K cmp.Ordered](path string) (*SavedGraph[K], error) { } // Save writes the graph to the file. -func (g *SavedGraph[K]) Save() error { - tmp, err := renameio.TempFile("", g.Path) +// +// The graph is written to a temporary file in the same directory, synced, +// and renamed over Path, so a crash never leaves a partially written graph +// behind. os.CreateTemp and os.Rename are portable; the renameio.TempFile +// this replaces is not built on Windows. +func (g *SavedGraph[K]) Save() (err error) { + tmp, err := os.CreateTemp(filepath.Dir(g.Path), filepath.Base(g.Path)+".tmp*") if err != nil { return err } - defer tmp.Cleanup() + defer func() { + if err != nil { + _ = tmp.Close() + _ = os.Remove(tmp.Name()) + } + }() wr := bufio.NewWriter(tmp) err = g.Export(wr) @@ -318,9 +327,19 @@ func (g *SavedGraph[K]) Save() error { return fmt.Errorf("flushing: %w", err) } - err = tmp.CloseAtomicallyReplace() + err = tmp.Sync() + if err != nil { + return fmt.Errorf("syncing: %w", err) + } + + err = tmp.Close() + if err != nil { + return fmt.Errorf("closing: %w", err) + } + + err = os.Rename(tmp.Name(), g.Path) if err != nil { - return fmt.Errorf("closing atomically: %w", err) + return fmt.Errorf("renaming: %w", err) } return nil diff --git a/go.mod b/go.mod index 9d0d0f6..ed213a9 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/coder/hnsw go 1.21.4 require ( - github.com/google/renameio v1.0.1 github.com/stretchr/testify v1.9.0 ) diff --git a/go.sum b/go.sum index f74eb2b..0bf4cf3 100644 --- a/go.sum +++ b/go.sum @@ -3,8 +3,6 @@ github.com/chewxy/math32 v1.10.1/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUw github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU= -github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=