package controller import ( "encoding/json" "fmt" "runtime" "sort" "time" "github.com/google/btree" "github.com/tidwall/resp" "github.com/tidwall/tile38/controller/server" ) func (c *Controller) cmdStats(msg *server.Message) (res string, err error) { start := time.Now() vs := msg.Values[1:] var ms = []map[string]interface{}{} if len(vs) == 0 { return "", errInvalidNumberOfArguments } var vals []resp.Value var key string var ok bool for { vs, key, ok = tokenval(vs) if !ok { break } col := c.getCol(key) if col != nil { m := make(map[string]interface{}) points := col.PointCount() m["num_points"] = points m["in_memory_size"] = col.TotalWeight() m["num_objects"] = col.Count() switch msg.OutputType { case server.JSON: ms = append(ms, m) case server.RESP: vals = append(vals, resp.ArrayValue(respValuesSimpleMap(m))) } } else { switch msg.OutputType { case server.JSON: ms = append(ms, nil) case server.RESP: vals = append(vals, resp.NullValue()) } } } switch msg.OutputType { case server.JSON: data, err := json.Marshal(ms) if err != nil { return "", err } res = `{"ok":true,"stats":` + string(data) + `,"elapsed":"` + time.Now().Sub(start).String() + "\"}" case server.RESP: data, err := resp.ArrayValue(vals).MarshalRESP() if err != nil { return "", err } res = string(data) } return res, nil } func (c *Controller) cmdServer(msg *server.Message) (res string, err error) { start := time.Now() if len(msg.Values) != 1 { return "", errInvalidNumberOfArguments } m := make(map[string]interface{}) m["id"] = c.config.ServerID if c.config.FollowHost != "" { m["following"] = fmt.Sprintf("%s:%d", c.config.FollowHost, c.config.FollowPort) m["caught_up"] = c.fcup } m["aof_size"] = c.aofsz m["num_collections"] = c.cols.Len() m["num_hooks"] = len(c.hooks) sz := 0 c.cols.Ascend(func(item btree.Item) bool { col := item.(*collectionT).Collection sz += col.TotalWeight() return true }) m["in_memory_size"] = sz points := 0 objects := 0 c.cols.Ascend(func(item btree.Item) bool { col := item.(*collectionT).Collection points += col.PointCount() objects += col.Count() return true }) m["num_points"] = points m["num_objects"] = objects var mem runtime.MemStats runtime.ReadMemStats(&mem) avgsz := 0 if points != 0 { avgsz = int(mem.HeapAlloc) / points } m["heap_size"] = mem.HeapAlloc m["max_heap_size"] = c.config.MaxMemory m["avg_item_size"] = avgsz m["pointer_size"] = (32 << uintptr(uint64(^uintptr(0))>>63)) / 8 m["read_only"] = c.config.ReadOnly switch msg.OutputType { case server.JSON: data, err := json.Marshal(m) if err != nil { return "", err } res = `{"ok":true,"stats":` + string(data) + `,"elapsed":"` + time.Now().Sub(start).String() + "\"}" case server.RESP: vals := respValuesSimpleMap(m) data, err := resp.ArrayValue(vals).MarshalRESP() if err != nil { return "", err } res = string(data) } return res, nil } func respValuesSimpleMap(m map[string]interface{}) []resp.Value { var keys []string for key := range m { keys = append(keys, key) } sort.Strings(keys) var vals []resp.Value for _, key := range keys { val := m[key] vals = append(vals, resp.StringValue(key)) vals = append(vals, resp.StringValue(fmt.Sprintf("%v", val))) } return vals } func (c *Controller) statsCollections(line string) (string, error) { start := time.Now() var key string var ms = []map[string]interface{}{} for len(line) > 0 { line, key = token(line) col := c.getCol(key) if col != nil { m := make(map[string]interface{}) points := col.PointCount() m["num_points"] = points m["in_memory_size"] = col.TotalWeight() m["num_objects"] = col.Count() ms = append(ms, m) } else { ms = append(ms, nil) } } data, err := json.Marshal(ms) if err != nil { return "", err } return `{"ok":true,"stats":` + string(data) + `,"elapsed":"` + time.Now().Sub(start).String() + "\"}", nil }