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

sqlstats, builtins: add builtin to reset activity tables #105841

Merged
merged 1 commit into from
Jul 4, 2023
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
2 changes: 2 additions & 0 deletions docs/generated/sql/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3279,6 +3279,8 @@ that has execution latency greater than the ‘minExecutionLatency’. If the
‘expiresAfter’ argument is empty, then the statement bundle request never
expires until the statement bundle is collected</p>
</span></td><td>Volatile</td></tr>
<tr><td><a name="crdb_internal.reset_activity_tables"></a><code>crdb_internal.reset_activity_tables() &rarr; <a href="bool.html">bool</a></code></td><td><span class="funcdesc"><p>This function is used to clear the {statement|transaction} activity system tables.</p>
</span></td><td>Volatile</td></tr>
<tr><td><a name="crdb_internal.reset_index_usage_stats"></a><code>crdb_internal.reset_index_usage_stats() &rarr; <a href="bool.html">bool</a></code></td><td><span class="funcdesc"><p>This function is used to clear the collected index usage statistics.</p>
</span></td><td>Volatile</td></tr>
<tr><td><a name="crdb_internal.reset_sql_stats"></a><code>crdb_internal.reset_sql_stats() &rarr; <a href="bool.html">bool</a></code></td><td><span class="funcdesc"><p>This function is used to clear the collected SQL statistics.</p>
Expand Down
28 changes: 28 additions & 0 deletions pkg/sql/sem/builtins/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -6996,6 +6996,34 @@ table's zone configuration this will return NULL.`,
Volatility: volatility.Volatile,
},
),
"crdb_internal.reset_activity_tables": makeBuiltin(
tree.FunctionProperties{
Category: builtinconstants.CategorySystemInfo,
DistsqlBlocklist: true, // applicable only on the gateway
},
tree.Overload{
Types: tree.ParamTypes{},
ReturnType: tree.FixedReturnType(types.Bool),
Fn: func(ctx context.Context, evalCtx *eval.Context, args tree.Datums) (tree.Datum, error) {
isAdmin, err := evalCtx.SessionAccessor.HasAdminRole(ctx)
if err != nil {
return nil, err
}
if !isAdmin {
return nil, errors.New("crdb_internal.reset_activity_tables() requires admin privilege")
}
if evalCtx.SQLStatsController == nil {
return nil, errors.AssertionFailedf("sql stats controller not set")
}
if err := evalCtx.SQLStatsController.ResetActivityTables(ctx); err != nil {
return nil, err
}
return tree.MakeDBool(true), nil
},
Info: `This function is used to clear the {statement|transaction} activity system tables.`,
Volatility: volatility.Volatile,
},
),
// Deletes the underlying spans backing a table, only
// if the user provides explicit acknowledgement of the
// form "I acknowledge this will irrevocably delete all revisions
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/sem/builtins/fixed_oids.go
Original file line number Diff line number Diff line change
Expand Up @@ -2423,6 +2423,7 @@ var builtinOidsArray = []string{
2450: `st_asmvtgeom(geometry: geometry, bbox: box2d, extent: int) -> geometry`,
2451: `st_asmvtgeom(geometry: geometry, bbox: box2d) -> geometry`,
2452: `crdb_internal.repaired_descriptor(descriptor: bytes, valid_descriptor_ids: int[], valid_job_ids: int[]) -> bytes`,
2453: `crdb_internal.reset_activity_tables() -> bool`,
}

var builtinOidsBySignature map[string]oid.Oid
Expand Down
1 change: 1 addition & 0 deletions pkg/sql/sem/eval/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,7 @@ type GossipOperator interface {
// to avoid circular dependency.
type SQLStatsController interface {
ResetClusterSQLStats(ctx context.Context) error
ResetActivityTables(ctx context.Context) error
CreateSQLStatsCompactionSchedule(ctx context.Context) error
}

Expand Down
34 changes: 20 additions & 14 deletions pkg/sql/sqlstats/persistedsqlstats/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,32 +59,38 @@ func (s *Controller) ResetClusterSQLStats(ctx context.Context) error {
return err
}

resetSysTableStats := func(tableName string) (err error) {
ex := s.db.Executor()
_, err = ex.ExecEx(
ctx,
"reset-sql-stats",
nil, /* txn */
sessiondata.NodeUserSessionDataOverride,
"TRUNCATE "+tableName)
if err := s.resetSysTableStats(ctx, "system.statement_statistics"); err != nil {
return err
}

if err := resetSysTableStats("system.statement_statistics"); err != nil {
if err := s.resetSysTableStats(ctx, "system.transaction_statistics"); err != nil {
return err
}

if err := resetSysTableStats("system.transaction_statistics"); err != nil {
return err
}
return s.ResetActivityTables(ctx)
}

// ResetActivityTables implements the tree.SQLStatsController interface. This
// method resets the {statement|transaction}_activity system tables.
func (s *Controller) ResetActivityTables(ctx context.Context) error {
if !s.st.Version.IsActive(ctx, clusterversion.V23_1CreateSystemActivityUpdateJob) {
return nil
}

if err := resetSysTableStats("system.statement_activity"); err != nil {
if err := s.resetSysTableStats(ctx, "system.statement_activity"); err != nil {
return err
}

return resetSysTableStats("system.transaction_activity")
return s.resetSysTableStats(ctx, "system.transaction_activity")
}

func (s *Controller) resetSysTableStats(ctx context.Context, tableName string) (err error) {
ex := s.db.Executor()
_, err = ex.ExecEx(
ctx,
"reset-sql-stats",
nil, /* txn */
sessiondata.NodeUserSessionDataOverride,
"TRUNCATE "+tableName)
return err
}
98 changes: 98 additions & 0 deletions pkg/sql/sqlstats/persistedsqlstats/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql"
"github.com/cockroachdb/cockroach/pkg/sql/sqlstats/persistedsqlstats"
"github.com/cockroachdb/cockroach/pkg/sql/tests"
"github.com/cockroachdb/cockroach/pkg/testutils"
"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
"github.com/cockroachdb/cockroach/pkg/util/leaktest"
"github.com/cockroachdb/cockroach/pkg/util/log"
"github.com/cockroachdb/errors"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -162,3 +164,99 @@ WHERE app_name = $1
`expected %s to be found in txn stats, but it was not.`, query)
}
}

