diff --git a/src/go/lib/util/util.go b/src/go/lib/tutil/util.go similarity index 98% rename from src/go/lib/util/util.go rename to src/go/lib/tutil/util.go index 61664f0c..4acda744 100644 --- a/src/go/lib/util/util.go +++ b/src/go/lib/tutil/util.go @@ -1,4 +1,4 @@ -package util +package tutil import ( "encoding/json" diff --git a/src/go/mongolib/proto/chunks_count.go b/src/go/mongolib/proto/chunks_count.go new file mode 100644 index 00000000..795d5c9c --- /dev/null +++ b/src/go/mongolib/proto/chunks_count.go @@ -0,0 +1,6 @@ +package proto + +type ChunksByCollection struct { + ID string `bson:"_id"` // Namespace + Count int `bson:"count"` +} diff --git a/src/go/mongolib/proto/system.profile.go b/src/go/mongolib/proto/system.profile.go index 0cf9cf42..3bb4494d 100644 --- a/src/go/mongolib/proto/system.profile.go +++ b/src/go/mongolib/proto/system.profile.go @@ -3,10 +3,10 @@ package proto import "time" type SystemProfile struct { - //AllUsers []interface{} `bson:"allUsers"` - Client string `bson:"client"` - CursorExhausted bool `bson:"cursorExhausted"` - DocsExamined int `bson:"docsExamined"` + AllUsers []interface{} `bson:"allUsers"` + Client string `bson:"client"` + CursorExhausted bool `bson:"cursorExhausted"` + DocsExamined int `bson:"docsExamined"` ExecStats struct { Advanced int `bson:"advanced"` ExecutionTimeMillisEstimate int `bson:"executionTimeMillisEstimate"` diff --git a/src/go/pt-mongodb-summary/main.go b/src/go/pt-mongodb-summary/main.go index 37d9ceb9..1723e60f 100644 --- a/src/go/pt-mongodb-summary/main.go +++ b/src/go/pt-mongodb-summary/main.go @@ -111,6 +111,7 @@ type clusterwideInfo struct { UnshardedDataSize int64 // bytes UnshardedDataSizeScaled float64 UnshardedDataSizeScale string + Chunks []proto.ChunksByCollection } type options struct { @@ -221,7 +222,7 @@ func main() { t := template.Must(template.New("hosttemplateData").Parse(templates.HostInfo)) t.Execute(os.Stdout, hostInfo) - if opts.RunningOpsSamples > 0 { + if opts.RunningOpsSamples > 0 && opts.RunningOpsInterval > 0 { if rops, err := GetOpCountersStats(session, opts.RunningOpsSamples, time.Duration(opts.RunningOpsInterval)*time.Millisecond); err != nil { log.Printf("[Error] cannot get Opcounters stats: %v\n", err) } else { @@ -385,6 +386,8 @@ func GetClusterwideInfo(session pmgo.SessionManager) (*clusterwideInfo, error) { cwi.ShardedDataSizeScaled, cwi.ShardedDataSizeScale = sizeAndUnit(cwi.ShardedDataSize) cwi.UnshardedDataSizeScaled, cwi.UnshardedDataSizeScale = sizeAndUnit(cwi.UnshardedDataSize) + cwi.Chunks, _ = getChunksCount(session) + return cwi, nil } @@ -808,3 +811,17 @@ func parseFlags() options { } return opts } + +func getChunksCount(session pmgo.SessionManager) ([]proto.ChunksByCollection, error) { + var result []proto.ChunksByCollection + + c := session.DB("config").C("chunks") + query := bson.M{"$group": bson.M{"_id": "$ns", "count": bson.M{"$sum": 1}}} + + // db.getSiblingDB('config').chunks.aggregate({$group:{_id:"$ns",count:{$sum:1}}}) + err := c.Pipe([]bson.M{query}).All(&result) + if err != nil { + return nil, err + } + return result, nil +} diff --git a/src/go/pt-mongodb-summary/main_test.go b/src/go/pt-mongodb-summary/main_test.go index b3c2beef..b43eaf3b 100644 --- a/src/go/pt-mongodb-summary/main_test.go +++ b/src/go/pt-mongodb-summary/main_test.go @@ -9,7 +9,7 @@ import ( "gopkg.in/mgo.v2/bson" "github.com/golang/mock/gomock" - lutil "github.com/percona/percona-toolkit/src/go/lib/util" + "github.com/percona/percona-toolkit/src/go/lib/tutil" "github.com/percona/percona-toolkit/src/go/mongolib/proto" "github.com/percona/pmgo/pmgomock" ) @@ -23,7 +23,7 @@ func TestGetOpCounterStats(t *testing.T) { database := pmgomock.NewMockDatabaseManager(ctrl) ss := proto.ServerStatus{} - lutil.LoadJson("test/sample/serverstatus.json", &ss) + tutil.LoadJson("test/sample/serverstatus.json", &ss) session.EXPECT().DB("admin").Return(database) database.EXPECT().Run(bson.D{{"serverStatus", 1}, {"recordStats", 1}}, gomock.Any()).SetArg(1, ss) @@ -306,6 +306,39 @@ func TestIsPrivateNetwork(t *testing.T) { } +func TestGetChunks(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + session := pmgomock.NewMockSessionManager(ctrl) + database := pmgomock.NewMockDatabaseManager(ctrl) + pipe := pmgomock.NewMockPipeManager(ctrl) + col := pmgomock.NewMockCollectionManager(ctrl) + + var res []proto.ChunksByCollection + tutil.LoadJson("test/sample/chunks.json", &res) + + pipe.EXPECT().All(gomock.Any()).SetArg(0, res) + + col.EXPECT().Pipe(gomock.Any()).Return(pipe) + + database.EXPECT().C("chunks").Return(col) + + session.EXPECT().DB("config").Return(database) + + want := []proto.ChunksByCollection{ + {ID: "samples.col2", Count: 5}, + } + + got, err := getChunksCount(session) + if err != nil { + t.Errorf("Cannot get chunks: %s", err.Error()) + } + if !reflect.DeepEqual(got, want) { + t.Errorf("Invalid getChunksCount response.\ngot: %+v\nwant: %+v\n", got, want) + } +} + func addToCounters(ss proto.ServerStatus, increment int64) proto.ServerStatus { ss.Opcounters.Command += increment ss.Opcounters.Delete += increment diff --git a/src/go/pt-mongodb-summary/templates/clusterwide.go b/src/go/pt-mongodb-summary/templates/clusterwide.go index 3c8db5eb..aa0b3427 100644 --- a/src/go/pt-mongodb-summary/templates/clusterwide.go +++ b/src/go/pt-mongodb-summary/templates/clusterwide.go @@ -7,4 +7,11 @@ const Clusterwide = ` Sharded Collections: {{.ShardedColsCount}} Unsharded Collections: {{.UnshardedColsCount}} Sharded Data Size: {{.ShardedDataSizeScaled}} {{.ShardedDataSizeScale}} - Unsharded Data Size: {{.UnshardedDataSizeScaled}} {{.UnshardedDataSizeScale}}` + Unsharded Data Size: {{.UnshardedDataSizeScaled}} {{.UnshardedDataSizeScale}} +{{- if .Chunks }} + ### Chunks: + {{- range .Chunks }} + {{ printf "%30s" .ID}}: {{ printf "%5d" .Count }} + {{- end -}} +{{ end -}} +` diff --git a/src/go/pt-mongodb-summary/test/sample/chunks.json b/src/go/pt-mongodb-summary/test/sample/chunks.json new file mode 100644 index 00000000..f2ef8072 --- /dev/null +++ b/src/go/pt-mongodb-summary/test/sample/chunks.json @@ -0,0 +1 @@ +[{"ID":"samples.col2","Count":5}] \ No newline at end of file