This is an automated email from the ASF dual-hosted git repository.

jrgemignani pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git


The following commit(s) were added to refs/heads/master by this push:
     new 23cbe57a fix: remove pthread_mutex that causes self-deadlock on VLE 
queries (#2433)
23cbe57a is described below

commit 23cbe57a1eedee9167221a0359b09e538ff6fc87
Author: crdv7 <[email protected]>
AuthorDate: Wed Jun 10 01:44:15 2026 +0800

    fix: remove pthread_mutex that causes self-deadlock on VLE queries (#2433)
    
    The pthread_mutex in manage_GRAPH_global_contexts() causes permanent
    self-deadlock when ereport(ERROR) triggers siglongjmp while the mutex
    is held, skipping pthread_mutex_unlock(). Any subsequent VLE query on
    the same backend connection hangs forever in pthread_mutex_lock() with
    __owner == own PID.
    
    The mutex was introduced in PR #1881 (fix for issue #1878) but is
    unnecessary: it protects a process-local static variable in
    PostgreSQL's single-threaded backend model where no concurrent access
    exists. The actual fix for #1878 was the Assert-to-runtime-check
    conversion and strndup defensive copy, which remain untouched.
---
 src/backend/utils/adt/age_global_graph.c | 63 +++++++-------------------------
 1 file changed, 13 insertions(+), 50 deletions(-)

diff --git a/src/backend/utils/adt/age_global_graph.c 
b/src/backend/utils/adt/age_global_graph.c
index 1c4a4601..397e0511 100644
--- a/src/backend/utils/adt/age_global_graph.c
+++ b/src/backend/utils/adt/age_global_graph.c
@@ -45,7 +45,6 @@
 #include "catalog/ag_label.h"
 #include "utils/ag_cache.h"
 
-#include <pthread.h>
 
 /* defines */
 #define VERTEX_HTAB_NAME "Vertex to edge lists " /* added a space at end for */
@@ -152,18 +151,8 @@ typedef struct GRAPH_global_context
     struct GRAPH_global_context *next; /* next graph */
 } GRAPH_global_context;
 
-/* container for GRAPH_global_context and its mutex */
-typedef struct GRAPH_global_context_container
-{
-    /* head of the list */
-    GRAPH_global_context *contexts;
-
-    /* mutex to protect the list */
-    pthread_mutex_t mutex_lock;
-} GRAPH_global_context_container;
-
 /* global variable to hold the per process GRAPH global contexts */
-static GRAPH_global_context_container global_graph_contexts_container = {0};
+static GRAPH_global_context *global_graph_contexts = NULL;
 
 /*
  * VertexEdgeArray helpers — flat-array adjacency container used by
@@ -1054,12 +1043,10 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
      *     5) One or more other contexts do exist but, one or more are invalid.
      */
 
-    /* lock the global contexts list */
-    pthread_mutex_lock(&global_graph_contexts_container.mutex_lock);
 
     /* free the invalidated GRAPH global contexts first */
     prev_ggctx = NULL;
-    curr_ggctx = global_graph_contexts_container.contexts;
+    curr_ggctx = global_graph_contexts;
     while (curr_ggctx != NULL)
     {
         GRAPH_global_context *next_ggctx = curr_ggctx->next;
@@ -1076,7 +1063,7 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
              */
             if (prev_ggctx == NULL)
             {
-                global_graph_contexts_container.contexts = next_ggctx;
+                global_graph_contexts = next_ggctx;
             }
             else
             {
@@ -1089,8 +1076,6 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
             /* if it wasn't successfull, there was a missing vertex entry */
             if (!success)
             {
-                /* unlock the mutex so we don't get a deadlock */
-                
pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
                 ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
                                 errmsg("missing vertex or edge entry during 
free")));
@@ -1106,7 +1091,7 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
     }
 
     /* find our graph's context. if it exists, we are done */
-    curr_ggctx = global_graph_contexts_container.contexts;
+    curr_ggctx = global_graph_contexts;
     while (curr_ggctx != NULL)
     {
         if (curr_ggctx->graph_oid == graph_oid)
@@ -1114,8 +1099,6 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
             /* switch our context back */
             MemoryContextSwitchTo(oldctx);
 
-            /* we are done unlock the global contexts list */
-            pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
             return curr_ggctx;
         }
@@ -1125,9 +1108,9 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
     /* otherwise, we need to create one and possibly attach it */
     new_ggctx = palloc0(sizeof(GRAPH_global_context));
 
-    if (global_graph_contexts_container.contexts != NULL)
+    if (global_graph_contexts != NULL)
     {
-        new_ggctx->next = global_graph_contexts_container.contexts;
+        new_ggctx->next = global_graph_contexts;
     }
     else
     {
@@ -1135,7 +1118,7 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
     }
 
     /* set the global context variable */
-    global_graph_contexts_container.contexts = new_ggctx;
+    global_graph_contexts = new_ggctx;
 
     /* set the graph name and oid */
     new_ggctx->graph_name = pstrdup(graph_name);
@@ -1157,8 +1140,6 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
     load_GRAPH_global_hashtables(new_ggctx);
     freeze_GRAPH_global_hashtables(new_ggctx);
 
-    /* unlock the global contexts list */
-    pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
     /* switch back to the previous memory context */
     MemoryContextSwitchTo(oldctx);
@@ -1170,18 +1151,16 @@ GRAPH_global_context *manage_GRAPH_global_contexts(char 
*graph_name,
  * Helper function to delete all of the global graph contexts used by the
  * process. When done the global global_graph_contexts will be NULL.
  *
- * NOTE: Function uses a MUTEX global_graph_contexts_mutex
+ *
  */
 static bool delete_GRAPH_global_contexts(void)
 {
     GRAPH_global_context *curr_ggctx = NULL;
     bool retval = false;
 
-    /* lock contexts list */
-    pthread_mutex_lock(&global_graph_contexts_container.mutex_lock);
 
     /* get the first context, if any */
-    curr_ggctx = global_graph_contexts_container.contexts;
+    curr_ggctx = global_graph_contexts;
 
     /* free all GRAPH global contexts */
     while (curr_ggctx != NULL)
@@ -1195,8 +1174,6 @@ static bool delete_GRAPH_global_contexts(void)
         /* if it wasn't successfull, there was a missing vertex entry */
         if (!success)
         {
-            /* unlock the mutex so we don't get a deadlock */
-            pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
             ereport(ERROR, (errcode(ERRCODE_DATA_EXCEPTION),
                             errmsg("missing vertex or edge entry during 
free")));
@@ -1209,10 +1186,8 @@ static bool delete_GRAPH_global_contexts(void)
     }
 
     /* reset the head of the contexts to NULL */
-    global_graph_contexts_container.contexts = NULL;
+    global_graph_contexts = NULL;
 
-    /* unlock the global contexts list */
-    pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
     return retval;
 }
@@ -1235,11 +1210,9 @@ static bool delete_specific_GRAPH_global_contexts(char 
*graph_name)
     /* get the graph oid */
     graph_oid = get_graph_oid(graph_name);
 
-    /* lock the global contexts list */
-    pthread_mutex_lock(&global_graph_contexts_container.mutex_lock);
 
     /* get the first context, if any */
-    curr_ggctx = global_graph_contexts_container.contexts;
+    curr_ggctx = global_graph_contexts;
 
     /* find the specified GRAPH global context */
     while (curr_ggctx != NULL)
@@ -1256,7 +1229,7 @@ static bool delete_specific_GRAPH_global_contexts(char 
*graph_name)
              */
             if (prev_ggctx == NULL)
             {
-                global_graph_contexts_container.contexts = next_ggctx;
+                global_graph_contexts = next_ggctx;
             }
             else
             {
@@ -1266,8 +1239,6 @@ static bool delete_specific_GRAPH_global_contexts(char 
*graph_name)
             /* free the current graph context */
             success = free_specific_GRAPH_global_context(curr_ggctx);
 
-            /* unlock the global contexts list */
-            pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
             /* if it wasn't successfull, there was a missing vertex entry */
             if (!success)
@@ -1285,8 +1256,6 @@ static bool delete_specific_GRAPH_global_contexts(char 
*graph_name)
         curr_ggctx = next_ggctx;
     }
 
-    /* unlock the global contexts list */
-    pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
     /* we didn't find it, return false */
     return false;
@@ -1347,19 +1316,15 @@ GRAPH_global_context *find_GRAPH_global_context(Oid 
graph_oid)
 {
     GRAPH_global_context *ggctx = NULL;
 
-    /* lock the global contexts lists */
-    pthread_mutex_lock(&global_graph_contexts_container.mutex_lock);
 
     /* get the root */
-    ggctx = global_graph_contexts_container.contexts;
+    ggctx = global_graph_contexts;
 
     while(ggctx != NULL)
     {
         /* if we found it return it */
         if (ggctx->graph_oid == graph_oid)
         {
-            /* unlock the global contexts lists */
-            pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
             return ggctx;
         }
@@ -1368,8 +1333,6 @@ GRAPH_global_context *find_GRAPH_global_context(Oid 
graph_oid)
         ggctx = ggctx->next;
     }
 
-    /* unlock the global contexts lists */
-    pthread_mutex_unlock(&global_graph_contexts_container.mutex_lock);
 
     /* we did not find it so return NULL */
     return NULL;

Reply via email to