@ -4,6 +4,7 @@ import (
"fmt"
"fmt"
"os"
"os"
"path/filepath"
"path/filepath"
"sync"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb"
"github.com/seaweedfs/seaweedfs/weed/pb/volume_server_pb"
@ -17,70 +18,110 @@ const (
)
)
type State struct {
type State struct {
FilePath string
Pb * volume_server_pb . VolumeServerState
filePath string
pb * volume_server_pb . VolumeServerState
mu sync . Mutex
}
}
func NewState ( dir string ) ( * State , error ) {
func NewState ( dir string ) ( * State , error ) {
state := & State {
state := & State {
F ilePath: filepath . Join ( dir , StateFileName ) ,
P b: nil ,
f ilePath: filepath . Join ( dir , StateFileName ) ,
p b: nil ,
}
}
err := state . Load ( )
err := state . Load ( )
return state , err
return state , err
}
}
func NewStateFromProto ( filePath string , state * volume_server_pb . VolumeServerState ) * State {
pb := & volume_server_pb . VolumeServerState { }
proto . Merge ( pb , state )
return & State {
filePath : filePath ,
pb : pb ,
}
}
func ( st * State ) Proto ( ) * volume_server_pb . VolumeServerState {
st . mu . Lock ( )
defer st . mu . Unlock ( )
return st . pb
}
func ( st * State ) Load ( ) error {
func ( st * State ) Load ( ) error {
st . Pb = & volume_server_pb . VolumeServerState { }
st . mu . Lock ( )
defer st . mu . Unlock ( )
st . pb = & volume_server_pb . VolumeServerState { }
if ! util . FileExists ( st . FilePath ) {
glog . V ( 1 ) . Infof ( "No preexisting store state at %s" , st . FilePath )
if ! util . FileExists ( st . f ilePath) {
glog . V ( 1 ) . Infof ( "No preexisting store state at %s" , st . f ilePath)
return nil
return nil
}
}
binPb , err := os . ReadFile ( st . FilePath )
binPb , err := os . ReadFile ( st . f ilePath)
if err != nil {
if err != nil {
st . Pb = nil
return fmt . Errorf ( "failed to read store state from %s : %v" , st . FilePath , err )
st . p b = nil
return fmt . Errorf ( "failed to read store state from %s : %v" , st . f ilePath, err )
}
}
if err := proto . Unmarshal ( binPb , st . Pb ) ; err != nil {
st . Pb = nil
return fmt . Errorf ( "failed to parse store state from %s : %v" , st . FilePath , err )
if err := proto . Unmarshal ( binPb , st . p b) ; err != nil {
st . p b = nil
return fmt . Errorf ( "failed to parse store state from %s : %v" , st . f ilePath, err )
}
}
glog . V ( 1 ) . Infof ( "Got store state from %s: %v" , st . F ilePath, st . P b)
glog . V ( 1 ) . Infof ( "Got store state from %s: %v" , st . f ilePath, st . p b)
return nil
return nil
}
}
func ( st * State ) Save ( ) error {
if st . Pb == nil {
st . Pb = & volume_server_pb . VolumeServerState { }
func ( st * State ) save ( locking bool ) error {
if locking {
st . mu . Lock ( )
defer st . mu . Unlock ( )
}
if st . pb == nil {
st . pb = & volume_server_pb . VolumeServerState { }
}
}
binPb , err := proto . Marshal ( st . Pb )
binPb , err := proto . Marshal ( st . p b)
if err != nil {
if err != nil {
return fmt . Errorf ( "failed to serialize store state %v: %s" , st . Pb , err )
return fmt . Errorf ( "failed to serialize store state %v: %s" , st . p b, err )
}
}
if err := util . WriteFile ( st . F ilePath, binPb , StateFileMode ) ; err != nil {
return fmt . Errorf ( "failed to write store state to %s : %v" , st . F ilePath, err )
if err := util . WriteFile ( st . f ilePath, binPb , StateFileMode ) ; err != nil {
return fmt . Errorf ( "failed to write store state to %s : %v" , st . f ilePath, err )
}
}
glog . V ( 1 ) . Infof ( "Saved store state %v to %s" , st . P b, st . F ilePath)
glog . V ( 1 ) . Infof ( "Saved store state %v to %s" , st . p b, st . f ilePath)
return nil
return nil
}
}
func ( st * State ) Save ( ) error {
return st . save ( true )
}
func ( st * State ) Update ( state * volume_server_pb . VolumeServerState ) error {
func ( st * State ) Update ( state * volume_server_pb . VolumeServerState ) error {
st . mu . Lock ( )
defer st . mu . Unlock ( )
if state == nil {
if state == nil {
return nil
return nil
}
}
if got , want := st . pb . GetVersion ( ) , state . GetVersion ( ) ; got != want {
return fmt . Errorf ( "version mismatch for VolumeServerState (got %d, want %d)" , got , want )
}
origState := st . pb
st . pb = & volume_server_pb . VolumeServerState { }
proto . Merge ( st . pb , state )
st . pb . Version = st . pb . GetVersion ( ) + 1
origState := st . Pb
st . Pb = state
err := st . Save ( )
err := st . save ( false )
if err != nil {
if err != nil {
// restore the original state upon save failures, to avoid skew between in-memory and disk state protos.
// restore the original state upon save failures, to avoid skew between in-memory and disk state protos.
st . Pb = origState
st . p b = origState
}
}
return err
return err