basic cluster mode

This commit is contained in:
hdt3213
2020-06-10 09:00:22 +08:00
parent d1a95a5fec
commit d492588d9e
14 changed files with 706 additions and 26 deletions

92
src/cluster/cluster.go Normal file
View File

@@ -0,0 +1,92 @@
package cluster
import (
"fmt"
"github.com/HDT3213/godis/src/config"
"github.com/HDT3213/godis/src/db"
"github.com/HDT3213/godis/src/interface/redis"
"github.com/HDT3213/godis/src/lib/consistenthash"
"github.com/HDT3213/godis/src/lib/logger"
"github.com/HDT3213/godis/src/redis/client"
"github.com/HDT3213/godis/src/redis/reply"
"runtime/debug"
"strings"
)
type Cluster struct {
self string
db *db.DB
peerPicker *consistenthash.Map
peers map[string]*client.Client
}
const (
replicas = 4
)
func MakeCluster() *Cluster {
cluster := &Cluster{
self: config.Properties.Self,
db: db.MakeDB(),
peerPicker: consistenthash.New(replicas, nil),
peers: make(map[string]*client.Client),
}
if config.Properties.Peers != nil && len(config.Properties.Peers) > 0 {
cluster.peerPicker.Add(config.Properties.Peers...)
}
return cluster
}
// args contains all
type CmdFunc func(cluster *Cluster, c redis.Client, args [][]byte) redis.Reply
func (cluster *Cluster) Close() {
cluster.db.Close()
}
var router = MakeRouter()
func (cluster *Cluster) Exec(c redis.Client, args [][]byte) (result redis.Reply) {
defer func() {
if err := recover(); err != nil {
logger.Warn(fmt.Sprintf("error occurs: %v\n%s", err, string(debug.Stack())))
result = &reply.UnknownErrReply{}
}
}()
cmd := strings.ToLower(string(args[0]))
cmdFunc, ok := router[cmd]
if !ok {
return reply.MakeErrReply("ERR unknown command '" + cmd + "'")
}
result = cmdFunc(cluster, c, args)
return
}
// relay command to peer
func (cluster *Cluster) Relay(key string, c redis.Client, args [][]byte) redis.Reply {
peer := cluster.peerPicker.Get(key)
if peer == cluster.self {
// to self db
return cluster.db.Exec(c, args)
} else {
peerClient, ok := cluster.peers[peer]
// lazy init
if !ok {
var err error
peerClient, err = client.MakeClient(peer)
if err != nil {
return reply.MakeErrReply(err.Error())
}
peerClient.Start()
cluster.peers[peer] = peerClient
}
return peerClient.Send(args)
}
}
func (cluster *Cluster) AfterClientClose(c redis.Client) {
}

102
src/cluster/router.go Normal file
View File

@@ -0,0 +1,102 @@
package cluster
import "github.com/HDT3213/godis/src/interface/redis"
func defaultFunc(cluster *Cluster, c redis.Client, args [][]byte) redis.Reply {
key := string(args[1])
return cluster.Relay(key, c, args)
}
func MakeRouter() map[string]CmdFunc {
routerMap := make(map[string]CmdFunc)
//routerMap["ping"] = defaultFunc
//routerMap["del"] = Del
routerMap["expire"] = defaultFunc
routerMap["expireat"] = defaultFunc
routerMap["pexpire"] = defaultFunc
routerMap["pexpireat"] = defaultFunc
routerMap["ttl"] = defaultFunc
routerMap["pttl"] = defaultFunc
routerMap["persist"] = defaultFunc
routerMap["exists"] = defaultFunc
routerMap["type"] = defaultFunc
//routerMap["rename"] = Rename
//routerMap["renamenx"] = RenameNx
routerMap["set"] = defaultFunc
routerMap["setnx"] = defaultFunc
routerMap["setex"] = defaultFunc
routerMap["psetex"] = defaultFunc
//routerMap["mset"] = MSet
//routerMap["mget"] = MGet
//routerMap["msetnx"] = MSetNX
routerMap["get"] = defaultFunc
routerMap["getset"] = defaultFunc
routerMap["incr"] = defaultFunc
routerMap["incrby"] = defaultFunc
routerMap["incrbyfloat"] = defaultFunc
routerMap["decr"] = defaultFunc
routerMap["decrby"] = defaultFunc
routerMap["lpush"] = defaultFunc
routerMap["lpushx"] = defaultFunc
routerMap["rpush"] = defaultFunc
routerMap["rpushx"] = defaultFunc
routerMap["lpop"] = defaultFunc
routerMap["rpop"] = defaultFunc
//routerMap["rpoplpush"] = RPopLPush
routerMap["lrem"] = defaultFunc
routerMap["llen"] = defaultFunc
routerMap["lindex"] = defaultFunc
routerMap["lset"] = defaultFunc
routerMap["lrange"] = defaultFunc
routerMap["hset"] = defaultFunc
routerMap["hsetnx"] = defaultFunc
routerMap["hget"] = defaultFunc
routerMap["hexists"] = defaultFunc
routerMap["hdel"] = defaultFunc
routerMap["hlen"] = defaultFunc
routerMap["hmget"] = defaultFunc
routerMap["hmset"] = defaultFunc
routerMap["hkeys"] = defaultFunc
routerMap["hvals"] = defaultFunc
routerMap["hgetall"] = defaultFunc
routerMap["hincrby"] = defaultFunc
routerMap["hincrbyfloat"] = defaultFunc
routerMap["sadd"] = defaultFunc
routerMap["sismember"] = defaultFunc
routerMap["srem"] = defaultFunc
routerMap["scard"] = defaultFunc
routerMap["smembers"] = defaultFunc
routerMap["sinter"] = defaultFunc
routerMap["sinterstore"] = defaultFunc
routerMap["sunion"] = defaultFunc
routerMap["sunionstore"] = defaultFunc
routerMap["sdiff"] = defaultFunc
routerMap["sdiffstore"] = defaultFunc
routerMap["srandmember"] = defaultFunc
routerMap["zadd"] = defaultFunc
routerMap["zscore"] = defaultFunc
routerMap["zincrby"] = defaultFunc
routerMap["zrank"] = defaultFunc
routerMap["zcount"] = defaultFunc
routerMap["zrevrank"] = defaultFunc
routerMap["zcard"] = defaultFunc
routerMap["zrange"] = defaultFunc
routerMap["zrevrange"] = defaultFunc
routerMap["zrangebyscore"] = defaultFunc
routerMap["zrevrangebyscore"] = defaultFunc
routerMap["zrem"] = defaultFunc
routerMap["zremrangebyscore"] = defaultFunc
routerMap["zremrangebyrank"] = defaultFunc
//routerMap["flushdb"] = FlushDB
//routerMap["flushall"] = FlushAll
//routerMap["keys"] = Keys
return routerMap
}

1
src/cluster/string.go Normal file
View File

@@ -0,0 +1 @@
package cluster