From fbf81bafe0d59061a79cd7bb95305c3ee9b1f70f Mon Sep 17 00:00:00 2001 From: Mikkel Krautz Date: Tue, 17 May 2011 20:23:28 +0200 Subject: [PATCH] Fix server freezing on Windows. --- freeze.go | 25 ++++++++++++++++++++++++- grumble.go | 15 +++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/freeze.go b/freeze.go index 596765e..b2909ce 100644 --- a/freeze.go +++ b/freeze.go @@ -13,6 +13,7 @@ import ( "io" "io/ioutil" "os" + "runtime" ) type frozenServer struct { @@ -64,7 +65,7 @@ type frozenGroup struct { Remove []int "remove" } -// Freeze a server and write it to a file +// Freeze a server and write it to a file. func (server *Server) FreezeToFile(filename string) (err os.Error) { r := server.FreezeServer() if err != nil { @@ -90,6 +91,28 @@ func (server *Server) FreezeToFile(filename string) (err os.Error) { if err != nil { return err } + // Temporary non-atomic path + // We should probably use MoveFileEx instead, but I'm + // not sure whether that's atomic either. MoveFileTransacted + // would be prefered for Vista/Server 2008+. + if runtime.GOOS == "windows" { + err = os.Remove(filename + ".old") + if e, ok := err.(*os.PathError); ok { + if e.Error != os.ENOENT { + return err + } + } else if err != nil { + return err + } + err = os.Rename(filename, filename + ".old") + if e, ok := err.(*os.LinkError); ok { + if e.Error != os.ENOENT { + return err + } + } else if err != nil { + return err + } + } err = os.Rename(f.Name(), filename) if err != nil { return err diff --git a/grumble.go b/grumble.go index 339dbf3..10f0b12 100644 --- a/grumble.go +++ b/grumble.go @@ -16,6 +16,7 @@ import ( "regexp" "rpc" "runtime" + "strconv" "time" ) @@ -206,6 +207,20 @@ func main() { servers[s.Id] = s go s.ListenAndMurmur() } + // win32 special-case + if matched, _ := regexp.MatchString("^[0-9]+.old$", name); matched { + sid, _ := strconv.Atoi64(name[0:len(name)-4]) + _, exists := servers[sid] + if !exists { + log.Printf("Recovering lost server %v", name) + s, err := NewServerFromFrozen(filepath.Join(*datadir, name)) + if err != nil { + log.Fatalf("Unable to recover server: %S", err.String()) + } + servers[sid] = s + go s.ListenAndMurmur() + } + } } if len(servers) == 0 {