Skip to content

Pessimistic Lock

Yilin Chen edited this page Dec 14, 2021 · 2 revisions

Pessimistic Lock

Pessimistic locks are supported to lock keys during the execution of a transaction.

Using pessimistic locks makes it cheaper to handle write conflicts by only retrying locking the conflicted keys instead of retrying the whole transaction.

Begin

Pessimistic locks can be only used in a pessimistic transaction. You have to explicitly set a transaction to be a pessimistic transaction before locking any key:

txn, err := client.Begin()
if err != nil {
	// handle error
}
txn.SetPessimistic(true)

Lock keys

After beginning a transaction, you can lock keys with LockKeysWithWaitTime. For example:

err := txn.LockKeysWithWaitTime(context.Background(), kv.LockAlwaysWait, []byte("k1"), []byte("k2"))

If the key you want to lock has already been locked, this method will wait until the lock is released, or it reaches the timeout specified by the second parameter. LockAlwaysWait means no limit. LockNoWait means the method will fail immediately as long as it encounters any existing lock.

If the method above returns an ErrLockWaitTimeout or an ErrLockAcquireFailAndNoWaitSet, it means the lock is still held by another transaction. If an ErrWriteConflict is returned, it just shows that the key to be locked is just modified by another transaction. On these errors, you probably want to retry locking.

Notice for writing

To write any key in a pessimistic transaction, you should lock the key before doing Set or Delete operations.

err := txn.LockKeysWithWaitTime(context.Background(), kv.LockAlwaysWait, []byte("k1"), []byte("k2"))
if err != nil {
	// handle error
}
txn.Set([]byte("k1"), []byte("v1"))
txn.Delete([]byte("k2"))
err = txn.Commit()

If you modify a key in a pessimistic transaction without locking it, consistency is not guaranteed for this key.