]> granicus.if.org Git - postgresql/commitdiff
Fix possible crash reading pg_stat_activity.
authorRobert Haas <rhaas@postgresql.org>
Thu, 5 Jan 2017 17:27:09 +0000 (12:27 -0500)
committerRobert Haas <rhaas@postgresql.org>
Thu, 5 Jan 2017 17:27:09 +0000 (12:27 -0500)
With the old code, a backend that read pg_stat_activity without ever
having executed a parallel query might see a backend in the midst of
executing one waiting on a DSA LWLock, resulting in a crash.  The
solution is for backends to register the tranche at startup time, not
the first time a parallel query is executed.

Report by Andreas Seltenreich.  Patch by me, reviewed by Thomas Munro.

src/backend/executor/execParallel.c
src/backend/storage/lmgr/lwlock.c
src/backend/utils/mmgr/dsa.c
src/include/utils/dsa.h

index 821f3e9a97b1d212e0ab99cceb9f91ad3f0fb0f1..86d9fb59ba63f09794b5f46f06b18dee869c2a83 100644 (file)
@@ -486,7 +486,6 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, int nworkers)
                shm_toc_insert(pcxt->toc, PARALLEL_KEY_DSA, area_space);
                pei->area = dsa_create_in_place(area_space, dsa_minsize,
                                                                                LWTRANCHE_PARALLEL_QUERY_DSA,
-                                                                               "parallel_query_dsa",
                                                                                pcxt->seg);
        }
 
index f4be4b4a7a63679fb1e9d36a103a6ca0a5a77875..1cf06848bb66bb61ba8d7a567a2899059f666909 100644 (file)
@@ -508,6 +508,8 @@ RegisterLWLockTranches(void)
        LWLockRegisterTranche(LWTRANCHE_LOCK_MANAGER, "lock_manager");
        LWLockRegisterTranche(LWTRANCHE_PREDICATE_LOCK_MANAGER,
                                                  "predicate_lock_manager");
+       LWLockRegisterTranche(LWTRANCHE_PARALLEL_QUERY_DSA,
+                                                 "parallel_query_dsa");
 
        /* Register named tranches. */
        for (i = 0; i < NamedLWLockTrancheRequests; i++)
index 200749feaaf23652b2e2ed221fed89f5959b80ac..2503aa5e988845a9f3334e9576d3f81a21d159d8 100644 (file)
@@ -276,11 +276,6 @@ static char dsa_size_class_map[] = {
  */
 #define DSA_FULLNESS_CLASSES           4
 
-/*
- * Maximum length of a DSA name.
- */
-#define DSA_MAXLEN                                     64
-
 /*
  * A dsa_area_pool represents a set of objects of a given size class.
  *
@@ -326,7 +321,6 @@ typedef struct
        Size            freed_segment_counter;
        /* The LWLock tranche ID. */
        int                     lwlock_tranche_id;
-       char            lwlock_tranche_name[DSA_MAXLEN];
        /* The general lock (protects everything except object pools). */
        LWLock          lock;
 } dsa_area_control;