func TestActivityTablesReset(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)

s, db, _ := serverutils.StartServer(t, base.TestServerArgs{})
sqlDB := sqlutils.MakeSQLRunner(db)
defer s.Stopper().Stop(context.Background())

// Disable sql activity flush job.
sqlDB.Exec(t, `SET CLUSTER SETTING sql.stats.activity.flush.enabled = false`)

testutils.SucceedsSoon(t, func() error {
var enabled bool
sqlDB.QueryRow(t,
"SHOW CLUSTER SETTING sql.stats.activity.flush.enabled",
).Scan(&enabled)
if enabled == true {
return errors.Newf("waiting for sql activity job to be disabled")
}
return nil
})

// Give the query runner privilege to insert into the activity tables.
sqlDB.Exec(t, "INSERT INTO system.users VALUES ('node', NULL, true, 3)")
sqlDB.Exec(t, "GRANT node TO root")

// Insert into system.statement_activity table
sqlDB.Exec(t, `
INSERT INTO system.public.statement_activity (aggregated_ts, fingerprint_id, transaction_fingerprint_id, plan_hash, app_name,
agg_interval, metadata, statistics, plan, index_recommendations, execution_count,
execution_total_seconds, execution_total_cluster_seconds,
contention_time_avg_seconds,
cpu_sql_avg_nanos,
service_latency_avg_seconds, service_latency_p99_seconds)
VALUES (
'2023-06-29 15:00:00+00',
'\x125167e869920859',
'\xbd32daa4ef93bf86',
'\x0fa54115f7caf3e6',
'activity_tables_reset',
'01:00:00',
'{"db": "", "distsql": false, "failed": false, "fullScan": false, "implicitTxn": true, "query": "SELECT id FROM system.jobs", "querySummary": "SELECT id FROM system.jobs", "stmtType": "TypeDML", "vec": true}',
'{"execution_statistics": {"cnt": 1, "contentionTime": {"mean": 0, "sqDiff": 0}, "cpuSQLNanos": {"mean": 133623, "sqDiff": 0}, "maxDiskUsage": {"mean": 0, "sqDiff": 0}, "maxMemUsage": {"mean": 3.072E+4, "sqDiff": 0}, "mvccIteratorStats": {"blockBytes": {"mean": 28086, "sqDiff": 0}, "blockBytesInCache": {"mean": 0, "sqDiff": 0}, "keyBytes": {"mean": 0, "sqDiff": 0}, "pointCount": {"mean": 6, "sqDiff": 0}, "pointsCoveredByRangeTombstones": {"mean": 0, "sqDiff": 0}, "rangeKeyContainedPoints": {"mean": 0, "sqDiff": 0}, "rangeKeyCount": {"mean": 0, "sqDiff": 0}, "rangeKeySkippedPoints": {"mean": 0, "sqDiff": 0}, "seekCount": {"mean": 2, "sqDiff": 0}, "seekCountInternal": {"mean": 2, "sqDiff": 0}, "stepCount": {"mean": 6, "sqDiff": 0}, "stepCountInternal": {"mean": 6, "sqDiff": 0}, "valueBytes": {"mean": 39, "sqDiff": 0}}, "networkBytes": {"mean": 0, "sqDiff": 0}, "networkMsgs": {"mean": 0, "sqDiff": 0}}, "index_recommendations": [], "statistics": {"bytesRead": {"mean": 432, "sqDiff": 0}, "cnt": 1, "firstAttemptCnt": 1, "idleLat": {"mean": 0, "sqDiff": 0}, "indexes": ["15@4"], "lastErrorCode": "", "lastExecAt": "2023-06-29T15:33:11.042902Z", "latencyInfo": {"max": 0.00142586, "min": 0.00142586, "p50": 0, "p90": 0, "p99": 0}, "maxRetries": 0, "nodes": [3], "numRows": {"mean": 3, "sqDiff": 0}, "ovhLat": {"mean": 0.000012357999999999857, "sqDiff": 0}, "parseLat": {"mean": 0, "sqDiff": 0}, "planGists": ["AgEeCACHDwIAAAMFAgYC"], "planLat": {"mean": 0.000655272, "sqDiff": 0}, "regions": ["us-east1"], "rowsRead": {"mean": 3, "sqDiff": 0}, "rowsWritten": {"mean": 0, "sqDiff": 0}, "runLat": {"mean": 0.00075823, "sqDiff": 0}, "svcLat": {"mean": 0.00142586, "sqDiff": 0}}}',
'{"Children": [], "Name": ""}',
'{}',
1,
1,
1,
1,
1,
1,
1
)
`)
// Insert into system.transaction_activity table
sqlDB.Exec(t, `
INSERT INTO system.public.transaction_activity (aggregated_ts, fingerprint_id, app_name, agg_interval, metadata,
statistics, query, execution_count, execution_total_seconds,
execution_total_cluster_seconds, contention_time_avg_seconds,
cpu_sql_avg_nanos, service_latency_avg_seconds, service_latency_p99_seconds)
VALUES (
'2023-06-29 15:00:00+00',
'\x125167e869920859',
'activity_tables_reset',
'01:00:00',
'{"db": "", "distsql": false, "failed": false, "fullScan": false, "implicitTxn": true, "query": "SELECT id FROM system.jobs", "querySummary": "SELECT id FROM system.jobs", "stmtType": "TypeDML", "vec": true}',
'{"execution_statistics": {"cnt": 1, "contentionTime": {"mean": 0, "sqDiff": 0}, "cpuSQLNanos": {"mean": 133623, "sqDiff": 0}, "maxDiskUsage": {"mean": 0, "sqDiff": 0}, "maxMemUsage": {"mean": 3.072E+4, "sqDiff": 0}, "mvccIteratorStats": {"blockBytes": {"mean": 28086, "sqDiff": 0}, "blockBytesInCache": {"mean": 0, "sqDiff": 0}, "keyBytes": {"mean": 0, "sqDiff": 0}, "pointCount": {"mean": 6, "sqDiff": 0}, "pointsCoveredByRangeTombstones": {"mean": 0, "sqDiff": 0}, "rangeKeyContainedPoints": {"mean": 0, "sqDiff": 0}, "rangeKeyCount": {"mean": 0, "sqDiff": 0}, "rangeKeySkippedPoints": {"mean": 0, "sqDiff": 0}, "seekCount": {"mean": 2, "sqDiff": 0}, "seekCountInternal": {"mean": 2, "sqDiff": 0}, "stepCount": {"mean": 6, "sqDiff": 0}, "stepCountInternal": {"mean": 6, "sqDiff": 0}, "valueBytes": {"mean": 39, "sqDiff": 0}}, "networkBytes": {"mean": 0, "sqDiff": 0}, "networkMsgs": {"mean": 0, "sqDiff": 0}}, "index_recommendations": [], "statistics": {"bytesRead": {"mean": 432, "sqDiff": 0}, "cnt": 1, "firstAttemptCnt": 1, "idleLat": {"mean": 0, "sqDiff": 0}, "indexes": ["15@4"], "lastErrorCode": "", "lastExecAt": "2023-06-29T15:33:11.042902Z", "latencyInfo": {"max": 0.00142586, "min": 0.00142586, "p50": 0, "p90": 0, "p99": 0}, "maxRetries": 0, "nodes": [3], "numRows": {"mean": 3, "sqDiff": 0}, "ovhLat": {"mean": 0.000012357999999999857, "sqDiff": 0}, "parseLat": {"mean": 0, "sqDiff": 0}, "planGists": ["AgEeCACHDwIAAAMFAgYC"], "planLat": {"mean": 0.000655272, "sqDiff": 0}, "regions": ["us-east1"], "rowsRead": {"mean": 3, "sqDiff": 0}, "rowsWritten": {"mean": 0, "sqDiff": 0}, "runLat": {"mean": 0.00075823, "sqDiff": 0}, "svcLat": {"mean": 0.00142586, "sqDiff": 0}}}',
'SELECT id FROM system.jobs',
1,
1,
1,
1,
1,
1,
1
)
`)

// Check that system.{statement|transaction} activity tables both have 1 row.
var count int
sqlDB.QueryRow(t, "SELECT count(*) FROM system.statement_activity").Scan(&count)
require.Equal(t, 1 /* expected */, count)

sqlDB.QueryRow(t, "SELECT count(*) FROM system.transaction_activity").Scan(&count)
require.Equal(t, 1 /* expected */, count)

// Flush the tables.
sqlDB.QueryRow(t, "SELECT crdb_internal.reset_activity_tables()")

sqlDB.QueryRow(t, "SELECT count(*) FROM system.statement_activity").Scan(&count)
require.Equal(t, 0 /* expected */, count)

sqlDB.QueryRow(t, "SELECT count(*) FROM system.transaction_activity").Scan(&count)
require.Equal(t, 0 /* expected */, count)
}