Search code examples
javapostgresqldeadlockdatabase-deadlocks

Deadlock when using delete on postgresql


I'm using postgres. I write code in java. Made a thread pool which periodically deletes rows from the database (deleteJobPeriodMs = 10 seconds):

long DELETEJOBPERIOD_MS_DEFAULT = 10000;
long deleteJobPeriodMs = userVariableDeleteJobPeriod.haveVariable()? deleteJobPeriodMsVar.getVariable(): DELETEJOBPERIOD_MS_DEFAULT;
executorService = new ScheduledThreadPoolExecutor(coreThreadsCount, this::createDeleteJobThread);
executorService.scheduleAtFixedRate(this::deleteMethod, 0, 
deleteJobPeriodMs, TimeUnit.MILLISECONDS);

The deleteMethod uses the following request: DELETE FROM field WHERE delete_date < ?

At the same time, new entries are constantly being added to the program that require further deletion. No other operations are performed. Deadlock occurs about 5-10 times per hour of operation. Here's what I get in the logs:

2021-05-22 00:16:01 MSK [117890]: [1-1] ERROR:  deadlock detected
2021-05-22 00:16:01 MSK [117890]: [2-1] DETAIL:  Process 117890 waits for 
AccessExclusiveLock on tuple (17724,12) of relation 471906 of database 471895; 
blocked by process 116805.
    Process 116805 waits for ShareLock on transaction 1923461368; blocked by process 115793.
    Process 115793 waits for ShareLock on transaction 1923460316; blocked by process 109269.
    Process 109269 waits for ShareLock on transaction 1923457105; blocked by process 117890.
    Process 117890: DELETE FROM field WHERE delete_date < $1
    Process 116805: DELETE FROM field WHERE delete_date < $1
    Process 115793: DELETE FROM field WHERE delete_date < $1
    Process 109269: DELETE FROM field WHERE delete_date < $1
2021-05-22 00:16:01 MSK [117890]: [3-1] HINT:  See server log for query details.
2021-05-22 00:16:01 MSK [117890]: [4-1] STATEMENT:  DELETE FROM jobs WHERE delete_date < $1

Part of one of the stacktrace:

Exception: operation: DeleteService.onDeleteFields, cause:
org.postgresql.util.PSQLException: ERROR: deadlock detected
  Detail: Process 127116 waits for ShareLock on transaction 1610026614; blocked by process 6433.
Process 6433 waits for ShareLock on transaction 1610014636; blocked by process 5957.
Process 5957 waits for AccessExclusiveLock on tuple (3,5) of relation 471906 of database 471895; blocked by process 127116.
  Hint: See server log for query details.
  Where: while deleting tuple (3,5) in relation "field"
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306)
    at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
    at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
    at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155)
    at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:132)
    at jdk.internal.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.postgresql.ds.PGPooledConnection$StatementHandler.invoke(PGPooledConnection.java:428)
    at com.sun.proxy.$Proxy7.executeUpdate(Unknown Source)

it is important to note that several of these applications are deployed on the same database


Solution

  • Changed the request from DELETE FROM field WHERE delete_date < ? to DELETE FROM JOBS WHERE fid IN (SELECT fid FROM JOBS WHERE delete_date < ? FOR UPDATE SKIP LOCKED). At the moment, the error does not occur.