mirror of
https://github.com/mumble-voip/grumble.git
synced 2025-12-19 21:59:59 -08:00
grumble, pkg/freezer: more stable freezing on Windows.
This commit is contained in:
parent
06ba075c41
commit
f953ece6f2
5 changed files with 171 additions and 68 deletions
90
freeze.go
90
freeze.go
|
|
@ -20,69 +20,48 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
// Freeze a server to disk, and re-open the log, if needed.
|
||||
// Freeze a server to disk and closes the log file.
|
||||
// This must be called from within the Server's synchronous handler.
|
||||
func (server *Server) FreezeToFile() (err error) {
|
||||
// Close the log file, if it's open
|
||||
if server.freezelog != nil {
|
||||
err = server.freezelog.Close()
|
||||
func (server *Server) FreezeToFile() error {
|
||||
// See freeeze_{windows,unix}.go for real implementations.
|
||||
err := server.freezeToFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if server.running {
|
||||
// Re-open the freeze log.
|
||||
err = server.openFreezeLog()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the whole server is synced to disk
|
||||
fs, err := server.Freeze()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := ioutil.TempFile(filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10)), ".main.fz_")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, err := proto.Marshal(fs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Sync()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Rename(f.Name(), filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "main.fz"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-open a new log file
|
||||
err = server.openFreezeLog()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Open a new freeze log
|
||||
func (server *Server) openFreezeLog() (err error) {
|
||||
// Open a new freeze log.
|
||||
func (server *Server) openFreezeLog() error {
|
||||
if server.freezelog != nil {
|
||||
err := server.freezelog.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logfn := filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "log.fz")
|
||||
err = os.Remove(logfn)
|
||||
err := os.Remove(logfn)
|
||||
if os.IsNotExist(err) {
|
||||
// OK. File does not exist...
|
||||
// fallthrough
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server.freezelog, err = freezer.NewLogFile(logfn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -406,10 +385,20 @@ func NewServerFromFrozen(name string) (s *Server, err error) {
|
|||
|
||||
path := filepath.Join(Args.DataDir, "servers", name)
|
||||
mainFile := filepath.Join(path, "main.fz")
|
||||
logFile := filepath.Join(path, "log.fz")
|
||||
backupFile := filepath.Join(path, "backup.fz")
|
||||
logFn := filepath.Join(path, "log.fz")
|
||||
|
||||
r, err := os.Open(mainFile)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
err = os.Rename(backupFile, mainFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err = os.Open(mainFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Close()
|
||||
|
|
@ -504,7 +493,8 @@ func NewServerFromFrozen(name string) (s *Server, err error) {
|
|||
}
|
||||
|
||||
// Attempt to walk the stored log file
|
||||
walker, err := freezer.NewFileWalker(logFile)
|
||||
logFile, err := os.Open(logFn)
|
||||
walker, err := freezer.NewReaderWalker(logFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -512,6 +502,10 @@ func NewServerFromFrozen(name string) (s *Server, err error) {
|
|||
for {
|
||||
values, err := walker.Next()
|
||||
if err == io.EOF {
|
||||
err = logFile.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
49
freeze_unix.go
Normal file
49
freeze_unix.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright (c) 2012 The Grumble Authors
|
||||
// The use of this source code is goverened by a BSD-style
|
||||
// license that can be found in the LICENSE-file.
|
||||
|
||||
// +build !windows
|
||||
|
||||
package main
|
||||
|
||||
func (server *Server) freezeToFile() (err error) {
|
||||
// Close the log file, if it's open
|
||||
if server.freezelog != nil {
|
||||
err = server.freezelog.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the whole server is synced to disk
|
||||
fs, err := server.Freeze()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := ioutil.TempFile(filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10)), ".main.fz_")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, err := proto.Marshal(fs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Sync()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Rename(f.Name(), filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "main.fz"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
59
freeze_windows.go
Normal file
59
freeze_windows.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) 2012 The Grumble Authors
|
||||
// The use of this source code is goverened by a BSD-style
|
||||
// license that can be found in the LICENSE-file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"code.google.com/p/goprotobuf/proto"
|
||||
"mumbleapp.com/grumble/pkg/replacefile"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (server *Server) freezeToFile() (err error) {
|
||||
// Close the log file, if it's open
|
||||
if server.freezelog != nil {
|
||||
err = server.freezelog.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the whole server is synced to disk
|
||||
fs, err := server.Freeze()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := ioutil.TempFile(filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10)), ".main.fz_")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, err := proto.Marshal(fs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = f.Write(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Sync()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
src := f.Name()
|
||||
dst := filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "main.fz")
|
||||
backup := filepath.Join(Args.DataDir, "servers", strconv.FormatInt(server.Id, 10), "backup.fz")
|
||||
err = replacefile.ReplaceFile(dst, src, backup, replacefile.Flag(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
var testValues []interface{} = []interface{}{
|
||||
var testValues []proto.Message = []proto.Message{
|
||||
&ConfigKeyValuePair{Key: proto.String("Foo")},
|
||||
&BanList{Bans: []*Ban{&Ban{Mask: proto.Uint32(32)}}},
|
||||
&User{Id: proto.Uint32(0), Name: proto.String("SuperUser")},
|
||||
|
|
@ -97,18 +97,26 @@ func TestLogging(t *testing.T) {
|
|||
t.Error(err)
|
||||
return
|
||||
}
|
||||
defer l.Close()
|
||||
defer os.Remove("logging.log")
|
||||
|
||||
for _, val := range testValues {
|
||||
err = l.Put(val)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
walker, err := NewFileWalker("logging.log")
|
||||
err = l.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Open("logging.log")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
walker, err := NewReaderWalker(f)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
|
|
@ -118,6 +126,10 @@ func TestLogging(t *testing.T) {
|
|||
for {
|
||||
entries, err := walker.Next()
|
||||
if err == io.EOF {
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
break
|
||||
} else if err != nil {
|
||||
t.Error(err)
|
||||
|
|
@ -127,7 +139,10 @@ func TestLogging(t *testing.T) {
|
|||
t.Error("> 1 entry in log tx")
|
||||
return
|
||||
}
|
||||
val := entries[0]
|
||||
val, ok := entries[0].(proto.Message)
|
||||
if !ok {
|
||||
t.Fatal("val does not implement proto.Message")
|
||||
}
|
||||
if !proto.Equal(val, testValues[i]) {
|
||||
t.Error("proto message mismatch")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
"hash/crc32"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Checks whether the error err is an EOF
|
||||
|
|
@ -79,19 +78,6 @@ func (txr *txReader) Consumed() int {
|
|||
return txr.consumed
|
||||
}
|
||||
|
||||
// Create a new Walker that iterates over the entries of the given log file.
|
||||
func NewFileWalker(fn string) (walker *Walker, err error) {
|
||||
f, err := os.Open(fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
walker = new(Walker)
|
||||
walker.r = f
|
||||
|
||||
return walker, nil
|
||||
}
|
||||
|
||||
// Create a new Walker that iterates over the log entries of a given Reader.
|
||||
func NewReaderWalker(r io.Reader) (walker *Walker, err error) {
|
||||
walker = new(Walker)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue