예제 #1
0
파일: raft.go 프로젝트: nikolodien/goDB
// Used to check for existence of server
func Exists(pid int, debug bool) bool {
	if cluster.Exists(pid, debug) {
		return true
	} else {
		return false
	}
}
예제 #2
0
파일: raft.go 프로젝트: nikolodien/goDB
// 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)
	}
}