mirror of
https://github.com/EchoVault/SugarDB.git
synced 2025-10-13 03:34:07 +08:00
181 lines
4.2 KiB
Go
181 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/hashicorp/memberlist"
|
|
"github.com/hashicorp/raft"
|
|
"github.com/sethvargo/go-retry"
|
|
)
|
|
|
|
type BroadcastMessage struct {
|
|
Action string `json:"Action"`
|
|
ServerID raft.ServerID `json:"ServerID"`
|
|
ServerAddr raft.ServerAddress `json:"ServerAddr"`
|
|
Content string `json:"Content"`
|
|
}
|
|
|
|
// Implements Broadcast interface
|
|
func (broadcastMessage *BroadcastMessage) Invalidates(other memberlist.Broadcast) bool {
|
|
mb, ok := other.(*BroadcastMessage)
|
|
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
if mb.ServerID == broadcastMessage.ServerID && mb.Action == "RaftJoin" {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Implements Broadcast interface
|
|
func (broadcastMessage *BroadcastMessage) Message() []byte {
|
|
msg, err := json.Marshal(broadcastMessage)
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return []byte{}
|
|
}
|
|
|
|
return msg
|
|
}
|
|
|
|
// Implements Broadcast interface
|
|
func (broadcastMessage *BroadcastMessage) Finished() {
|
|
// No-Op
|
|
}
|
|
|
|
func (server *Server) MemberListInit() {
|
|
// Triggered before RaftInit
|
|
cfg := memberlist.DefaultLocalConfig()
|
|
cfg.BindAddr = server.config.BindAddr
|
|
cfg.BindPort = int(server.config.MemberListBindPort)
|
|
cfg.Events = server
|
|
cfg.Delegate = server
|
|
|
|
server.broadcastQueue.RetransmitMult = 1
|
|
server.broadcastQueue.NumNodes = func() int {
|
|
return server.numOfNodes
|
|
}
|
|
|
|
list, err := memberlist.Create(cfg)
|
|
server.memberList = list
|
|
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
if server.config.JoinAddr != "" {
|
|
ctx := context.Background()
|
|
|
|
backoffPolicy := RetryBackoff(retry.NewFibonacci(1*time.Second), 5, 200*time.Millisecond, 0, 0)
|
|
|
|
err := retry.Do(ctx, backoffPolicy, func(ctx context.Context) error {
|
|
_, err := list.Join([]string{server.config.JoinAddr})
|
|
if err != nil {
|
|
return retry.RetryableError(err)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
go server.broadcastRaftAddress()
|
|
}
|
|
}
|
|
|
|
func (server *Server) broadcastRaftAddress() {
|
|
ticker := time.NewTicker(5 * time.Second)
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
fmt.Println("[JOIN_BROADCAST]: Trying to joing server if id ", server.config.ServerID)
|
|
msg := BroadcastMessage{
|
|
Action: "RaftJoin",
|
|
ServerID: raft.ServerID(server.config.ServerID),
|
|
ServerAddr: raft.ServerAddress(fmt.Sprintf("%s:%d", server.config.BindAddr, server.config.RaftBindPort)),
|
|
}
|
|
server.broadcastQueue.QueueBroadcast(&msg)
|
|
case msg := <-*server.raftJoinSuccessCh:
|
|
if msg.ServerID == raft.ServerID(server.config.ServerID) {
|
|
fmt.Printf("Server %s succesfully joined raft cluster.\n", msg.ServerID)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Implements Delegate interface
|
|
func (server *Server) NodeMeta(limit int) []byte {
|
|
return []byte("")
|
|
}
|
|
|
|
// Implements Delegate interface
|
|
func (server *Server) NotifyMsg(msgBytes []byte) {
|
|
var msg BroadcastMessage
|
|
|
|
if err := json.Unmarshal(msgBytes, &msg); err != nil {
|
|
fmt.Print(err)
|
|
return
|
|
}
|
|
|
|
switch msg.Action {
|
|
case "RaftJoin":
|
|
if err := server.addVoter(raft.ServerID(msg.ServerID), raft.ServerAddress(msg.ServerAddr), 0, 0); err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
case "RaftJoinSuccess":
|
|
*server.raftJoinSuccessCh <- msg
|
|
case "MutateData":
|
|
// Mutate the value at a given key
|
|
case "FetchData":
|
|
// Fetch the value at a fiven key
|
|
}
|
|
}
|
|
|
|
// Implements Delegate interface
|
|
func (server *Server) GetBroadcasts(overhead, limit int) [][]byte {
|
|
return server.broadcastQueue.GetBroadcasts(overhead, limit)
|
|
}
|
|
|
|
// Implements Delegate interface
|
|
func (server *Server) LocalState(join bool) []byte {
|
|
// No-Op
|
|
return []byte("")
|
|
}
|
|
|
|
// Implements Delegate interface
|
|
func (server *Server) MergeRemoteState(buf []byte, join bool) {
|
|
// No-Op
|
|
}
|
|
|
|
// Implements EventDelegate interface
|
|
func (server *Server) NotifyJoin(node *memberlist.Node) {
|
|
server.numOfNodes += 1
|
|
}
|
|
|
|
// Implements EventDelegate interface
|
|
func (server *Server) NotifyLeave(node *memberlist.Node) {
|
|
server.numOfNodes -= 1
|
|
}
|
|
|
|
// Implements EventDelegate interface
|
|
func (server *Server) NotifyUpdate(node *memberlist.Node) {
|
|
// No-Op
|
|
}
|
|
|
|
func (server *Server) MemberListShutdown() {
|
|
// Triggered after RaftShutdown
|
|
// Gracefully leave memberlist cluster
|
|
// Broadcast message to remove current node from raft cluster
|
|
fmt.Println("Shutting down memberlist.")
|
|
}
|