158 lines
3.0 KiB
Go
158 lines
3.0 KiB
Go
package fsm
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/gob"
|
|
"fmt"
|
|
"fusenapi/initalize"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/hashicorp/raft"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func test1() {
|
|
log.SetFlags(log.Llongfile)
|
|
|
|
fsm := StartNode("fs1", "localhost:5500", initalize.InitMysql("fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest"))
|
|
|
|
time.Sleep(time.Second * 5)
|
|
|
|
for i := 0; i < 30; i++ {
|
|
go log.Println(fsm.GetUserState(39))
|
|
}
|
|
|
|
log.Println(fsm.GetUserState(39))
|
|
|
|
select {}
|
|
}
|
|
|
|
// StartNode 启动节点
|
|
func StartNode(ServerID string, RaftBind string, gdb *gorm.DB) *StateCluster {
|
|
|
|
fsm := &StateCluster{
|
|
store: make(map[int64]*UserState),
|
|
waiter: NewWaitCallback(),
|
|
gdb: gdb,
|
|
}
|
|
|
|
var retainSnapshotCount = 2
|
|
// var ServerID string = "fs1"
|
|
// var RaftBind string = "localhost:5500"
|
|
var RaftDir string = fmt.Sprintf("/tmp/raftdir/%s", ServerID)
|
|
|
|
// Setup Raft configuration.
|
|
config := raft.DefaultConfig()
|
|
config.LocalID = raft.ServerID(ServerID)
|
|
|
|
// Setup Raft communication.
|
|
addr, err := net.ResolveTCPAddr("tcp", RaftBind)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
transport, err := raft.NewTCPTransport(RaftBind, addr, 3, 30*time.Second, os.Stderr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Create the snapshot store. This allows the Raft to truncate the log.
|
|
snapshots, err := raft.NewFileSnapshotStore(RaftDir, retainSnapshotCount, os.Stderr)
|
|
if err != nil {
|
|
panic(fmt.Errorf("file snapshot store: %s", err))
|
|
}
|
|
|
|
// Create the log store and stable store.
|
|
logStore := raft.NewInmemStore()
|
|
stableStore := raft.NewInmemStore()
|
|
|
|
// Create the Raft system.
|
|
fsm.ra, err = raft.NewRaft(config, fsm, logStore, stableStore, snapshots, transport)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
configuration := raft.Configuration{
|
|
Servers: []raft.Server{
|
|
{
|
|
Suffrage: raft.Voter,
|
|
ID: config.LocalID,
|
|
Address: transport.LocalAddr(),
|
|
},
|
|
},
|
|
}
|
|
|
|
fu := fsm.ra.BootstrapCluster(configuration)
|
|
if err := fu.Error(); err != nil {
|
|
log.Println(err)
|
|
}
|
|
|
|
waitForLeader(fsm.ra)
|
|
|
|
return fsm
|
|
}
|
|
|
|
func waitForLeader(ra *raft.Raft) {
|
|
leaderCh := ra.LeaderCh()
|
|
|
|
for {
|
|
select {
|
|
case isLeader := <-leaderCh:
|
|
if isLeader {
|
|
return
|
|
}
|
|
case <-time.After(10 * time.Second):
|
|
log.Println("Still waiting for the leader...")
|
|
}
|
|
}
|
|
}
|
|
|
|
// var gdb *gorm.DB = initalize.InitMysql("fusentest:XErSYmLELKMnf3Dh@tcp(110.41.19.98:3306)/fusentest")
|
|
|
|
type UserState struct {
|
|
Expired time.Time
|
|
UserId int64
|
|
PwdHash uint64
|
|
}
|
|
|
|
func (us *UserState) Encode() []byte {
|
|
var buf = bytes.NewBuffer(nil)
|
|
err := gob.NewEncoder(buf).Encode(us)
|
|
if err != nil {
|
|
log.Panic(err)
|
|
return nil
|
|
}
|
|
|
|
return buf.Bytes()
|
|
}
|
|
|
|
// command is used for internal command representation.
|
|
type command struct {
|
|
Op string
|
|
Key int64
|
|
Value *UserState
|
|
}
|
|
|
|
func (cmd *command) Encode() []byte {
|
|
var buf = bytes.NewBuffer(nil)
|
|
err := gob.NewEncoder(buf).Encode(cmd)
|
|
if err != nil {
|
|
log.Panic(err)
|
|
return nil
|
|
}
|
|
|
|
return buf.Bytes()
|
|
}
|
|
|
|
func (cmd *command) Decode(sbuf []byte) error {
|
|
var buf = bytes.NewBuffer(sbuf)
|
|
err := gob.NewDecoder(buf).Decode(cmd)
|
|
if err != nil {
|
|
// log.Panic(err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|