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

statistics: use session pool when locking or unlocking table stats #46611

Merged
merged 16 commits into from
Sep 5, 2023

Conversation

Rustin170506
Copy link
Member

@Rustin170506 Rustin170506 commented Sep 4, 2023

What problem does this PR solve?

Issue Number: ref #46351
Problem Summary:

What is changed and how it works?

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No code

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Please refer to Release Notes Language Style Guide to write a quality release note.

None

@ti-chi-bot ti-chi-bot bot added release-note-none Denotes a PR that doesn't merit a release note. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Sep 4, 2023
@codecov
Copy link

codecov bot commented Sep 4, 2023

Codecov Report

Merging #46611 (be8b49e) into master (19e888f) will decrease coverage by 0.6095%.
Report is 11 commits behind head on master.
The diff coverage is 68.7943%.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #46611        +/-   ##
================================================
- Coverage   73.3655%   72.7560%   -0.6095%     
================================================
  Files          1315       1339        +24     
  Lines        395585     402706      +7121     
================================================
+ Hits         290223     292993      +2770     
- Misses        86902      91192      +4290     
- Partials      18460      18521        +61     
Flag Coverage Δ
integration 25.4455% <18.6813%> (?)
unit 73.4348% <68.7943%> (+0.0692%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 54.0444% <ø> (ø)
parser 84.9689% <ø> (+0.0169%) ⬆️
br 48.1649% <ø> (-4.2948%) ⬇️

@hawkingrei hawkingrei self-requested a review September 4, 2023 03:29
@ti-chi-bot ti-chi-bot bot added needs-1-more-lgtm Indicates a PR needs 1 more LGTM. approved labels Sep 4, 2023
@Rustin170506 Rustin170506 force-pushed the rustin-patch-stats-refactor branch from fdb1ccd to c4b21d2 Compare September 4, 2023 08:37
@Rustin170506 Rustin170506 changed the title statistics: add tests for lock/unlock stats statistics: use session poll when locking or unlocking table stats Sep 4, 2023
@Rustin170506 Rustin170506 force-pushed the rustin-patch-stats-refactor branch from c4b21d2 to 1a3a853 Compare September 4, 2023 08:44
@ti-chi-bot ti-chi-bot bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Sep 4, 2023
statistics: fix tests

statistics: fix tests

statistics: fix tests
statistics: gen mock

statistics: gen mock
@Rustin170506 Rustin170506 force-pushed the rustin-patch-stats-refactor branch from 35db42f to 34c1a05 Compare September 4, 2023 09:35
@ti-chi-bot ti-chi-bot bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Sep 5, 2023
@Rustin170506
Copy link
Member Author

  1. Start the TiDB cluster: tiup playground nightly --tiflash 0 --db.binpath /Users/hi-rustin/GolandProjects/tidb/bin/tidb-server
  2. Create table and analyze it:
create table t(a int, b int);
insert into t values (1,2), (3,4), (5,6), (7,8);
analyze table t;
show warnings;
  1. Lock table: lock stats t;
  2. Analyze it again: analyze table t;
  3. Check the warnings: show warnings;
mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                 |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------+
| Note    | 1105 | Analyze use auto adjusted sample rate 1.000000 for table test.t, reason to use this rate is "use min(1, 110000/4) as the sample-rate=1" |
| Warning | 1105 | skip analyze locked table: t                                                                                                            |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------+
  1. Check the mysql.stats_table_locked table:
mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from stats_table_locked;
+----------+--------------+-------+--------------------+
| table_id | modify_count | count | version            |
+----------+--------------+-------+--------------------+
|       98 |            4 |     4 | 443863948666601483 |
+----------+--------------+-------+--------------------+
1 row in set (0.00 sec)
  1. Try to lock it again: lock stats t;
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> lock stats t;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> show warnings;
+---------+------+-----------------------------------+
| Level   | Code | Message                           |
+---------+------+-----------------------------------+
| Warning | 1105 | skip locking locked table: test.t |
+---------+------+-----------------------------------+
1 row in set (0.00 sec)
  1. Show locked stats: show stats_locked;.
mysql> show stats_locked;
+---------+------------+----------------+--------+
| Db_name | Table_name | Partition_name | Status |
+---------+------------+----------------+--------+
| test    | t          |                | locked |
+---------+------------+----------------+--------+
1 row in set (0.00 sec)
  1. Unlock the table: unlock stats t;
  2. Check the mysql.stats_table_locked table again:
mysql> select * from stats_table_locked;
Empty set (0.00 sec)
  1. Show locked stats: show stats_locked;
mysql> show stats_locked;
Empty set (0.00 sec)
  1. Unlock the table again and check warnings: unlock stats t;
mysql> unlock stats t;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+---------------------------------------+
| Level   | Code | Message                               |
+---------+------+---------------------------------------+
| Warning | 1105 | skip unlocking unlocked table: test.t |
+---------+------+---------------------------------------+
1 row in set (0.00 sec)

Copy link
Member Author

@Rustin170506 Rustin170506 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self-check

@time-and-fate time-and-fate changed the title statistics: use session poll when locking or unlocking table stats statistics: use session pool when locking or unlocking table stats Sep 5, 2023
@@ -29,9 +27,15 @@ import (
// - tables: table names of which will be locked.
// Return the message of skipped tables and error.
func (h *Handle) AddLockedTables(tids []int64, pids []int64, tables []*ast.TableName) (string, error) {
Copy link
Contributor

@qw4990 qw4990 Sep 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this PR (in the next few PRs), can we thoroughly detach(decouple) StatsLock from StatsHandler? Specifically, can we remove all Handle.XXLockedXX methods (all methods in this file lock_stats_handler.go) and move them into a new separate package?

Logically, if we implement these XXLockedXX methods on Handler, we think the management of locked stats is part of the responsibility of Handler, although Handler is big enough and it already has too many responsibilities.
Another way is to let the Handler just as a consumer of locked stats info. It doesn't update locked stats info and only reads locked stats info from the storage and reacts to it accordingly.
I'm not sure whether this can simplify the design and implementation, what do you think of this? @hi-rustin
(I'm not sure whether I explain it clearly...

image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if this really helps. If we want to split the entry from the handle to stats locker. Then we need to put it in the domain or some other global structurations. I guess using the stats handle as an entry point for stats logic is fine. The problem with the handle is that we put too much business logic in the entry point.

Right now, the lock/unlock stats handler is pretty simple:

// AddLockedTables add locked tables id to store.
// - tids: table ids of which will be locked.
// - pids: partition ids of which will be locked.
// - tables: table names of which will be locked.
// Return the message of skipped tables and error.
func (h *Handle) AddLockedTables(tids []int64, pids []int64, tables []*ast.TableName) (string, error) {
	se, err := h.pool.Get()
	if err != nil {
		return "", errors.Trace(err)
	}
	defer h.pool.Put(se)

	exec := se.(sqlexec.RestrictedSQLExecutor)

	return lockstats.AddLockedTables(exec, tids, pids, tables)
}

// RemoveLockedTables remove tables from table locked array.
// - tids: table ids of which will be unlocked.
// - pids: partition ids of which will be unlocked.
// - tables: table names of which will be unlocked.
// Return the message of skipped tables and error.
func (h *Handle) RemoveLockedTables(tids []int64, pids []int64, tables []*ast.TableName) (string, error) {
	se, err := h.pool.Get()
	if err != nil {
		return "", errors.Trace(err)
	}
	defer h.pool.Put(se)

	exec := se.(sqlexec.RestrictedSQLExecutor)
	return lockstats.RemoveLockedTables(exec, tids, pids, tables)
}

// QueryTablesLockedStatuses query whether table is locked.
// Note: This function query locked tables from store, so please try to batch the query.
func (h *Handle) QueryTablesLockedStatuses(tableIDs ...int64) (map[int64]bool, error) {
	tableLocked, err := h.queryLockedTables()
	if err != nil {
		return nil, err
	}

	return lockstats.GetTablesLockedStatuses(tableLocked, tableIDs...), nil
}

// queryLockedTables query locked tables from store.
func (h *Handle) queryLockedTables() (map[int64]struct{}, error) {
	se, err := h.pool.Get()
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer h.pool.Put(se)

	exec := se.(sqlexec.RestrictedSQLExecutor)
	return lockstats.QueryLockedTables(exec)
}

But I can try it recently to see if this helps. Do you have any suggestions on where to put the `statsLocker/statsUnlocker/statsQuerier'?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then in the feature, we can break the huge StatsHandler down to multiple smaller sub-components.
This makes our code easier to maintain (maintaining multiple smaller and simpler components is better than maintaining a big and complex component).
And these sub-components rely on the storage to synchronize information instead of relying on memory status, which is much safer.

image

@@ -25,16 +25,22 @@ import (
"go.uber.org/zap"
)

var (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we can use const for these strings.

@ti-chi-bot
Copy link

ti-chi-bot bot commented Sep 5, 2023

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: hawkingrei, time-and-fate

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [hawkingrei,time-and-fate]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Sep 5, 2023
@ti-chi-bot
Copy link

ti-chi-bot bot commented Sep 5, 2023

[LGTM Timeline notifier]

Timeline:

  • 2023-09-04 03:38:36.11701143 +0000 UTC m=+2330280.666027412: ☑️ agreed by hawkingrei.
  • 2023-09-05 10:10:36.104231343 +0000 UTC m=+2440200.653247315: ☑️ agreed by time-and-fate.

@ti-chi-bot ti-chi-bot bot merged commit d8dbc4f into pingcap:master Sep 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved lgtm release-note-none Denotes a PR that doesn't merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants