// Used to check for existence of server func Exists(pid int, debug bool) bool { if cluster.Exists(pid, debug) { return true } else { return false } }
// The main server routine func serverRoutine(pid int, rserver *rServer, config string, channelClose chan bool, debug bool) { // Retrieve term,votedFor,start and commit Index for this server err := retrieveData(rserver) // Apply the commands in the log to the state machine for index := rserver.StartIndex; index <= rserver.CommitIndex; index++ { rserver.ReaderRequest <- &ReadRequest{Index: index} // Wait for the logEntry to be read select { case serverLogEntry := <-rserver.ReaderData: if debug { log.Printf("Server %d read logEntry %v for index %v", rserver.Pid, serverLogEntry, index) } if serverLogEntry != nil { if debug { log.Printf("Applying %v to StateMachine of server %d", serverLogEntry.ServerLogData.Command, pid) } kvCommand := serverLogEntry.ServerLogData.Command switch cmd := kvCommand.(type) { case KVCommand: switch cmd.Command { case PUT: rserver.StateMachine[cmd.Key] = cmd.Value case DEL: delete(rserver.StateMachine, cmd.Key) case GET: // No action needs to be performed for GET } } rserver.LastApplied = index } } } // Check if server already exists if cluster.Exists(pid, debug) { if debug { log.Printf("Server %d already exists", pid) } // If a server is already present, then return return } // This will start a new server cserver := cluster.New(pid, config, debug) // A server starts of as a follower rserver.State = FOLLOWER if err != nil { if debug { log.Printf("Error in Server %d: %v", rserver.Pid, err) } } // Print server timeout if debug { log.Printf("Timeout for server with pid %d is %d", pid, rserver.Timeout) } if err != nil { if debug { log.Printf("Error while reading persistant data for %d", pid) } // Set the term to the default value rserver.CurrentTerm = DEFAULT_TERM } outer: for { // A server will be in one of the three states at any moment switch rserver.State { // Describes what the server will do when in the follower state case FOLLOWER: if debug { log.Printf("Server %d with term %d is executing as follower", pid, rserver.CurrentTerm) } followerFunc(pid, rserver, channelClose, cserver.Inbox(), cserver.Outbox(), debug) // Describes the behavior of a candidate case CANDIDATE: if debug { log.Printf("Server %d with term %d is executing as candidate", pid, rserver.CurrentTerm) } candidateFunc(pid, rserver, channelClose, cserver.Inbox(), cserver.Outbox(), cserver.Peers(), debug) // Describes the behavior of a leader case LEADER: if debug { log.Printf("Server %d with term %d is executing as leader", pid, rserver.CurrentTerm) } leaderFunc(pid, rserver, channelClose, cserver.Inbox(), cserver.Outbox(), cserver.Peers(), debug) case EXIT: if debug { log.Printf("Server %d with term %d is preparing to shutdown", pid, rserver.State) } // close the db writer rserver.HandlerClose <- true if debug { log.Printf("Sending close signal to dbHandler") } break outer } } err = persistData(rserver) if err != nil { log.Printf("Error in Server %d: %v", rserver.Pid, err) } rserver.RSLeader = false cluster.Close(cserver, debug) // time.Sleep(time.Millisecond) if debug { log.Printf("Shutting down server with id %d", pid) } }