mirror of
https://github.com/HDT3213/godis.git
synced 2025-10-05 00:42:43 +08:00

# Conflicts: # cluster/cluster.go # cluster/router.go # config/config.go # database/database.go # database/server.go
153 lines
3.8 KiB
Go
153 lines
3.8 KiB
Go
package cluster
|
|
|
|
import (
|
|
"github.com/hdt3213/godis/config"
|
|
database2 "github.com/hdt3213/godis/database"
|
|
"github.com/hdt3213/godis/datastruct/dict"
|
|
"github.com/hdt3213/godis/lib/idgenerator"
|
|
"github.com/hdt3213/godis/lib/utils"
|
|
"github.com/hdt3213/godis/redis/connection"
|
|
"github.com/hdt3213/godis/redis/protocol/asserts"
|
|
"path"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func makeTestRaft(addresses []string, timeoutFlags []bool, persistFilenames []string) ([]*Cluster, error) {
|
|
nodes := make([]*Cluster, len(addresses))
|
|
factory := &testClientFactory{
|
|
nodes: nodes,
|
|
timeoutFlags: timeoutFlags,
|
|
}
|
|
for i, addr := range addresses {
|
|
addr := addr
|
|
nodes[i] = &Cluster{
|
|
self: addr,
|
|
addr: addr,
|
|
db: database2.NewStandaloneServer(),
|
|
transactions: dict.MakeSimple(),
|
|
idGenerator: idgenerator.MakeGenerator(config.Properties.Self),
|
|
clientFactory: factory,
|
|
slots: make(map[uint32]*hostSlot),
|
|
}
|
|
topologyPersistFile := persistFilenames[i]
|
|
nodes[i].topology = newRaft(nodes[i], topologyPersistFile)
|
|
}
|
|
|
|
err := nodes[0].startAsSeed(addresses[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = nodes[1].Join(addresses[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = nodes[2].Join(addresses[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return nodes, nil
|
|
}
|
|
|
|
func TestRaftStart(t *testing.T) {
|
|
addresses := []string{"127.0.0.1:6399", "127.0.0.1:7379", "127.0.0.1:7369"}
|
|
timeoutFlags := []bool{false, false, false}
|
|
persistFilenames := []string{"", "", ""}
|
|
nodes, err := makeTestRaft(addresses, timeoutFlags, persistFilenames)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if nodes[0].asRaft().state != leader {
|
|
t.Error("expect leader")
|
|
return
|
|
}
|
|
if nodes[1].asRaft().state != follower {
|
|
t.Error("expect follower")
|
|
return
|
|
}
|
|
if nodes[2].asRaft().state != follower {
|
|
t.Error("expect follower")
|
|
return
|
|
}
|
|
size := 100
|
|
conn := connection.NewFakeConn()
|
|
for i := 0; i < size; i++ {
|
|
str := strconv.Itoa(i)
|
|
result := nodes[0].Exec(conn, utils.ToCmdLine("SET", str, str))
|
|
asserts.AssertNotError(t, result)
|
|
}
|
|
for i := 0; i < size; i++ {
|
|
str := strconv.Itoa(i)
|
|
result := nodes[0].Exec(conn, utils.ToCmdLine("Get", str))
|
|
asserts.AssertBulkReply(t, result, str)
|
|
}
|
|
for _, node := range nodes {
|
|
_ = node.asRaft().Close()
|
|
}
|
|
}
|
|
|
|
func TestRaftElection(t *testing.T) {
|
|
addresses := []string{"127.0.0.1:6399", "127.0.0.1:7379", "127.0.0.1:7369"}
|
|
timeoutFlags := []bool{false, false, false}
|
|
persistFilenames := []string{"", "", ""}
|
|
nodes, err := makeTestRaft(addresses, timeoutFlags, persistFilenames)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
nodes[0].asRaft().Close()
|
|
time.Sleep(3 * electionTimeoutMaxMs * time.Millisecond) // wait for leader timeout
|
|
//<-make(chan struct{}) // wait for leader timeout
|
|
for i := 0; i < 10; i++ {
|
|
leaderCount := 0
|
|
for _, node := range nodes {
|
|
if node.asRaft().closed {
|
|
continue
|
|
}
|
|
switch node.asRaft().state {
|
|
case leader:
|
|
leaderCount++
|
|
}
|
|
}
|
|
if leaderCount == 1 {
|
|
break
|
|
} else if leaderCount > 1 {
|
|
t.Errorf("get %d leaders, split brain", leaderCount)
|
|
break
|
|
}
|
|
time.Sleep(time.Second)
|
|
}
|
|
}
|
|
|
|
func TestRaftPersist(t *testing.T) {
|
|
addresses := []string{"127.0.0.1:6399", "127.0.0.1:7379", "127.0.0.1:7369"}
|
|
timeoutFlags := []bool{false, false, false}
|
|
persistFilenames := []string{
|
|
path.Join(config.Properties.Dir, "test6399.conf"),
|
|
path.Join(config.Properties.Dir, "test7379.conf"),
|
|
path.Join(config.Properties.Dir, "test7369.conf"),
|
|
}
|
|
nodes, err := makeTestRaft(addresses, timeoutFlags, persistFilenames)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
node1 := nodes[0].asRaft()
|
|
err = node1.persist()
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
for _, node := range nodes {
|
|
_ = node.asRaft().Close()
|
|
}
|
|
|
|
err = node1.LoadConfigFile()
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
}
|