diff --git a/cluster/cluster.go b/cluster/cluster.go index 59aaeee..1594d66 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -132,6 +132,9 @@ func (cluster *Cluster) Exec(c redis.Connection, cmdLine [][]byte) (result redis } }() cmdName := strings.ToLower(string(cmdLine[0])) + if cmdName == "info" { + return database2.Info(c, cmdLine) + } if cmdName == "auth" { return database2.Auth(c, cmdLine[1:]) } diff --git a/cluster/router.go b/cluster/router.go index 34c3ac0..93536e2 100644 --- a/cluster/router.go +++ b/cluster/router.go @@ -8,6 +8,7 @@ type CmdLine = [][]byte func makeRouter() map[string]CmdFunc { routerMap := make(map[string]CmdFunc) routerMap["ping"] = ping + routerMap["info"] = info routerMap["prepare"] = execPrepare routerMap["commit"] = execCommit diff --git a/cluster/utils.go b/cluster/utils.go index fdeb669..422ef68 100644 --- a/cluster/utils.go +++ b/cluster/utils.go @@ -11,6 +11,10 @@ func ping(cluster *Cluster, c redis.Connection, cmdLine CmdLine) redis.Reply { return cluster.db.Exec(c, cmdLine) } +func info(cluster *Cluster, c redis.Connection, cmdLine CmdLine) redis.Reply { + return cluster.db.Exec(c, cmdLine) +} + /*----- utils -------*/ func makeArgs(cmd string, args ...string) [][]byte { diff --git a/config/config.go b/config/config.go index d12c789..ba323ca 100644 --- a/config/config.go +++ b/config/config.go @@ -5,6 +5,7 @@ import ( "github.com/hdt3213/godis/lib/utils" "io" "os" + "path/filepath" "reflect" "strconv" "strings" @@ -136,4 +137,9 @@ func SetupConfig(configFilename string) { defer file.Close() Properties = parse(file) Properties.RunID = utils.RandString(40) + configFilePath, err := filepath.Abs(configFilename) + if err != nil { + return + } + Properties.CfPath = configFilePath } diff --git a/database/systemcmd.go b/database/systemcmd.go index f13df44..bcd9054 100644 --- a/database/systemcmd.go +++ b/database/systemcmd.go @@ -5,6 +5,7 @@ import ( "github.com/hdt3213/godis/config" "github.com/hdt3213/godis/interface/redis" "github.com/hdt3213/godis/redis/protocol" + "github.com/hdt3213/godis/tcp" "os" "runtime" "strings" @@ -25,21 +26,28 @@ func Ping(c redis.Connection, args [][]byte) redis.Reply { // Info the information of the godis server returned by the INFO command func Info(c redis.Connection, args [][]byte) redis.Reply { if len(args) == 1 { - return protocol.MakeBulkReply(GenGodisInfoString()) + infoCommandList := [...]string{"server", "client", "cluster"} + var allSection []byte + for _, s := range infoCommandList { + allSection = append(allSection, GenGodisInfoString(s)...) + } + + return protocol.MakeBulkReply(allSection) } else if len(args) == 2 { section := strings.ToLower(string(args[1])) switch section { case "server": - reply := GenGodisInfoString() + reply := GenGodisInfoString("server") return protocol.MakeBulkReply(reply) + case "client": + return protocol.MakeBulkReply(GenGodisInfoString("client")) + case "cluster": + return protocol.MakeBulkReply(GenGodisInfoString("cluster")) default: return protocol.MakeNullBulkReply() } - } else { - return protocol.MakeErrReply("ERR wrong number of arguments for 'info' command") } - - return &protocol.NullBulkReply{} + return protocol.MakeErrReply("ERR wrong number of arguments for 'info' command") } // Auth validate client's password @@ -65,44 +73,75 @@ func isAuthenticated(c redis.Connection) bool { return c.GetPassword() == config.Properties.RequirePass } -func GenGodisInfoString() []byte { +func GenGodisInfoString(section string) []byte { startUpTimeFromNow := getGodisRunningTime() - s := fmt.Sprintf("# Server\r\n"+ - "godis_version:%s\r\n"+ - //"godis_git_sha1:%s\r\n"+ - //"godis_git_dirty:%d\r\n"+ - //"godis_build_id:%s\r\n"+ - "godis_mode:%s\r\n"+ - "os:%s %s\r\n"+ - "arch_bits:%d\r\n"+ - //"multiplexing_api:%s\r\n"+ - "go_version:%s\r\n"+ - "process_id:%d\r\n"+ - "run_id:%s\r\n"+ - "tcp_port:%d\r\n"+ - "uptime_in_seconds:%d\r\n"+ - "uptime_in_days:%d\r\n"+ - //"hz:%d\r\n"+ - //"lru_clock:%d\r\n"+ - "config_file:%s\r\n", - godisVersion, - //TODO, - //TODO, - //TODO, - getGodisRunningMode(), - runtime.GOOS, runtime.GOARCH, - 32<<(^uint(0)>>63), - //TODO, - runtime.Version(), - os.Getpid(), - config.Properties.RunID, - config.Properties.Port, - startUpTimeFromNow, - startUpTimeFromNow/time.Duration(3600*24), - //TODO, - //TODO, - config.Properties.CfPath) - return []byte(s) + switch section { + case "server": + s := fmt.Sprintf("# Server\r\n"+ + "godis_version:%s\r\n"+ + //"godis_git_sha1:%s\r\n"+ + //"godis_git_dirty:%d\r\n"+ + //"godis_build_id:%s\r\n"+ + "godis_mode:%s\r\n"+ + "os:%s %s\r\n"+ + "arch_bits:%d\r\n"+ + //"multiplexing_api:%s\r\n"+ + "go_version:%s\r\n"+ + "process_id:%d\r\n"+ + "run_id:%s\r\n"+ + "tcp_port:%d\r\n"+ + "uptime_in_seconds:%d\r\n"+ + "uptime_in_days:%d\r\n"+ + //"hz:%d\r\n"+ + //"lru_clock:%d\r\n"+ + "config_file:%s\r\n", + godisVersion, + //TODO, + //TODO, + //TODO, + getGodisRunningMode(), + runtime.GOOS, runtime.GOARCH, + 32<<(^uint(0)>>63), + //TODO, + runtime.Version(), + os.Getpid(), + config.Properties.RunID, + config.Properties.Port, + startUpTimeFromNow, + startUpTimeFromNow/time.Duration(3600*24), + //TODO, + //TODO, + config.Properties.CfPath) + return []byte(s) + case "client": + s := fmt.Sprintf("# Clients\r\n"+ + "connected_clients:%d\r\n", + //"client_recent_max_input_buffer:%d\r\n"+ + //"client_recent_max_output_buffer:%d\r\n"+ + //"blocked_clients:%d\n", + tcp.ClientCounter, + //TODO, + //TODO, + //TODO, + ) + return []byte(s) + case "cluster": + if getGodisRunningMode() == config.ClusterMode { + s := fmt.Sprintf("# Cluster\r\n"+ + "cluster_enabled:%s\r\n", + "1", + ) + return []byte(s) + } else { + s := fmt.Sprintf("# Cluster\r\n"+ + "cluster_enabled:%s\r\n", + "0", + ) + return []byte(s) + } + } + + return []byte("") } // getGodisRunningMode return godis running mode diff --git a/database/systemcmd_test.go b/database/systemcmd_test.go index 123abd1..a0f8c6a 100644 --- a/database/systemcmd_test.go +++ b/database/systemcmd_test.go @@ -46,6 +46,10 @@ func TestInfo(t *testing.T) { asserts.AssertNotError(t, ret) ret = testServer.Exec(c, utils.ToCmdLine("INFO", "server")) asserts.AssertNotError(t, ret) + ret = testServer.Exec(c, utils.ToCmdLine("INFO", "client")) + asserts.AssertNotError(t, ret) + ret = testServer.Exec(c, utils.ToCmdLine("INFO", "cluster")) + asserts.AssertNotError(t, ret) ret = testServer.Exec(c, utils.ToCmdLine("iNFO", "SeRvEr")) asserts.AssertNotError(t, ret) ret = testServer.Exec(c, utils.ToCmdLine("iNFO", "abc", "bde")) diff --git a/tcp/server.go b/tcp/server.go index 24cdaa2..c382110 100644 --- a/tcp/server.go +++ b/tcp/server.go @@ -25,6 +25,9 @@ type Config struct { Timeout time.Duration `yaml:"timeout"` } +// ClientCounter Record the number of clients in the current Godis server +var ClientCounter int + // ListenAndServeWithSignal binds port and handle requests, blocking until receive stop signal func ListenAndServeWithSignal(cfg *Config, handler tcp.Handler) error { closeChan := make(chan struct{}) @@ -75,10 +78,12 @@ func ListenAndServe(listener net.Listener, handler tcp.Handler, closeChan <-chan } // handle logger.Info("accept link") + ClientCounter++ waitDone.Add(1) go func() { defer func() { waitDone.Done() + ClientCounter-- }() handler.Handle(ctx, conn) }()