Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql: add json encoding/decoding support for stmt/txn stats. #67805

Merged
merged 1 commit into from
Jul 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ ALL_TESTS = [
"//pkg/sql/span:span_test",
"//pkg/sql/sqlliveness/slinstance:slinstance_test",
"//pkg/sql/sqlliveness/slstorage:slstorage_test",
"//pkg/sql/sqlstats/persistedsqlstats/sqlstatsutil:sqlstatsutil_test",
"//pkg/sql/stats:stats_test",
"//pkg/sql/stmtdiagnostics:stmtdiagnostics_test",
"//pkg/sql/tests:tests_test",
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ go_library(
"//pkg/sql/sqlfsm",
"//pkg/sql/sqlliveness",
"//pkg/sql/sqlstats",
"//pkg/sql/sqlstats/persistedsqlstats/sqlstatsutil",
"//pkg/sql/sqlstats/sslocal",
"//pkg/sql/sqltelemetry",
"//pkg/sql/sqlutil",
Expand Down
25 changes: 2 additions & 23 deletions pkg/sql/crdb_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
"github.com/cockroachdb/cockroach/pkg/sql/sqlliveness"
"github.com/cockroachdb/cockroach/pkg/sql/sqlstats"
"github.com/cockroachdb/cockroach/pkg/sql/sqlstats/persistedsqlstats/sqlstatsutil"
"github.com/cockroachdb/cockroach/pkg/sql/types"
"github.com/cockroachdb/cockroach/pkg/util/duration"
"github.com/cockroachdb/cockroach/pkg/util/errorutil"
Expand Down Expand Up @@ -851,28 +852,6 @@ func getSQLStats(p *planner, virtualTableName string) (sqlstats.Storage, error)
return p.extendedEvalCtx.statsStorage, nil
}

// ExplainTreePlanNodeToJSON builds a formatted JSON object from the explain tree nodes.
func ExplainTreePlanNodeToJSON(node *roachpb.ExplainTreePlanNode) json.JSON {

// Create a new json.ObjectBuilder with key-value pairs for the node's name (1),
// node's attributes (len(node.Attrs)), and the node's children (1).
nodePlan := json.NewObjectBuilder(len(node.Attrs) + 2 /* numAddsHint */)
nodeChildren := json.NewArrayBuilder(len(node.Children))

nodePlan.Add("Name", json.FromString(node.Name))

for _, attr := range node.Attrs {
nodePlan.Add(strings.Title(attr.Key), json.FromString(attr.Value))
}

for _, childNode := range node.Children {
nodeChildren.Add(ExplainTreePlanNodeToJSON(childNode))
}

nodePlan.Add("Children", nodeChildren.Build())
return nodePlan.Build()
}

var crdbInternalStmtStatsTable = virtualSchemaTable{
comment: `statement statistics (in-memory, not durable; local node only). ` +
`This table is wiped periodically (by default, at least every two hours)`,
Expand Down Expand Up @@ -956,7 +935,7 @@ CREATE TABLE crdb_internal.node_statement_statistics (
flags = "!" + flags
}

samplePlan := ExplainTreePlanNodeToJSON(&stats.Stats.SensitiveInfo.MostRecentPlanDescription)
samplePlan := sqlstatsutil.ExplainTreePlanNodeToJSON(&stats.Stats.SensitiveInfo.MostRecentPlanDescription)

execNodeIDs := tree.NewDArray(types.Int)
for _, nodeID := range stats.Stats.Nodes {
Expand Down
124 changes: 0 additions & 124 deletions pkg/sql/crdb_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,130 +495,6 @@ UPDATE system.namespace SET id = 12345 WHERE id = 53;
require.False(t, rows.Next())
}

// TestExplainTreePlanNodeToJSON tests whether the ExplainTreePlanNode function
// correctly builds a JSON object from an ExplainTreePlanNode.
func TestExplainTreePlanNodeToJSON(t *testing.T) {
defer leaktest.AfterTest(t)()

testDataArr := []struct {
explainTree roachpb.ExplainTreePlanNode
expected string
}{
// Test data using a node with multiple inner children.
{
roachpb.ExplainTreePlanNode{
Name: "root",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "rootKey",
Value: "rootValue",
},
},
Children: []*roachpb.ExplainTreePlanNode{
{
Name: "child",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "childKey",
Value: "childValue",
},
},
Children: []*roachpb.ExplainTreePlanNode{
{
Name: "innerChild",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "innerChildKey",
Value: "innerChildValue",
},
},
},
},
},
},
},
`{"Children": [{"ChildKey": "childValue", "Children": [{"Children": [], "InnerChildKey": "innerChildValue", "Name": "innerChild"}], "Name": "child"}], "Name": "root", "RootKey": "rootValue"}`,
},
// Test using a node with multiple attributes.
{
roachpb.ExplainTreePlanNode{
Name: "root",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "rootFirstKey",
Value: "rootFirstValue",
},
{
Key: "rootSecondKey",
Value: "rootSecondValue",
},
},
Children: []*roachpb.ExplainTreePlanNode{
{
Name: "child",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "childKey",
Value: "childValue",
},
},
},
},
},
`{"Children": [{"ChildKey": "childValue", "Children": [], "Name": "child"}], "Name": "root", "RootFirstKey": "rootFirstValue", "RootSecondKey": "rootSecondValue"}`,
},
// Test using a node with multiple children and multiple inner children.
{
roachpb.ExplainTreePlanNode{
Name: "root",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "rootKey",
Value: "rootValue",
},
},
Children: []*roachpb.ExplainTreePlanNode{
{
Name: "firstChild",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "firstChildKey",
Value: "firstChildValue",
},
},
Children: []*roachpb.ExplainTreePlanNode{
{
Name: "innerChild",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "innerChildKey",
Value: "innerChildValue",
},
},
},
},
},
{
Name: "secondChild",
Attrs: []*roachpb.ExplainTreePlanNode_Attr{
{
Key: "secondChildKey",
Value: "secondChildValue",
},
},
},
},
},
`{"Children": [{"Children": [{"Children": [], "InnerChildKey": "innerChildValue", "Name": "innerChild"}], "FirstChildKey": "firstChildValue", "Name": "firstChild"}, {"Children": [], "Name": "secondChild", "SecondChildKey": "secondChildValue"}], "Name": "root", "RootKey": "rootValue"}`,
},
}

