Commit 9574763b authored by Harshit Pande's avatar Harshit Pande

fixed conflicts in raft.go with cluster configuration

parents 1eb4542d aafa7ab8
...@@ -2,6 +2,7 @@ package raft ...@@ -2,6 +2,7 @@ package raft
import ( import (
"bytes" "bytes"
"encoding/gob"
"log" "log"
"net" "net"
"strconv" "strconv"
...@@ -193,10 +194,14 @@ func MonitorCommitChannel(ch chan LogEntry) { ...@@ -193,10 +194,14 @@ func MonitorCommitChannel(ch chan LogEntry) {
temp := <-ch temp := <-ch
conn := temp.(*LogEntryData).conn conn := temp.(*LogEntryData).conn
cmd := new(utils.Command) cmd := new(utils.Command)
if err := cmd.GobDecode(temp.Data()); err != nil {
log.Fatal("Error decoding command!") buffer := bytes.NewBuffer(temp.GetData())
dec := gob.NewDecoder(buffer)
if err := dec.Decode(cmd); err != nil {
log.Fatal("Error decoding command!", err)
} }
ParseInput(conn, cmd) ParseInput(conn, cmd)
//Debug()
} }
} }
...@@ -498,7 +503,7 @@ func performDelete(conn net.Conn, tokens []string) int { ...@@ -498,7 +503,7 @@ func performDelete(conn net.Conn, tokens []string) int {
*arguments: none *arguments: none
*return: none *return: none
*/ */
func debug() { func Debug() {
logger.Println("----start debug----") logger.Println("----start debug----")
for key, val := range (*table).dictionary { for key, val := range (*table).dictionary {
logger.Println(key, val) logger.Println(key, val)
......
...@@ -19,6 +19,8 @@ const ( ...@@ -19,6 +19,8 @@ const (
// Logger // Logger
var Info *log.Logger var Info *log.Logger
var lsn Lsn
// Flag for enabling/disabling logging functionality // Flag for enabling/disabling logging functionality
var DEBUG = true var DEBUG = true
...@@ -43,30 +45,27 @@ type SharedLog interface { ...@@ -43,30 +45,27 @@ type SharedLog interface {
} }
type Raft struct { type Raft struct {
log_array []*LogEntryData LogArray []*LogEntryData
commitCh chan LogEntry commitCh chan LogEntry
cluster_config *ClusterConfig //cluster clusterConfig *ClusterConfig //cluster
id int //this server id id int //this server id
sync.RWMutex sync.RWMutex
} }
type LogEntry interface { type LogEntry interface {
Lsn() Lsn GetLsn() Lsn
Data() []byte GetData() []byte
Committed() bool GetCommitted() bool
SetCommitted(status bool)
} }
type LogEntryData struct { type LogEntryData struct {
id Lsn Id Lsn
data []byte Data []byte
committed bool Committed bool
conn net.Conn conn net.Conn
} }
type Args struct {
X int
}
type Reply struct { type Reply struct {
X int X int
} }
...@@ -79,18 +78,31 @@ func GetClusterConfig() *ClusterConfig { ...@@ -79,18 +78,31 @@ func GetClusterConfig() *ClusterConfig {
return cluster_config return cluster_config
} }
func NewRaft(config *ClusterConfig, thisServerId int, commitCh chan LogEntry) (*Raft, error) { func NewRaft(config *ClusterConfig, thisServerId int, commitCh chan LogEntry, logger *log.Logger) (*Raft, error) {
rft := new(Raft) rft := new(Raft)
rft.commitCh = commitCh rft.commitCh = commitCh
rft.cluster_config = config rft.clusterConfig = config
cluster_config = config
rft.id = thisServerId rft.id = thisServerId
Info = logger
lsn = 0
return rft, nil return rft, nil
} }
func NewLogEntry(data []byte, committed bool, conn net.Conn) *LogEntryData {
entry := new(LogEntryData)
entry.Id = lsn
entry.Data = data
entry.conn = conn
entry.Committed = committed
lsn++
return entry
}
//goroutine that monitors channel to check if the majority of servers have replied //goroutine that monitors channel to check if the majority of servers have replied
func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh chan bool) { func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh chan bool) {
acks_received := 0 acks_received := 0
num_servers := len(rft.cluster_config.Servers) num_servers := len(rft.clusterConfig.Servers)
required_acks := num_servers / 2 required_acks := num_servers / 2
up := make(chan bool, 1) up := make(chan bool, 1)
err := false err := false
...@@ -103,9 +115,12 @@ func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh c ...@@ -103,9 +115,12 @@ func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh c
for { for {
select { select {
case temp := <-ack_ch: case temp := <-ack_ch:
Info.Println("Ack Received:", temp)
acks_received += temp acks_received += temp
if acks_received == required_acks { if acks_received == required_acks {
rft.log_array[log_entry.(*LogEntryData).id].committed = true Info.Println("Majority Achieved", log_entry.(*LogEntryData).Id)
rft.LogArray[log_entry.(*LogEntryData).Id].Committed = true
//Info.Println(rft.LogArray)
rft.commitCh <- log_entry rft.commitCh <- log_entry
majCh <- true majCh <- true
err = true err = true
...@@ -113,6 +128,7 @@ func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh c ...@@ -113,6 +128,7 @@ func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh c
} }
case <-up: case <-up:
Info.Println("Error")
err = true err = true
break break
} }
...@@ -122,47 +138,56 @@ func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh c ...@@ -122,47 +138,56 @@ func monitorAckChannel(rft *Raft, ack_ch <-chan int, log_entry LogEntry, majCh c
} }
} }
//make LogEntryData implement the //make LogEntryData implement the LogEntry Interface
func (entry *LogEntryData) Lsn() Lsn { func (entry *LogEntryData) GetLsn() Lsn {
return entry.id return entry.Id
}
func (entry *LogEntryData) GetData() []byte {
return entry.Data
} }
func (entry *LogEntryData) Data() []byte { func (entry *LogEntryData) GetCommitted() bool {
return entry.data return entry.Committed
} }
func (entry *LogEntryData) Committed() bool { func (entry *LogEntryData) SetCommitted(committed bool) {
return entry.committed entry.Committed = committed
}
//make rpc call to followers
func doRPCCall(ackChan chan int, hostname string, logPort int, temp *LogEntryData) {
client, err := rpc.Dial("tcp", hostname+":"+strconv.Itoa(logPort))
if err != nil {
Info.Fatal("Dialing:", err)
}
reply := new(Reply)
args := temp
Info.Println("RPC Called", logPort)
appendCall := client.Go("AppendEntries.AppendEntriesRPC", args, reply, nil) //let go allocate done channel
appendCall = <-appendCall.Done
Info.Println("Reply", appendCall, reply.X)
ackChan <- reply.X
} }
//make raft implement the append function //make raft implement the append function
func (rft *Raft) Append(data []byte, conn net.Conn) (LogEntry, error) { func (rft *Raft) Append(data []byte, conn net.Conn) (LogEntry, error) {
Info.Println("Append Called")
if rft.id != 1 { if rft.id != 1 {
return nil, ErrRedirect(1) return nil, ErrRedirect(1)
} }
temp := new(LogEntryData) defer rft.Unlock()
temp.id = 1 rft.Lock()
temp.committed = false temp := NewLogEntry(data, false, conn)
temp.data = data
temp.conn = conn rft.LogArray = append(rft.LogArray, temp)
rft.log_array = append(rft.log_array, temp)
ackChan := make(chan int) ackChan := make(chan int)
majChan := make(chan bool) majChan := make(chan bool)
go monitorAckChannel(rft, ackChan, temp, majChan) go monitorAckChannel(rft, ackChan, temp, majChan)
for _, server := range cluster_config.Servers[1:] { for _, server := range rft.clusterConfig.Servers[1:] {
go func(ackChan chan int) { doRPCCall(ackChan, server.Hostname, server.LogPort, temp)
client, err := rpc.Dial("tcp", server.Hostname+":"+strconv.Itoa(server.LogPort))
if err != nil {
Info.Fatal("Dialing:", err)
}
reply := new(Reply)
args := temp
appendCall := client.Go("AppendEntries.AppendEntriesRPC", args, reply, nil) //let go allocate done channel
appendCall = <-appendCall.Done
ackChan <- reply.X
}(ackChan)
} }
if <-majChan { if <-majChan {
......
...@@ -16,8 +16,7 @@ import ( ...@@ -16,8 +16,7 @@ import (
// Logger // Logger
var Info *log.Logger var Info *log.Logger
// Flag for enabling/disabling logging functionality var rft *raft.Raft
var DEBUG = true
type AppendEntries struct{} type AppendEntries struct{}
...@@ -59,8 +58,17 @@ type Reply struct { ...@@ -59,8 +58,17 @@ type Reply struct {
X int X int
} }
func (t *AppendEntries) AppendEntriesRPC(args *raft.LogEntry, reply *Reply) error { func (t *AppendEntries) AppendEntriesRPC(args *raft.LogEntryData, reply *Reply) error {
Info.Println("RPC invoked") Info.Println("Append Entries RPC invoked", (*args).GetLsn(), (*args).GetData(), (*args).GetCommitted())
rft.LogArray = append(rft.LogArray, raft.NewLogEntry((*args).GetData(), (*args).GetCommitted(), nil))
reply.X = 1
return nil
}
func (t *AppendEntries) CommitRPC(args *raft.LogEntry, reply *Reply) error {
Info.Println("Commit RPC invoked")
rft.LogArray[(*args).GetLsn()].SetCommitted(true)
reply.X = 1 reply.X = 1
return nil return nil
} }
...@@ -84,12 +92,11 @@ func initInterServerCommunication(server *raft.ServerConfig, rft *raft.Raft, ch ...@@ -84,12 +92,11 @@ func initInterServerCommunication(server *raft.ServerConfig, rft *raft.Raft, ch
} }
// Initialize Logger // Initialize Logger
func initLogger(serverId int) { func initLogger(serverId int, toDebug bool) {
// Logger Initializaion // Logger Initializaion
if !DEBUG { if !toDebug {
Info = log.New(ioutil.Discard, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) Info = log.New(ioutil.Discard, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
} else { } else {
Info = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) Info = log.New(os.Stdout, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile)
} }
...@@ -120,7 +127,11 @@ func main() { ...@@ -120,7 +127,11 @@ func main() {
Info.Println("argument ", os.Args[1], "is not string") Info.Println("argument ", os.Args[1], "is not string")
} }
initLogger(sid) if len(os.Args) > 3 {
initLogger(sid, true)
} else {
initLogger(sid, false)
}
Info.Println("Starting") Info.Println("Starting")
serverCount, err2 := strconv.Atoi((os.Args[2])) serverCount, err2 := strconv.Atoi((os.Args[2]))
...@@ -132,7 +143,7 @@ func main() { ...@@ -132,7 +143,7 @@ func main() {
clusterConfig, _ := raft.NewClusterConfig(serverCount) clusterConfig, _ := raft.NewClusterConfig(serverCount)
commitCh := make(chan raft.LogEntry) commitCh := make(chan raft.LogEntry)
rft, _ := raft.NewRaft(clusterConfig, sid, commitCh) rft, _ = raft.NewRaft(clusterConfig, sid, commitCh, Info)
raft.InitKVStore(Info) raft.InitKVStore(Info)
go raft.MonitorCommitChannel(commitCh) //for kvstore go raft.MonitorCommitChannel(commitCh) //for kvstore
......
...@@ -4,7 +4,7 @@ package main ...@@ -4,7 +4,7 @@ package main
import ( import (
"bytes" "bytes"
"fmt" //"fmt"
"net" "net"
"net/rpc" "net/rpc"
"os" "os"
...@@ -39,6 +39,8 @@ func TestAll(t *testing.T) { ...@@ -39,6 +39,8 @@ func TestAll(t *testing.T) {
//test no reply //test no reply
testNoReply(t) testNoReply(t)
testSet(t)
} }
//run servers //run servers
...@@ -63,7 +65,7 @@ func testConnectFollower(t *testing.T) { ...@@ -63,7 +65,7 @@ func testConnectFollower(t *testing.T) {
if err != nil { if err != nil {
t.Error("Error in connecting the server at port: " + strconv.Itoa(server_port)) t.Error("Error in connecting the server at port: " + strconv.Itoa(server_port))
} else { } else {
time.Sleep(time.Millisecond) //time.Sleep(time.Millisecond)
sending := []byte("set mykey1 100 3\r\nlul\r\n") sending := []byte("set mykey1 100 3\r\nlul\r\n")
port := strconv.Itoa(raft.CLIENT_PORT + 1) port := strconv.Itoa(raft.CLIENT_PORT + 1)
expecting := []byte("ERR_REDIRECT 127.0.0.1 " + port + "\r\n") expecting := []byte("ERR_REDIRECT 127.0.0.1 " + port + "\r\n")
...@@ -80,7 +82,7 @@ func testConnectFollower(t *testing.T) { ...@@ -80,7 +82,7 @@ func testConnectFollower(t *testing.T) {
) )
} }
conn.Close() conn.Close()
time.Sleep(time.Millisecond) //time.Sleep(time.Millisecond)
} }
} }
} }
...@@ -99,13 +101,13 @@ func testNoReply(t *testing.T) { ...@@ -99,13 +101,13 @@ func testNoReply(t *testing.T) {
if err != nil { if err != nil {
t.Error("Error in connecting the server at port: " + strconv.Itoa(server_port)) t.Error("Error in connecting the server at port: " + strconv.Itoa(server_port))
} else { } else {
time.Sleep(time.Millisecond) //time.Sleep(time.Millisecond)
for _, pair := range noreply_cases { for _, pair := range noreply_cases {
conn.Write(pair.to_server) conn.Write(pair.to_server)
buffer := make([]byte, 1024) buffer := make([]byte, 1024)
conn.Read(buffer) conn.Read(buffer)
n := bytes.Index(buffer, []byte{0}) n := bytes.Index(buffer, []byte{0})
fmt.Println(buffer) //fmt.Println(buffer)
if !bytes.Equal(buffer[:n], pair.from_server) { if !bytes.Equal(buffer[:n], pair.from_server) {
t.Error( t.Error(
"For", pair.to_server, string(pair.to_server), "For", pair.to_server, string(pair.to_server),
...@@ -115,7 +117,40 @@ func testNoReply(t *testing.T) { ...@@ -115,7 +117,40 @@ func testNoReply(t *testing.T) {
} }
} }
conn.Close() conn.Close()
time.Sleep(time.Millisecond) //time.Sleep(time.Millisecond)
}
}
//noreply option is not more valid with set and cas
//client should get command error from the server if it sends 'no reply' option
func testSet(t *testing.T) {
var noreply_cases = []Testpair{
{[]byte("set mykey1 100 3\r\nadd\r\n"), []byte("OK 1\r\n")},
}
server_port := raft.CLIENT_PORT + 1
conn, err := net.Dial("tcp", ":"+strconv.Itoa(server_port))
if err != nil {
t.Error("Error in connecting the server at port: " + strconv.Itoa(server_port))
} else {
//time.Sleep(time.Millisecond)
for _, pair := range noreply_cases {
conn.Write(pair.to_server)
buffer := make([]byte, 1024)
conn.Read(buffer)
n := bytes.Index(buffer, []byte{0})
//fmt.Println(buffer)
if !bytes.Equal(buffer[:n], pair.from_server) {
t.Error(
"For", pair.to_server, string(pair.to_server),
"expected", pair.from_server, string(pair.from_server),
"got", buffer[:n], string(buffer[:n]),
)
}
}
conn.Close()
//time.Sleep(time.Millisecond)
} }
} }
...@@ -190,24 +225,24 @@ func monitorPresentChannel(presentChan chan bool, t *testing.T) { ...@@ -190,24 +225,24 @@ func monitorPresentChannel(presentChan chan bool, t *testing.T) {
// Add some dummy entries in raft.ClusterConfig such that majority is not achieved // Add some dummy entries in raft.ClusterConfig such that majority is not achieved
// Expected: Time out should occur after 5 sec and log entry table should not be updated // Expected: Time out should occur after 5 sec and log entry table should not be updated
func CommandNotCommittedWithoutMajority() { func testCommandNotCommittedWithoutMajority() {
} }
// Expected: Log entry table updated with the new entry // Expected: Log entry table updated with the new entry
func CommandCommittedWithMajority() { func testCommandCommittedWithMajority() {
} }
// Multiple clients sending different requests // Multiple clients sending different requests
// Expected: Log entry table updated // Expected: Log entry table updated
func ConcurrentManyClientsToLeader() { func testConcurrentManyClientsToLeader() {
} }
// Single client sending 100 requests one after another // Single client sending 100 requests one after another
// Expected: Log entry table updated // Expected: Log entry table updated
func ConcurrentClientManyRequestsToLeader() { func testConcurrentClientManyRequestsToLeader() {
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment