Skip to content

Commit

Permalink
server, statistics: add dump_stats api for debug (pingcap#5534)
Browse files Browse the repository at this point in the history
  • Loading branch information
fipped authored and alivxxx committed Jan 3, 2018
1 parent 3e3b633 commit 7c23a84
Show file tree
Hide file tree
Showing 11 changed files with 461 additions and 46 deletions.
3 changes: 3 additions & 0 deletions server/http_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ func (s *Server) startHTTPServer() {
// HTTP path for prometheus.
router.Handle("/metrics", prometheus.Handler())

// HTTP path for dump statistics.
router.Handle("/stats/dump/{db}/{table}", s.newStatsHandler())

if s.cfg.Store == "tikv" {
tikvHandler := s.newRegionHandler()
// HTTP path for regions
Expand Down
72 changes: 36 additions & 36 deletions server/region_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func (t *regionHandlerTool) getRegionsMeta(regionIDs []uint64) ([]RegionMeta, er
func (rh schemaHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
schema, err := rh.schema()
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}

Expand All @@ -267,10 +267,10 @@ func (rh schemaHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
cTableName := model.NewCIStr(tableName)
data, err := schema.TableByName(cDBName, cTableName)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
rh.writeData(w, data.Meta())
writeData(w, data.Meta())
return
}
// all table schemas in a specified database
Expand All @@ -280,34 +280,34 @@ func (rh schemaHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
for i := range tbsInfo {
tbsInfo[i] = tbs[i].Meta()
}
rh.writeData(w, tbsInfo)
writeData(w, tbsInfo)
return
}
rh.writeError(w, infoschema.ErrDatabaseNotExists.GenByArgs(dbName))
writeError(w, infoschema.ErrDatabaseNotExists.GenByArgs(dbName))
return
}

if tableID := req.FormValue(qTableID); len(tableID) > 0 {
// table schema of a specified tableID
tid, err := strconv.Atoi(tableID)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
if tid < 0 {
rh.writeError(w, infoschema.ErrTableNotExists.Gen("Table which ID = %s does not exist.", tableID))
writeError(w, infoschema.ErrTableNotExists.Gen("Table which ID = %s does not exist.", tableID))
return
}
if data, ok := schema.TableByID(int64(tid)); ok {
rh.writeData(w, data.Meta())
writeData(w, data.Meta())
return
}
rh.writeError(w, infoschema.ErrTableNotExists.Gen("Table which ID = %s does not exist.", tableID))
writeError(w, infoschema.ErrTableNotExists.Gen("Table which ID = %s does not exist.", tableID))
return
}

// all databases' schemas
rh.writeData(w, schema.AllSchemas())
writeData(w, schema.AllSchemas())
return
}

Expand All @@ -319,13 +319,13 @@ func (rh tableHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
tableName := params[pTableName]
schema, err := rh.schema()
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
// get table's schema.
table, err := schema.TableByName(model.NewCIStr(dbName), model.NewCIStr(tableName))
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}

Expand All @@ -335,7 +335,7 @@ func (rh tableHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
case opTableDiskUsage:
rh.handleDiskUsageRequest(schema, table, w, req)
default:
rh.writeError(w, errors.New("method not found"))
writeError(w, errors.New("method not found"))
}
}

Expand All @@ -345,12 +345,12 @@ func (rh tableHandler) handleRegionRequest(schema infoschema.InfoSchema, tbl tab
startKey, endKey := tablecodec.GetTableHandleKeyRange(tableID)
recordRegionIDs, err := rh.regionCache.ListRegionIDsInKeyRange(rh.bo, startKey, endKey)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
recordRegions, err := rh.getRegionsMeta(recordRegionIDs)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}

Expand All @@ -363,12 +363,12 @@ func (rh tableHandler) handleRegionRequest(schema infoschema.InfoSchema, tbl tab
startKey, endKey := tablecodec.GetTableIndexKeyRange(tableID, indexID)
rIDs, err := rh.regionCache.ListRegionIDsInKeyRange(rh.bo, startKey, endKey)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
indices[i].Regions, err = rh.getRegionsMeta(rIDs)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
}
Expand All @@ -380,7 +380,7 @@ func (rh tableHandler) handleRegionRequest(schema infoschema.InfoSchema, tbl tab
RecordRegions: recordRegions,
}

rh.writeData(w, tableRegions)
writeData(w, tableRegions)
}

