Created
October 29, 2024 13:03
-
-
Save gdiasag/3f962e0631a63ec67d5267a64dc5a26a to your computer and use it in GitHub Desktop.
Tarefa 11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "math/rand" | |
| "sync" | |
| "time" | |
| ) | |
| type ServerState string | |
| const ( | |
| Leader ServerState = "Leader" | |
| Follower ServerState = "Follower" | |
| Candidate ServerState = "Candidate" | |
| ) | |
| type LogEntry struct { | |
| Command string | |
| Term int | |
| } | |
| type Node struct { | |
| ID int | |
| State ServerState | |
| CurrentTerm int | |
| VotedFor *int | |
| Log []LogEntry | |
| IsAlive bool | |
| Votes int | |
| } | |
| type Cluster struct { | |
| Nodes []*Node | |
| LeaderID *int | |
| mu sync.Mutex | |
| ElectionCh chan int | |
| } | |
| func NewCluster(n int) *Cluster { | |
| nodes := make([]*Node, n) | |
| for i := range nodes { | |
| nodes[i] = &Node{ | |
| ID: i + 1, | |
| State: Follower, | |
| CurrentTerm: 0, | |
| VotedFor: nil, | |
| Log: []LogEntry{}, | |
| IsAlive: true, | |
| Votes: 0, | |
| } | |
| } | |
| return &Cluster{Nodes: nodes, LeaderID: nil, ElectionCh: make(chan int)} | |
| } | |
| func (c *Cluster) StartElection(node *Node) { | |
| c.mu.Lock() | |
| defer c.mu.Unlock() | |
| node.State = Candidate | |
| node.CurrentTerm++ | |
| node.VotedFor = &node.ID | |
| node.Votes = 1 // Vote for self | |
| fmt.Printf("Node %d started election for term %d\n", node.ID, node.CurrentTerm) | |
| for _, peer := range c.Nodes { | |
| if peer.ID != node.ID && peer.IsAlive && peer.CurrentTerm <= node.CurrentTerm { | |
| peer.VotedFor = &node.ID | |
| node.Votes++ | |
| } | |
| } | |
| if node.Votes > len(c.Nodes)/2 { | |
| c.LeaderID = &node.ID | |
| node.State = Leader | |
| fmt.Printf("Node %d became the leader for term %d\n", node.ID, node.CurrentTerm) | |
| c.ElectionCh <- node.ID | |
| } | |
| } | |
| func (c *Cluster) Heartbeat(node *Node) { | |
| for { | |
| select { | |
| case leaderID := <-c.ElectionCh: | |
| if node.ID != leaderID && node.IsAlive { | |
| fmt.Printf("Node %d acknowledges leader %d\n", node.ID, leaderID) | |
| node.State = Follower | |
| node.VotedFor = nil | |
| } | |
| case <-time.After(2 * time.Second): | |
| if node.State == Leader && node.IsAlive { | |
| fmt.Printf("Leader %d sending heartbeat\n", node.ID) | |
| } else if node.State != Leader && node.IsAlive { | |
| fmt.Printf("Node %d has not received heartbeat, starting election\n", node.ID) | |
| c.StartElection(node) | |
| } | |
| } | |
| } | |
| } | |
| func (c *Cluster) Simulate(duration time.Duration) { | |
| fmt.Println("Starting simulation...") | |
| ticker := time.NewTicker(2 * time.Second) | |
| defer ticker.Stop() | |
| end := time.After(duration) | |
| for { | |
| select { | |
| case <-ticker.C: | |
| c.mu.Lock() | |
| node := c.Nodes[rand.Intn(len(c.Nodes))] | |
| node.IsAlive = !node.IsAlive // Toggle alive status for simulation | |
| status := "failed" | |
| if node.IsAlive { | |
| status = "recovered" | |
| } | |
| fmt.Printf("Node %d has %s\n", node.ID, status) | |
| c.mu.Unlock() | |
| case <-end: | |
| fmt.Println("Simulation ended.") | |
| return | |
| } | |
| } | |
| } | |
| func main() { | |
| rand.Seed(time.Now().UnixNano()) | |
| cluster := NewCluster(5) | |
| // Launch Heartbeat and Election goroutines | |
| for _, node := range cluster.Nodes { | |
| go cluster.Heartbeat(node) | |
| } | |
| // Run the simulation for 10 seconds | |
| cluster.Simulate(10 * time.Second) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment