Explicit Locking

Explicit Locking in YugabyteDB.

This section describes how explicit locking works in YugabyteDB.

YugabyteDB supports most row-level locks, similar to PostgreSQL. Explicit row-locks use transaction priorities to ensure that two transactions can never hold conflicting locks on the same row. To do this, the query layer acquires the row lock by assigning a very high value for the priority of the transaction that is being run. This causes all other transactions that conflict with the current transaction to fail, because they have a lower transaction priority.

Note

Explicit locking is an area of active development in YugabyteDB. A number of enhancements are planned in this area. Unlike PostgreSQL, YugabyteDB uses optimistic concurrency control and does not block / wait for currently held locks, instead opting to abort the conflicting transaction with a lower priority. Pessimistic concurrency control is currently under development.

The types of row locks currently supported are:

  • FOR UPDATE
  • FOR NO KEY UPDATE
  • FOR SHARE
  • FOR KEY SHARE

The following example uses the FOR UPDATE row lock. First, a row is selected for update, thereby locking it, and subsequently updated. A concurrent transaction should not be able to abort this transaction by updating the value of that row after the row is locked.

To try out this scenario, first create an example table with sample data, as follows:

yugabyte=# CREATE TABLE t (k VARCHAR, v VARCHAR);
yugabyte=# INSERT INTO t VALUES ('k1', 'v1');

Next, connect to the cluster using two independent ysqlsh instances. You can connect both session ysqlsh instances to the same server, or to different servers.

Begin a transaction in the first session, and perform a SELECT FOR UPDATE on the row in the table t. This locks the row for an update as a part of a transaction that has a very high priority.

yugabyte=# BEGIN;
BEGIN
yugabyte=# SELECT * from t WHERE k='k1' FOR UPDATE;
 k  | v
----+----
 k1 | v1
(1 row)

Before completing the transaction, try to update the same key in your other session using a simple update statement.

yugabyte=# UPDATE t SET v='v1.1' WHERE k='k1';
ERROR:  Operation failed. Try again. xxx Conflicts with higher priority transaction: yyy

This uses optimistic concurrency control, and fails.

If you used optimistic concurrency control instead of an explicit row-lock to do the first transaction, then this update would succeed in some of the attempts and the first transaction would fail in those cases.

Note

Blocking this transaction and retrying it after the other transaction completes is work in progress.

Finally, in the first session, update the row and commit the transaction. This should succeed.

yugabyte=# UPDATE t SET v='v1.2' WHERE k='k1';
UPDATE 1
yugabyte=# COMMIT;
COMMIT