// pdRegionStats is the json response from PD.
Expand All @@ -399,11 +399,11 @@ func (rh tableHandler) handleDiskUsageRequest(schema infoschema.InfoSchema, tbl
var pdAddrs []string
etcd, ok := rh.store.(domain.EtcdBackend)
if !ok {
rh.writeError(w, errors.New("not implemented"))
writeError(w, errors.New("not implemented"))
}
pdAddrs = etcd.EtcdAddrs()
if len(pdAddrs) < 0 {
rh.writeError(w, errors.New("pd unavailable"))
writeError(w, errors.New("pd unavailable"))
}

// Include table and index data, because their range located in tableID_i tableID_r
Expand All @@ -419,7 +419,7 @@ func (rh tableHandler) handleDiskUsageRequest(schema infoschema.InfoSchema, tbl

resp, err := http.Get(statURL)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
defer func() {
Expand All @@ -431,10 +431,10 @@ func (rh tableHandler) handleDiskUsageRequest(schema infoschema.InfoSchema, tbl
var stats pdRegionStats
dec := json.NewDecoder(resp.Body)
if err := dec.Decode(&stats); err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
rh.writeData(w, stats.StorageSize)
writeData(w, stats.StorageSize)
}

// ServeHTTP handles request of get region by ID.
Expand All @@ -447,36 +447,36 @@ func (rh regionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {

recordRegionIDs, err := rh.regionCache.ListRegionIDsInKeyRange(rh.bo, startKey, endKey)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}

recordRegions, err := rh.getRegionsMeta(recordRegionIDs)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
rh.writeData(w, recordRegions)
writeData(w, recordRegions)
return
}

regionIDInt, err := strconv.ParseInt(params[pRegionID], 0, 64)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
regionID := uint64(regionIDInt)

// locate region
region, err := rh.regionCache.LocateRegionByID(rh.bo, regionID)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}

frameRange, err := NewRegionFrameRange(region)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}

Expand All @@ -488,7 +488,7 @@ func (rh regionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
schema, err := rh.schema()
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
// Since we need a database's name for each frame, and a table's database name can not
Expand All @@ -501,19 +501,19 @@ func (rh regionHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
regionDetail.addTableInRange(db.Name.String(), table, start, end)
}
}
rh.writeData(w, regionDetail)
writeData(w, regionDetail)
}

func (rh *regionHandler) writeError(w http.ResponseWriter, err error) {
func writeError(w http.ResponseWriter, err error) {
w.WriteHeader(http.StatusBadRequest)
_, err = w.Write([]byte(err.Error()))
terror.Log(errors.Trace(err))
}

func (rh *regionHandler) writeData(w http.ResponseWriter, data interface{}) {
func writeData(w http.ResponseWriter, data interface{}) {
js, err := json.Marshal(data)
if err != nil {
rh.writeError(w, err)
writeError(w, err)
return
}
log.Info(string(js))
Expand Down Expand Up @@ -723,9 +723,9 @@ func (rh mvccTxnHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
err = errors.NotSupportedf("Operation not supported.")
}
if err != nil {
rh.writeError(w, err)
writeError(w, err)
} else {
rh.writeData(w, data)
writeData(w, data)
}
}

Expand Down
63 changes: 63 additions & 0 deletions server/statistics_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2018 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
"net/http"

"github.com/gorilla/mux"
"github.com/pingcap/tidb"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/model"
log "github.com/sirupsen/logrus"
)

// StatsHandler is the handler for dump statistics.
type StatsHandler struct {
do *domain.Domain
}

func (s *Server) newStatsHandler() *StatsHandler {
store, ok := s.driver.(*TiDBDriver)
if !ok {
panic("Illegal driver")
}
do, err := tidb.BootstrapSession(store.store)
if err != nil {
log.Error("Failed to bootstrap session", err)
return nil
}
return &StatsHandler{do}
}

func (sh StatsHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")

params := mux.Vars(req)

is := sh.do.InfoSchema()
h := sh.do.StatsHandle()

tbl, err := is.TableByName(model.NewCIStr(params[pDBName]), model.NewCIStr(params[pTableName]))
if err != nil {
writeError(w, err)
} else {
js, err := h.DumpStatsToJSON(params[pDBName], tbl.Meta())
if err != nil {
writeError(w, err)
} else {
writeData(w, js)
}
}
}
Loading

0 comments on commit 7c23a84

Please sign in to comment.