You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by zt...@apache.org on 2022/11/09 16:21:49 UTC

[hawq] branch master updated: HAWQ-1850. Fix life cycle of PlannedStmt and its resource

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 1f0bd6031 HAWQ-1850. Fix life cycle of PlannedStmt and its resource
1f0bd6031 is described below

commit 1f0bd60319a5376d8b81421ecf17247812f94c64
Author: ztao1987 <zh...@gmail.com>
AuthorDate: Thu Nov 10 00:21:21 2022 +0800

    HAWQ-1850. Fix life cycle of PlannedStmt and its resource
---
 src/backend/executor/spi.c           | 37 +++++++++++++++---------------------
 src/backend/optimizer/plan/planner.c | 27 ++++++++++++++++++++++++--
 2 files changed, 40 insertions(+), 24 deletions(-)

diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 5190670e7..1bc2e6801 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -1963,17 +1963,21 @@ _SPI_execute_plan(_SPI_plan * plan, Datum *Values, const char *Nulls,
           originalStmt =
               refineCachedPlan(lfirst(plan_list_item),
                                queryTree, 0, NULL);
-          stmt = copyObject(originalStmt);
-          if (Debug_udf_plan &&
-              originalStmt->datalocalityInfo) {
-            stmt->datalocalityTime =
-                originalStmt->datalocalityTime;
-            stmt->datalocalityInfo = makeStringInfo();
-            stmt->datalocalityInfo->cursor =
-                originalStmt->datalocalityInfo->cursor;
-            appendStringInfoString(
-                stmt->datalocalityInfo,
-                originalStmt->datalocalityInfo->data);
+          if (lfirst(plan_list_item) == originalStmt) {
+            stmt = copyObject(originalStmt);
+            if (Debug_udf_plan &&
+                originalStmt->datalocalityInfo) {
+              stmt->datalocalityTime =
+                  originalStmt->datalocalityTime;
+              stmt->datalocalityInfo = makeStringInfo();
+              stmt->datalocalityInfo->cursor =
+                  originalStmt->datalocalityInfo->cursor;
+              appendStringInfoString(
+                  stmt->datalocalityInfo,
+                  originalStmt->datalocalityInfo->data);
+            }
+          } else {
+            stmt = originalStmt;
           }
         }
 
@@ -2648,17 +2652,6 @@ _SPI_copy_plan(SPIPlanPtr plan, int location)
 					                       ((PlannedStmt*)lfirst(lc))->datalocalityInfo->data);
 				}
 				ps->qdContext = plancxt;
-				if (ps->resource) {
-					List *prevSegList = ps->resource->segments;
-					ps->resource->segments = NULL;
-					ListCell *lc = NULL;
-					foreach (lc, prevSegList) {
-						Segment *seg = (Segment *)lfirst(lc);
-						ps->resource->segments =
-								lappend(ps->resource->segments,
-												CopySegment(seg, plancxt));
-					}
-				}
 			}
 			newplan->ptlist = lappend(newplan->ptlist, node);
 		}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index f82b5c029..a3be57878 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -311,8 +311,31 @@ PlannedStmt *refineCachedPlan(PlannedStmt * plannedstmt,
   SplitAllocResult *allocResult = NULL;
   Query *my_parse = copyObject(parse);
 
-  /* If this is a parallel plan. request resource and allocate split again*/
-  if (my_parse->commandType != CMD_UTILITY && plannedstmt->planTree->dispatch == DISPATCH_PARALLEL)
+  // The conditions for re-allocating resource are complicated:
+  // 1. It is not a CMD_UTILITY
+  // 2. It is a parallel plan or a previously inherited resource
+  //
+  // We want to replace pre-allocated inherited resource forcefully because the
+  // life cycle of PlannedStmt is inconsistent with its resource.
+  //
+  // There is a cache mechanism for plan in plpgsql, which means that executing
+  // the same statement will access the same 'plan' object, and the resource for
+  // executing is stored in this object. The problem occurs after the first
+  // execution, the resource will be actively freed, but the cached plan still
+  // retains the freed resource, which means that when the same
+  // statement is executed the second time, an illegal address will be accessed
+  // (of course the occurrence of the problem depends on whether the memory
+  // address is polluted. In addition, we can forcibly set the address of pfree
+  // to 0 to increase the possibility of the problem).
+  //
+  // Although it is difficult for us to fundamentally control the life cycle of
+  // PlannedStmt and its resource to be consistent, we can avoid the problem
+  // through a tricky way: inheritating resource from ActiveQueryResource when
+  // fetching PlannedStmt.
+
+  if (my_parse->commandType != CMD_UTILITY && // not a CMD_UTILITY
+      (plannedstmt->planTree->dispatch == DISPATCH_PARALLEL || // parallel paln
+       (plannedstmt->resource && plannedstmt->resource->life == QRL_INHERIT))) // replace pre-allocated inherited resource forcefully
   {
     /*
      * Now, we want to allocate resource.