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

[YSQL] Snapshot isolation [FOR] SHARE row locks conflict #2842

Closed
jaki opened this issue Nov 5, 2019 · 2 comments
Closed

[YSQL] Snapshot isolation [FOR] SHARE row locks conflict #2842

jaki opened this issue Nov 5, 2019 · 2 comments
Assignees
Labels
area/ysql Yugabyte SQL (YSQL) kind/bug This issue is a bug priority/high High Priority

Comments

@jaki
Copy link
Contributor

jaki commented Nov 5, 2019

The row locks SHARE and KEY SHARE should not conflict. However, they often do in snapshot isolation. They may also conflict in serializable isolation, but I have not tested them thoroughly.

Session A Session B
CREATE TABLE t (<schema>)
INSERT INTO t VALUES (1), (2), (3)
BEGIN ISOLATION LEVEL REPEATABLE READ
SELECT '(setting read point)'
BEGIN ISOLATION LEVEL REPEATABLE READ
SELECT '(setting read point)'
<stmt1>
<stmt2>
COMMIT
COMMIT
<schema> <stmt1> <stmt2> PostgreSQL 11 Yugabyte
i int PRIMARY KEY SELECT * FROM t FOR <lock> SELECT * FROM t FOR <lock> success first COMMIT fails
i int PRIMARY KEY SELECT * FROM t WHERE i = 1 FOR <lock> SELECT * FROM t WHERE i = 2 FOR <lock> success success
i int PRIMARY KEY SELECT * FROM t WHERE i = 2 FOR <lock> SELECT * FROM t WHERE i = 2 FOR <lock> success <stmt2> fails OR first COMMIT fails
i int SELECT * FROM t FOR <lock> SELECT * FROM t FOR <lock> success first COMMIT fails
i int SELECT * FROM t WHERE i = 1 FOR <lock> SELECT * FROM t WHERE i = 2 FOR <lock> success <stmt2> fails OR first COMMIT fails
i int SELECT * FROM t WHERE i = 2 FOR <lock> SELECT * FROM t WHERE i = 2 FOR <lock> success <stmt2> fails OR first COMMIT fails

Behavior should be the same between the locks SHARE and KEY SHARE.

Failure on <stmt2> is of the following form:

ERROR:  Operation failed. Try again.: b9c713c2-32fd-4f2d-97a6-14ef5f3c3ed8 Conflicts with higher priority transaction: efbc2bd1-14be-470b-8436-c2e1511df4f6

Failure on the first COMMIT is of the following form:

ERROR:  Error during commit: Operation expired: Transaction expired: 25P02
@kmuthukk
Copy link
Collaborator

kmuthukk commented Nov 19, 2019

This is another test case for the related issue (based on an issue reported by Konstantin in slack).

https://gist.github.com/kmuthukk/0778609b63b2468a4446c2fafe9bfe07

Use of references (FK) in snapshot isolation (REPEATABLE READ) causes above test to run into two kinds of errors:

Error during commit: Operation expired: Transaction expired: 25P02

and

Unexpected exception: Operation failed. Try again.: c1f51af9-5811-4086-816f-966d2a7b4a6c Conflicts with committed transaction: eedae21d-719a-403e-a08c-8443cfd43238
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."table1" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR KEY SHARE OF x"

Current workaround is to change:

conn.set_session(autocommit=True, isolation_level="REPEATABLE READ")
to:
conn.set_session(autocommit=True, isolation_level="SERIALIZABLE")
But once this fix lands, this should be not be required.

@jaki
Copy link
Contributor Author

jaki commented Nov 19, 2019

For people waiting, this is in progress, and I am trying to land it as soon as I can. I hope to do so within 24 hours. There are some broken regression tests that I need to investigate.

jaki pushed a commit that referenced this issue Nov 20, 2019
Summary:
Enable `FOR UPDATE` and `FOR NO KEY UPDATE` row locking statements with
the caveat that `FOR NO KEY UPDATE` behaves like `FOR UPDATE` (see
follow-up issue #2922).  Also, fix conflict detection such that `FOR
SHARE` locks do not conflict with each other.

Implement the fix as follows:

1. Pass down `FOR UPDATE` and `FOR NO KEY UPDATE` row locks through
   Protobufs.

   1. Pass them through `PgsqlReadRequestPB.row_mark_type`.  (Also,
      change the field from `repeated` to `optional`.)
   1. Pass them through `KeyValueWriteBatchPB.row_mark_type`.  (Also,
      change the field from `repeated` to `optional`.)

1. Add a row lock parameter to `docdb::GetStrongIntentTypeSet`, and
   permeate row lock information throughout the affected areas (fix
   issue #2842).  Remove the isolation level hack in
   `tablet::Tablet::PrepareTransactionWriteBatch` in favor of using row
   lock information (fix issue #2496).
1. Create a new value type `kRowLock` to be placed in the value of
   intents for row locking.  Handle this value type in
   `docdb::(anonymous namespace)::DecodeStrongWriteIntent` (for
   in-transaction reads) and `docdb::IntentToWriteRequest` (for
   transaction commits).
1. Create tests, specified in the test plan.

Also, do the following:

* Create new files defining helper functions related to row locks (row
  marks).

  * `src/yb/common/row_mark.cc`
  * `src/yb/common/row_mark.h`

* Prevent `ROW_MARK_REFERENCE` and `ROW_MARK_COPY` from getting passed
  down as the `rowmark` execution parameter.
* Update regress test `yb_pg_privileges` (java test
  `TestPgRegressAuthorization`) to uncomment `FOR UPDATE` row locking
  statements.

Test Plan:
* Jenkins
* `./yb_build.sh`

  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.RowLockConflictMatrix`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SerializableDeleteForNoKeyUpdate`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SerializableDeleteForUpdate`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SerializableInsertForNoKeyUpdate`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SerializableInsertForUpdate`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SnapshotDeleteForNoKeyUpdate`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SnapshotDeleteForUpdate`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SnapshotInsertForNoKeyUpdate`
  * `--cxx-test pgwrapper_pg_mini-test --gtest_filter
    PgMiniTest.SnapshotInsertForUpdate`

Reviewers: hector, sergei, mikhail

Reviewed By: mikhail

Subscribers: yql, bogdan

Differential Revision: https://phabricator.dev.yugabyte.com/D7453
@jaki jaki closed this as completed Nov 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/ysql Yugabyte SQL (YSQL) kind/bug This issue is a bug priority/high High Priority
Projects
None yet
Development

No branches or pull requests

2 participants