When are locks released in Postgres - postgresql

I have some problems understanding locks. Naturally locks are released when everything goes smoothly. But I'm unsure on the exact logic for when locks are released, when things break down. How long a lock can persist? Can I kill all processes and thereby release all locks? Do I have to explicitly call rollback?

In general locks are released when transaction ends with COMMIT or ROLLBACK.
There are exceptions:
Once acquired, a lock is normally held till end of transaction. But if
a lock is acquired after establishing a savepoint, the lock is
released immediately if the savepoint is rolled back to. This is
consistent with the principle that ROLLBACK cancels all effects of the
commands since the savepoint. The same holds for locks acquired within
a PL/pgSQL exception block: an error escape from the block releases
locks acquired within it.
2.
There are two ways to acquire an advisory lock in PostgreSQL: at
session level or at transaction level. Once acquired at session level,
an advisory lock is held until explicitly released or the session
ends.
Killing backend processes should release the locks but should be not the right way to release the locks: it should only be used as last resort if you cannot end the client application in a clean way.

Related

maxTransactionLockRequestTimeoutMillis with concurrent transactions

I'm trying to get a better understanding of the lock acquisition behavior on MongoDB transactions. I have a scenario where two concurrent transactions try to modify the same document. Since one transaction will get the write lock on the document first, the second transaction will run into a write conflict and fail.
I stumbled upon the maxTransactionLockRequestTimeoutMillis setting as documented here: https://docs.mongodb.com/manual/reference/parameters/#param.maxTransactionLockRequestTimeoutMillis and it states:
The maximum amount of time in milliseconds that multi-document transactions should wait to acquire locks required by the operations in the transaction.
However, changing this value does not seem to have an impact on the observed behavior with a write conflict. Transaction 2 does not seem to wait for the lock to be released again but immediately runs into a write conflict when another transaction holds the lock (other than concurrent writes outside a transaction which will block and wait for the lock).
Do I understand correctly that the configured time in maxTransactionLockRequestTimeoutMillis does not include the act of actually receiving the write lock on the document or is there something wrong with my tests?

Debug long running 'RELEASE SAVEPOINT <savepoint_name>'

I have a savepoint which has been running for almost 24 hrs now. Its causing other issues like long running queries which refreshes materialized view concurrently.
Is there a way to know which query is causing the RELEASE SAVEPOINT <savepoint-name> to be in idle in transaction. Is it safe to use SELECT pg_cancel_backend(__pid__); against its pid?
If the session is “idle in transaction”, it is not running.
What you see in pg_stat_activity is the last statement executed in that session.
There is a bug in your application that causes a transaction to remain open, and the locks that are held by this transmission can block concurrent sessions.

When is lock from pg_try_advisory_xact_lock released exactly?

pg_try_advisory_xact_lock works the same as pg_try_advisory_lock, except the lock, if acquired, is automatically released at the end of the current transaction and cannot be released explicitly.
Does that mean the lock is released immediately before transaction is committed and visible to other processes or immediately after the transaction is committed?
I wanted to know if there is a potential for a very small race condition if I query in a 2nd transaction for data from 1st transaction OR is lock obtained in 1st transaction and not get any of them?

Is it possible that both transactions rollback during a deadlock or serialization error?

In PostgreSQL (and other MVCC databases), transactions can rollback due to a deadlock or serialization error. Assume two transactions are currently running, is it ever possible that both, instead of just one, transaction will fail due to this kind of errors?
The reason why I am asking is that I am writing a retry implementation. If both transactions can fail, we might end up in a never-ending loop of retries if both retry immediately. If only one transaction can fail, I don't see any harm in retrying as soon as possible.
Yes. A deadlock can involve more than two transactions. In this case more than one may be terminated. But this is an extremely rare condition. Normally.
If just two transactions deadlock, one survives. The manual:
PostgreSQL automatically detects deadlock situations and resolves them by aborting one of the transactions involved, allowing the other(s) to complete.
Serialization failures only happen in REPEATABLE READ or SERIALIZABLE transaction isolation. I wouldn't know of any particular limit to how many serialization failures can happen concurrently. But I also never heard of any necessity to delay retrying.
I would retry as soon as possible either way.

PostgreSQL advisory locks are not working with Doctrine's DBAL

I'm experiencing a very strange behavior when trying to use advisory locks in Doctrine's DBAL.
I have a Symfony 2 application in which I want to obtain an advisory lock for some entity. I'm making the following query to obtain the lock:
SELECT pg_try_advisory_lock(83049, 5)
Via the following code in PHP:
/** #var Doctrine\DBAL\Connection */
protected $connection;
public function lock()
{
return $this->connection->fetchColumn(
"SELECT pg_try_advisory_lock({$this->getTableOid()}, {$this->entity->getLockingId()})"
);
}
I've created the following script to test the concurrency:
// Obtaining the lock.
$locker->lock();
// Doing something for ten seconds.
sleep(10);
However, when I run it concurrently, it looks like every instance is successfully getting the lock. Also, after request is terminated, it looks like lock is automatically released, even when I've not called unlock().
Why it behaving that way?
Does doctrine use single connection for all requests?
Does doctrine releases the locks automatically after script is terminated?
13.3.4. Advisory Locks
PostgreSQL provides a means for creating locks that have
application-defined meanings. These are called advisory locks, because
the system does not enforce their use — it is up to the application to
use them correctly. Advisory locks can be useful for locking
strategies that are an awkward fit for the MVCC model. For example, a
common use of advisory locks is to emulate pessimistic locking
strategies typical of so-called "flat file" data management systems.
While a flag stored in a table could be used for the same purpose,
advisory locks are faster, avoid table bloat, and are automatically
cleaned up by the server at the end of the session.
There are two ways to acquire an advisory lock in PostgreSQL: at
session level or at transaction level. Once acquired at session level,
an advisory lock is held until explicitly released or the session
ends. Unlike standard lock requests, session-level advisory lock
requests do not honor transaction semantics: a lock acquired during a
transaction that is later rolled back will still be held following the
rollback, and likewise an unlock is effective even if the calling
transaction fails later. A lock can be acquired multiple times by its
owning process; for each completed lock request there must be a
corresponding unlock request before the lock is actually released.
Transaction-level lock requests, on the other hand, behave more like
regular lock requests: they are automatically released at the end of
the transaction, and there is no explicit unlock operation. This
behavior is often more convenient than the session-level behavior for
short-term usage of an advisory lock. Session-level and
transaction-level lock requests for the same advisory lock identifier
will block each other in the expected way. If a session already holds
a given advisory lock, additional requests by it will always succeed,
even if other sessions are awaiting the lock; this statement is true
regardless of whether the existing lock hold and new request are at
session level or transaction level.
http://www.postgresql.org/docs/9.1/static/explicit-locking.html