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 }