Commit 49f1b8c
committed
[yugabyte#24431] YSQL: Supplement read restart error with more info
Summary:
### Motivation
Read restart errors are a common occurence in YugabyteDB.
Mitigation strategy varies case-by-case. Well known approaches:
1. Use READ COMMITTED isolation level. A popular mitigation strategy.
2. Increase ysql_output_buffer_size. This is applicable for large SELECTs that have a low read restart rate.
3. Use the deferrable mode. This is for background tasks that scan a lot of rows.
4. Leverage time sync service. Best option but still early.
However, these mitigitation strategies do not always work. Such cases require addressing the underlying problem. Currently, the logs lack sufficient detail, leading to speculation rather than concrete diagnosis.
### Examples
#### Running CREATE/DROP TEMP TABLE concurrently results in a read restart error
```
2025-04-04 01:57:32.353 UTC [587443] ERROR: Restart read required at: read: { days: 20182 time: 01:57:32.350502 } local_limit: { days: 20182 time: 01:57:32.350502 } global_limit: <min> in_txn_limit: <max> serial_no: 0 } (yb_max_query_layer_retries set to 0 are exhausted)
```
Users do not expect this error because TEMP TABLEs are local to each pg backend. Moreover, increasing ysql_output_buffer_size does not mitigate the error here because read restart errors on DDLs cannot be retried yet. That said, users find it helpful to understand the root cause of the error. After this revision, the log becomes
```
2025-04-04 01:57:32.353 UTC [587443] DETAIL: restart_read_time: { read: { days: 20182 time: 01:57:32.350502 } local_limit: { days: 20182 time: 01:57:32.350502 } global_limit: <min> in_txn_limit: <max> serial_no: 0 }, original_read_time: { read: { days: 20182 time: 01:57:32.096749 } local_limit: { days: 20182 time: 01:57:32.098414 } global_limit: { days: 20182 time: 01:57:32.596749 } in_txn_limit: <max> serial_no: 0 }, table: template1.pg_yb_invalidation_messages [ysql_schema=pg_catalog] [00000001000030008001000000001f90], tablet: 00000000000000000000000000000000, leader_uuid: f1ac558309244cbab385761b531980f0, key: SubDocKey(DocKey(CoTableId=901f0000-0000-0180-0030-000001000000, [], [13515, 10]), [SystemColumnId(0)]), start_time: 2025-04-04 01:57:32.094965+00
```
**Cause:** The read restart error is returned when accessing the `pg_yb_invalidation_messages` table in the above example.
**Mitigation:** Avoid creating TEMP TABLEs from mutliple sessions concurrently. Note: The issue is fixed by table-level locking.
#### CREATE INDEX NONCONCURRENTLY
CREATE INDEX NONCONCURRENTLY accesses both the user table as well as syscatalog. How can the user identify whether the read restart error occurred due to a concurrent DDL or DML?
```
[ts-1] 2025-04-04 04:25:47.694 UTC [665450] DETAIL: restart_read_time: { read: { days: 20182 time: 04:25:47.512991 } local_limit: { days: 20182 time: 04:25:47.512991 } global_limit: <min> in_txn_limit: <max> serial_no: 0 }, original_read_time: { read: { days: 20182 time: 04:25:47.012991 } local_limit: { days: 20182 time: 04:25:47.512991 } global_limit: { days: 20182 time: 04:25:47.512991 } in_txn_limit: <max> serial_no: 0 }, table: yugabyte.test_table [ysql_schema=public] [000034cb000030008000000000004000], tablet: bf9d2bf8908b43d4b8b5ff75b169bf11, leader_uuid: 6d60cea932ca41498fee5ad07c375d18, key: SubDocKey(DocKey(0x0a73, [5], []), [ColumnId(1)])
```
**Cause:** In the above log, the error occurs on the user table.
**Mitigation:** Stop concurrent writes when creating the INDEX.
The read restart can also be on a catalog table. Example:
```
[ts-1] 2025-04-04 02:17:48.392 UTC [592811] DETAIL: restart_read_time: { read: { days: 20182 time: 02:17:48.326938 } local_limit: { days: 20182 time: 02:17:48.326938 } global_limit: <min> in_txn_limit: <max> serial_no: 0 }, original_read_time: { read: { days: 20182 time: 02:17:48.023542 } local_limit: { days: 20182 time: 02:17:48.024082 } global_limit: { days: 20182 time: 02:17:48.523542 } in_txn_limit: <max> serial_no: 0 }, table: yugabyte.pg_attribute [ysql_schema=pg_catalog] [000034cb0000300080010000000004e1], tablet: 00000000000000000000000000000000, leader_uuid: e941d4ee43bc40a8b4303eab317f52fd, key: SubDocKey(DocKey(CoTableId=e1040000-0000-0180-0030-0000cb340000, [], [16384, 5]), []), start_time: 2025-04-04 02:17:48.022154+00
[ts-1] 2025-04-04 02:17:48.392 UTC [592811] STATEMENT: CREATE INDEX NONCONCURRENTLY non_concurrent_idx_0 ON test_table(key)
```
#### Read restarts on absent keys
Users sometimes report that they notice read restart errors even though they are no conflicting keys. To better observe such scenarios, print a key on which read restart error occurred. There can be multiple such keys, so we print the first one we encounter.
Here's an example fixed by yugabyte#25214.
Setup
```
CREATE TABLE keys(k1 INT, k2 INT, PRIMARY KEY(k1 ASC, k2 ASC));
INSERT INTO keys(k1, k2) VALUES (1, 1);
```
The following query
```
INSERT INTO keys(k1, k2) VALUES (0, 0), (9, 9) ON CONFLICT DO NOTHING
```
results in a read restart error even though none of 0 or 9 conflict with 1.
```
2025-04-04 17:55:03.013 UTC [955800] DETAIL: restart_read_time: { read: { days: 20182 time: 17:55:03.012147 } local_limit: { days: 20182 time: 17:55:03.012147 } global_limit: <min> in_txn_limit: <max> serial_no: 0 }, original_read_time: { read: { days: 20182 time: 17:55:02.983152 } local_limit: { days: 20182 time: 17:55:03.483152 } global_limit: { days: 20182 time: 17:55:03.483152 } in_txn_limit: { days: 20182 time: 17:55:03.011777 } serial_no: 0 }, table: yugabyte.keys [ysql_schema=public] [000034cb000030008000000000004000], tablet: 2a19ede71f7e4389b1ca682e87318b32, leader_uuid: 7010bbec8ec94110b5e2316bca5319f4, key: SubDocKey(DocKey([], [1, 1]), [SystemColumnId(0)]), start_time: 2025-04-04 17:55:03.010743+00
```
This helps us understand where the read restart error occurred. It occurs on key = (1, 1), not relevant to the INSERT ON CONFLICT statement. The key field helps diagnose such scenarios.
**Mitigation:** See 1bcb09c for the fix.
#### Local Limit Fixes
Commits d67ba12 and 02ced43 fix some bugs with the local llimit mechanism. Identifying the value of local limit when the issue occurs is fairly straightforward. The error message has local limit.
```
[ts-1] 2025-04-04 02:17:48.392 UTC [592811] DETAIL: restart_read_time: { read: { days: 20182 time: 02:17:48.326938 } local_limit: { days: 20182 time: 02:17:48.326938 } global_limit: <min> in_txn_limit: <max> serial_no: 0 }, original_read_time: { read: { days: 20182 time: 02:17:48.023542 } local_limit: { days: 20182 time: 02:17:48.024082 } global_limit: { days: 20182 time: 02:17:48.523542 } in_txn_limit: <max> serial_no: 0 }, table: yugabyte.pg_attribute [ysql_schema=pg_catalog] [000034cb0000300080010000000004e1], tablet: 00000000000000000000000000000000, leader_uuid: e941d4ee43bc40a8b4303eab317f52fd, key: SubDocKey(DocKey(CoTableId=e1040000-0000-0180-0030-0000cb340000, [], [16384, 5]), []), start_time: 2025-04-04 02:17:48.022154+00
[ts-1] 2025-04-04 02:17:48.392 UTC [592811] STATEMENT: CREATE INDEX NONCONCURRENTLY non_concurrent_idx_0 ON test_table(key)
```
#### pg_partman faces read restart errors
pg_partman faces a read restart error on max query
```
ERROR: Restart read required at: { read: { physical: 1730622229379200 } local_limit: { physical: 1730622229379200 } global_limit: <min> in_txn_limit: <max> serial_no: 0 }
CONTEXT: SQL statement "SELECT max(id)::text FROM public.t1_p100000"
```
**Cause:** This is because there is no range index on the tablet 1_p100000 to retrieve the max value efficiently using the index.
A log such as
```
2025-04-04 18:55:31.936 UTC [963409] DETAIL: restart_read_time: { read: { days: 20182 time: 18:55:31.934321 } local_limit: { days: 20182 time: 18:55:31.934321 } global_limit: <min> in_txn_limit: <max> serial_no: 0 }, original_read_time: { days: 20182 time: 18:55:31.738805 }, table: yugabyte.tokens_idx [ysql_schema=public] [000034cb000030008000000000004003], tablet: {tokens_idx_tablet_id1}, leader_uuid: {ts2_peer_id}, key: SubDocKey(DocKey([], [300, "G%\xf8S\xde\xb0h\xe6)\xa3G0\x96\xae\x9e9\xf7r\xbe\xc3\x00\x00!!"]), [SystemColumnId(0)]), start_time: 2025-04-04 18:55:31.933012+00
```
informs us the table on which the read restart error occurred. If the table is an index such as tokens_idx, the query is using an index scan.
**Upgrade/Rollback safety:**
Adds a new key restart_read_key to tserver.proto. The key is marked optional. When absent an empty value is printed in its stead.
Jira: DB-13338
Test Plan:
Jenkins
Backport-through: 2024.2
Reviewers: smishra, pjain
Reviewed By: pjain
Subscribers: yql
Differential Revision: https://phorge.dev.yugabyte.com/D428831 parent 58c2f45 commit 49f1b8c
File tree
41 files changed
+258
-113
lines changed- docs/content/preview/architecture/transactions
- src
- postgres/src
- backend/utils
- error
- misc
- include
- utils
- yb
- client
- common
- docdb
- master
- tablet
- tools
- tserver
- yql/pgwrapper
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
41 files changed
+258
-113
lines changedLines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
| 27 | + | |
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4624 | 4624 | | |
4625 | 4625 | | |
4626 | 4626 | | |
| 4627 | + | |
| 4628 | + | |
| 4629 | + | |
| 4630 | + | |
| 4631 | + | |
| 4632 | + | |
| 4633 | + | |
| 4634 | + | |
| 4635 | + | |
| 4636 | + | |
| 4637 | + | |
| 4638 | + | |
| 4639 | + | |
| 4640 | + | |
| 4641 | + | |
| 4642 | + | |
| 4643 | + | |
| 4644 | + | |
| 4645 | + | |
| 4646 | + | |
| 4647 | + | |
4627 | 4648 | | |
4628 | 4649 | | |
4629 | 4650 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
857 | 857 | | |
858 | 858 | | |
859 | 859 | | |
860 | | - | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
861 | 864 | | |
862 | 865 | | |
863 | 866 | | |
| |||
871 | 874 | | |
872 | 875 | | |
873 | 876 | | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
874 | 880 | | |
875 | 881 | | |
876 | 882 | | |
| |||
891 | 897 | | |
892 | 898 | | |
893 | 899 | | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
894 | 930 | | |
895 | 931 | | |
896 | 932 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1160 | 1160 | | |
1161 | 1161 | | |
1162 | 1162 | | |
1163 | | - | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
1164 | 1167 | | |
1165 | 1168 | | |
1166 | 1169 | | |
| |||
1201 | 1204 | | |
1202 | 1205 | | |
1203 | 1206 | | |
| 1207 | + | |
1204 | 1208 | | |
1205 | 1209 | | |
| 1210 | + | |
1206 | 1211 | | |
1207 | 1212 | | |
| 1213 | + | |
1208 | 1214 | | |
1209 | 1215 | | |
1210 | 1216 | | |
1211 | | - | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
1212 | 1220 | | |
1213 | 1221 | | |
1214 | 1222 | | |
1215 | 1223 | | |
1216 | 1224 | | |
1217 | 1225 | | |
1218 | 1226 | | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
1219 | 1231 | | |
1220 | 1232 | | |
1221 | 1233 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
508 | 508 | | |
509 | 509 | | |
510 | 510 | | |
| 511 | + | |
511 | 512 | | |
512 | 513 | | |
513 | 514 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
471 | 471 | | |
472 | 472 | | |
473 | 473 | | |
| 474 | + | |
| 475 | + | |
474 | 476 | | |
475 | | - | |
| 477 | + | |
| 478 | + | |
476 | 479 | | |
477 | | - | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
478 | 489 | | |
479 | 490 | | |
480 | 491 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
| 91 | + | |
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
| |||
199 | 199 | | |
200 | 200 | | |
201 | 201 | | |
202 | | - | |
| 202 | + | |
| 203 | + | |
203 | 204 | | |
204 | 205 | | |
205 | 206 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
205 | 205 | | |
206 | 206 | | |
207 | 207 | | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
208 | 213 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
298 | 298 | | |
299 | 299 | | |
300 | 300 | | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
301 | 324 | | |
0 commit comments