Skip to content

Commit

Permalink
[#23120] YSQL: Do not wait for a safe snapshot in serializable read o…
Browse files Browse the repository at this point in the history
…nly deferrable mode.

Summary:
PostgreSQL uses SSI to implement serializable isolation level. Read only serializable isolation transactions may abort other
serializable transactions by creating a cycle in the transaction dependency graph. This can be avoided by waiting for all
concurrent transactions to finish by using the READ ONLY DEFERRABLE mode.

On the other hand, YugabyteDB does not use SSI for serializable transactions and uses 2-phase
locking instead. And YB assigns a different meaning to the DEFERRABLE mode for READ ONLY
serializable transactions as compared to Pg. In YB, DEFERRABLE READ ONLY transactions wait
out the maximum possible clock skew to avoid read restart errors (see https://docs.yugabyte.com/preview/architecture/transactions/read-restart-error/).
So, in YB's use of DEFERRABLE, there is no need to wait for concurrent transactions to complete, apart from waiting out the max_clock_skew_usec.
Jira: DB-12053

Test Plan:
Jenkins

```
./yb_build.sh --java-test TestPgRegressWaitQueues
```

There are tests already in modify-transaction-characteristics that use a read only deferrable transaction for a select statement. Modified the test output to remove waiting.

Reviewers: pjain, bkolagani, smishra

Reviewed By: pjain

Subscribers: yql

Differential Revision: https://phorge.dev.yugabyte.com/D36671
  • Loading branch information
pao214 committed Jul 18, 2024
1 parent 4af129f commit a64fbfc
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 49 deletions.
24 changes: 23 additions & 1 deletion src/postgres/src/backend/storage/lmgr/predicate.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@
#include "utils/snapmgr.h"
#include "utils/tqual.h"

#include "pg_yb_utils.h"

/* Uncomment the next line to test the graceful degradation code. */
/* #define TEST_OLDSERXID */

Expand Down Expand Up @@ -1608,8 +1610,28 @@ GetSerializableTransactionSnapshot(Snapshot snapshot)
* A special optimization is available for SERIALIZABLE READ ONLY
* DEFERRABLE transactions -- we can wait for a suitable snapshot and
* thereby avoid all SSI overhead once it's running.
*
* YB: PG uses SSI to implement serializable isolation level.
* YB uses 2PL (i.e., two phase locking) for the same.
* Both YB and PG expose a different functionality using
* the same DEFERRABLE keyword.
*
* In PG, READ ONLY DEFERRABLE allows a read only transaction
* to avoid serialization errors with concurrent serializable
* transactions, by waiting for the concurrent transactions to
* complete first.
*
* In YB, there is no cycle detection algorithm. Instead READ ONLY
* serializable transactions are essentially equivalent to a
* READ ONLY snapshot isolation transaction (see #23213).
* YB uses DEFERRABLE to allow READ ONLY transactions to wait out
* the maximum possible clock skew (i.e., max_clock_skew_usec)
* so as to avoid read restart errors.
*
* Given this difference, YB need not wait for a safe snapshot
* i.e., concurrent transactions need not be waited for.
*/
if (XactReadOnly && XactDeferrable)
if (!YBTransactionsEnabled() && XactReadOnly && XactDeferrable)
return GetSafeSnapshot(snapshot);

return GetSerializableTransactionSnapshotInt(snapshot,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,12 +507,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_rc_method2 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -522,12 +521,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_rc_method3_part1 s2_method3_part2 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -538,12 +536,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_rc_method4 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -553,12 +550,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_rr_method1 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -568,12 +564,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_rr_method2 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -583,12 +578,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_rr_method3_part1 s2_method3_part2 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -599,12 +593,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_rr_method4 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -614,12 +607,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_sr_method1 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -629,12 +621,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_sr_method2 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -644,12 +635,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_sr_method3_part1 s2_method3_part2 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -660,12 +650,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s2_begin_sr_method4 s2_switch_to_sr s2_read_only s2_deferrable s1_begin_sr_method1 s1_update s2_select s1_commit s2_commit
Expand All @@ -675,12 +664,11 @@ step s2_read_only: SET TRANSACTION READ ONLY;
step s2_deferrable: SET TRANSACTION DEFERRABLE;
step s1_begin_sr_method1: BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
step s1_update: UPDATE test SET v=v+1 WHERE k=1;
step s2_select: SELECT * FROM test; <waiting ...>
step s1_commit: COMMIT;
step s2_select: <... completed>
step s2_select: SELECT * FROM test;
k v

1 3
1 2
step s1_commit: COMMIT;
step s2_commit: COMMIT;

starting permutation: s1_begin_rc_method1 s1_switch_to_sr s1_read_only s1_read_write s2_update s1_commit
Expand Down

0 comments on commit a64fbfc

Please sign in to comment.