@@ -405,7 +399,7 @@ static void unlink_segment(dsa_area *area, dsa_segment_map *segment_map);
 static dsa_segment_map *get_best_segment(dsa_area *area, Size npages);
 static dsa_segment_map *make_new_segment(dsa_area *area, Size requested_pages);
 static dsa_area *create_internal(void *place, size_t size,
-                               int tranche_id, const char *tranche_name,
+                               int tranche_id,
                                dsm_handle control_handle,
                                dsm_segment *control_segment);
 static dsa_area *attach_internal(void *place, dsm_segment *segment,
@@ -419,12 +413,10 @@ static void check_for_freed_segments(dsa_area *area);
  * We can't allocate a LWLock tranche_id within this function, because tranche
  * IDs are a scarce resource; there are only 64k available, using low numbers
  * when possible matters, and we have no provision for recycling them.  So,
- * we require the caller to provide one.  The caller must also provide the
- * tranche name, so that we can distinguish LWLocks belonging to different
- * DSAs.
+ * we require the caller to provide one.
  */
 dsa_area *
-dsa_create(int tranche_id, const char *tranche_name)
+dsa_create(int tranche_id)
 {
        dsm_segment *segment;
        dsa_area   *area;
@@ -446,7 +438,7 @@ dsa_create(int tranche_id, const char *tranche_name)
        /* Create a new DSA area with the control objet in this segment. */
        area = create_internal(dsm_segment_address(segment),
                                                   DSA_INITIAL_SEGMENT_SIZE,
-                                                  tranche_id, tranche_name,
+                                                  tranche_id,
                                                   dsm_segment_handle(segment), segment);
 
        /* Clean up when the control segment detaches. */
@@ -474,12 +466,11 @@ dsa_create(int tranche_id, const char *tranche_name)
  */
 dsa_area *
 dsa_create_in_place(void *place, size_t size,
-                                       int tranche_id, const char *tranche_name,
-                                       dsm_segment *segment)
+                                       int tranche_id, dsm_segment *segment)
 {
        dsa_area   *area;
 
-       area = create_internal(place, size, tranche_id, tranche_name,
+       area = create_internal(place, size, tranche_id,
                                                   DSM_HANDLE_INVALID, NULL);
 
        /*
@@ -1139,7 +1130,7 @@ dsa_minimum_size(void)
  */
 static dsa_area *
 create_internal(void *place, size_t size,
-                               int tranche_id, const char *tranche_name,
+                               int tranche_id,
                                dsm_handle control_handle,
                                dsm_segment *control_segment)
 {
@@ -1192,7 +1183,6 @@ create_internal(void *place, size_t size,
        control->refcnt = 1;
        control->freed_segment_counter = 0;
        control->lwlock_tranche_id = tranche_id;
-       strlcpy(control->lwlock_tranche_name, tranche_name, DSA_MAXLEN);
 
        /*
         * Create the dsa_area object that this backend will use to access the
@@ -1204,8 +1194,6 @@ create_internal(void *place, size_t size,
        area->mapping_pinned = false;
        memset(area->segment_maps, 0, sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS);
        area->high_segment_index = 0;
-       LWLockRegisterTranche(control->lwlock_tranche_id,
-                                                 control->lwlock_tranche_name);
        LWLockInitialize(&control->lock, control->lwlock_tranche_id);
        for (i = 0; i < DSA_NUM_SIZE_CLASSES; ++i)
                LWLockInitialize(DSA_SCLASS_LOCK(area, i),
@@ -1262,8 +1250,6 @@ attach_internal(void *place, dsm_segment *segment, dsa_handle handle)
        memset(&area->segment_maps[0], 0,
                   sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS);
        area->high_segment_index = 0;
-       LWLockRegisterTranche(control->lwlock_tranche_id,
-                                                 control->lwlock_tranche_name);
 
        /* Set up the segment map for this process's mapping. */
        segment_map = &area->segment_maps[0];
index 0aca58f5296ca5e5942ace2104da6d9e8587c160..bb634e77cdaa59deb94a41c6d5f51abae3d10e09 100644 (file)
@@ -90,10 +90,9 @@ typedef dsm_handle dsa_handle;
 
 extern void dsa_startup(void);
 
-extern dsa_area *dsa_create(int tranche_id, const char *tranche_name);
+extern dsa_area *dsa_create(int tranche_id);
 extern dsa_area *dsa_create_in_place(void *place, Size size,
-                                       int tranche_id, const char *tranche_name,
-                                       dsm_segment *segment);
+                                       int tranche_id, dsm_segment *segment);
 extern dsa_area *dsa_attach(dsa_handle handle);
 extern dsa_area *dsa_attach_in_place(void *place, dsm_segment *segment);
 extern void dsa_release_in_place(void *place);