Skip to content

Commit

Permalink
Change: Replace blocking table locks with a non-blocking retry loop
Browse files Browse the repository at this point in the history
  • Loading branch information
timopollmeier authored Oct 26, 2021
2 parents 3a68a9e + 1acc4e2 commit 44a054a
Showing 1 changed file with 58 additions and 11 deletions.
69 changes: 58 additions & 11 deletions src/manage_sql.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@
*/
#define G_LOG_DOMAIN "md manage"

/**
* @brief Number of retries for
* LOCK TABLE .. IN ACCESS EXLUSIVE MODE NOWAIT
* statements.
*/
#define LOCK_RETRIES 16

/**
* @brief Time of delay between two lock retries.
*/
#define LOCK_RETRY_DELAY 2

#ifdef DEBUG_FUNCTION_NAMES
#include <dlfcn.h>

Expand Down Expand Up @@ -24449,7 +24461,7 @@ int
delete_report (const char *report_id, int dummy)
{
report_t report;
int ret;
int ret, lock_ret, lock_retries;

sql_begin_immediate ();

Expand All @@ -24459,7 +24471,19 @@ delete_report (const char *report_id, int dummy)
*
* If the report is running already then delete_report_internal will
* ROLLBACK. */
sql ("LOCK table reports IN ACCESS EXCLUSIVE MODE;");
lock_retries = LOCK_RETRIES;
lock_ret = sql_int ("SELECT try_exclusive_lock('reports');");
while ((lock_ret == 0) && (lock_retries > 0))
{
sleep(LOCK_RETRY_DELAY);
lock_ret = sql_int ("SELECT try_exclusive_lock('reports');");
lock_retries--;
}
if (lock_ret == 0)
{
sql_rollback ();
return -1;
}

if (acl_user_may ("delete_report") == 0)
{
Expand Down Expand Up @@ -29287,7 +29311,7 @@ copy_task (const char* name, const char* comment, const char *task_id,
static int
delete_task_lock (task_t task, int ultimate)
{
int ret;
int ret, lock_ret, lock_retries;

g_debug (" delete task %llu", task);

Expand All @@ -29299,7 +29323,15 @@ delete_task_lock (task_t task, int ultimate)
*
* If the task is already active then delete_report (via delete_task)
* will fail and rollback. */
if (sql_error ("LOCK table reports IN ACCESS EXCLUSIVE MODE;"))
lock_retries = LOCK_RETRIES;
lock_ret = sql_int ("SELECT try_exclusive_lock('reports');");
while ((lock_ret == 0) && (lock_retries > 0))
{
sleep(LOCK_RETRY_DELAY);
lock_ret = sql_int ("SELECT try_exclusive_lock('reports');");
lock_retries--;
}
if (lock_ret == 0)
{
sql_rollback ();
return -1;
Expand Down Expand Up @@ -29388,6 +29420,7 @@ int
request_delete_task_uuid (const char *task_id, int ultimate)
{
task_t task = 0;
int lock_ret, lock_retries;

/* Tasks have special handling for the trashcan. Other resources have trash
* tables, like targets_trash. Tasks are marked as trash in the tasks table
Expand Down Expand Up @@ -29463,13 +29496,27 @@ request_delete_task_uuid (const char *task_id, int ultimate)
int ret;

if (ultimate)
/* This prevents other processes (for example a START_TASK) from
* getting a reference to a report ID or the task ID, and then using
* that reference to try access the deleted report or task.
*
* If the task is running already then delete_task will lead to
* ROLLBACK. */
sql ("LOCK table reports IN ACCESS EXCLUSIVE MODE;");
{
/* This prevents other processes (for example a START_TASK) from
* getting a reference to a report ID or the task ID, and then
* using that reference to try access the deleted report or task.
*
* If the task is running already then delete_task will lead to
* ROLLBACK. */
lock_retries = LOCK_RETRIES;
lock_ret = sql_int ("SELECT try_exclusive_lock('reports');");
while ((lock_ret == 0) && (lock_retries > 0))
{
sleep(LOCK_RETRY_DELAY);
lock_ret = sql_int ("SELECT try_exclusive_lock('reports');");
lock_retries--;
}
if (lock_ret == 0)
{
sql_rollback ();
return -1;
}
}

ret = delete_task (task, ultimate);
if (ret)
Expand Down

0 comments on commit 44a054a

Please sign in to comment.