for _, testData := range testDataArr {
explainTreeJSON := sql.ExplainTreePlanNodeToJSON(&testData.explainTree)
require.Equal(t, testData.expected, explainTreeJSON.String())
}
}

func TestDistSQLFlowsVirtualTables(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)
Expand Down
32 changes: 32 additions & 0 deletions pkg/sql/sqlstats/persistedsqlstats/sqlstatsutil/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "sqlstatsutil",
srcs = [
"json_decoding.go",
"json_encoding.go",
"json_impl.go",
],
importpath = "github.com/cockroachdb/cockroach/pkg/sql/sqlstats/persistedsqlstats/sqlstatsutil",
visibility = ["//visibility:public"],
deps = [
"//pkg/roachpb:with-mocks",
"//pkg/util/encoding",
"//pkg/util/json",
"@com_github_cockroachdb_apd_v2//:apd",
"@com_github_cockroachdb_errors//:errors",
],
)

go_test(
name = "sqlstatsutil_test",
srcs = ["json_encoding_test.go"],
embed = [":sqlstatsutil"],
deps = [
"//pkg/roachpb:with-mocks",
"//pkg/util/json",
"//pkg/util/leaktest",
"//pkg/util/log",
"@com_github_stretchr_testify//require",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2021 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package sqlstatsutil

import (
"github.com/cockroachdb/cockroach/pkg/roachpb"
"github.com/cockroachdb/cockroach/pkg/util/json"
)

// DecodeTxnStatsMetadataJSON decodes the 'metadata' field of the JSON
// representation of transaction statistics into
// roachpb.CollectedTransactionStatistics.
func DecodeTxnStatsMetadataJSON(
metadata json.JSON, result *roachpb.CollectedTransactionStatistics,
) error {
return jsonFields{
{"stmtFingerprintIDs", (*stmtFingerprintIDArray)(&result.StatementFingerprintIDs)},
}.decodeJSON(metadata)
}

// DecodeTxnStatsStatisticsJSON decodes the 'statistics' section of the
// transaction statistics JSON payload into roachpb.TransactionStatistics
// protobuf.
func DecodeTxnStatsStatisticsJSON(jsonVal json.JSON, result *roachpb.TransactionStatistics) error {
return (*txnStats)(result).decodeJSON(jsonVal)
}

// DecodeStmtStatsMetadataJSON decodes the 'metadata' field of the JSON
// representation of the statement statistics into
// roachpb.CollectedStatementStatistics.
func DecodeStmtStatsMetadataJSON(
metadata json.JSON, result *roachpb.CollectedStatementStatistics,
) error {
return (*stmtStatsMetadata)(result).jsonFields().decodeJSON(metadata)
}

// DecodeStmtStatsStatisticsJSON decodes the 'statistics' field and the
// 'execution_statistics' field in the given json into
// roachpb.StatementStatistics.
func DecodeStmtStatsStatisticsJSON(jsonVal json.JSON, result *roachpb.StatementStatistics) error {
return (*stmtStats)(result).decodeJSON(jsonVal)
}
Loading