Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fbc7a71

Browse files
committed
Rearrange validity checks for plpgsql "simple" expressions.
Buildfarm experience shows what probably should've occurred to me before: if a cache flush occurs partway through building a generic plan, then the plansource may have is_valid = false even though the plan is valid. We need to accept this case, use the generated plan, and then try to replan the next time. We can't try to replan immediately, because that would produce an infinite loop in CLOBBER_CACHE_ALWAYS builds; moreover it's really overkill. (We can assume that the plan is valid, it's just possibly a bit stale. Note that the pre-existing code behaved this way, and the non-simple-expression code paths do too.) Conversely, not using the generated plan would drop us into the not-a-simple-expression code path, which is bad for performance and would also cause regression-test failures due to visibly different error-reporting behavior. Hence, refactor the validity-check functions so that the initial check and recheck cases can react differently to plansource->is_valid. This makes their usage a bit simpler, too. Discussion: https://postgr.es/m/7072.1585332104@sss.pgh.pa.us
1 parent 8d1b964 commit fbc7a71

File tree

3 files changed

+42
-26
lines changed

3 files changed

+42
-26
lines changed

src/backend/utils/cache/plancache.c

+27-4
Original file line numberDiff line numberDiff line change
@@ -1290,6 +1290,10 @@ ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
12901290
* to be invalidated, for example due to a change in a function that was
12911291
* inlined into the plan.)
12921292
*
1293+
* If the plan is simply valid, and "owner" is not NULL, record a refcount on
1294+
* the plan in that resowner before returning. It is caller's responsibility
1295+
* to be sure that a refcount is held on any plan that's being actively used.
1296+
*
12931297
* This must only be called on known-valid generic plans (eg, ones just
12941298
* returned by GetCachedPlan). If it returns true, the caller may re-use
12951299
* the cached plan as long as CachedPlanIsSimplyValid returns true; that
@@ -1298,16 +1302,24 @@ ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
12981302
*/
12991303
bool
13001304
CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
1301-
CachedPlan *plan)
1305+
CachedPlan *plan, ResourceOwner owner)
13021306
{
13031307
ListCell *lc;
13041308

1305-
/* Sanity-check that the caller gave us a validated generic plan. */
1309+
/*
1310+
* Sanity-check that the caller gave us a validated generic plan. Notice
1311+
* that we *don't* assert plansource->is_valid as you might expect; that's
1312+
* because it's possible that that's already false when GetCachedPlan
1313+
* returns, e.g. because ResetPlanCache happened partway through. We
1314+
* should accept the plan as long as plan->is_valid is true, and expect to
1315+
* replan after the next CachedPlanIsSimplyValid call.
1316+
*/
13061317
Assert(plansource->magic == CACHEDPLANSOURCE_MAGIC);
13071318
Assert(plan->magic == CACHEDPLAN_MAGIC);
1308-
Assert(plansource->is_valid);
13091319
Assert(plan->is_valid);
13101320
Assert(plan == plansource->gplan);
1321+
Assert(plansource->search_path != NULL);
1322+
Assert(OverrideSearchPathMatchesCurrent(plansource->search_path));
13111323

13121324
/* We don't support oneshot plans here. */
13131325
if (plansource->is_oneshot)
@@ -1371,6 +1383,15 @@ CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
13711383
* Okay, it's simple. Note that what we've primarily established here is
13721384
* that no locks need be taken before checking the plan's is_valid flag.
13731385
*/
1386+
1387+
/* Bump refcount if requested. */
1388+
if (owner)
1389+
{
1390+
ResourceOwnerEnlargePlanCacheRefs(owner);
1391+
plan->refcount++;
1392+
ResourceOwnerRememberPlanCacheRef(owner, plan);
1393+
}
1394+
13741395
return true;
13751396
}
13761397

@@ -1408,7 +1429,9 @@ CachedPlanIsSimplyValid(CachedPlanSource *plansource, CachedPlan *plan,
14081429

14091430
/*
14101431
* Has cache invalidation fired on this plan? We can check this right
1411-
* away since there are no locks that we'd need to acquire first.
1432+
* away since there are no locks that we'd need to acquire first. Note
1433+
* that here we *do* check plansource->is_valid, so as to force plan
1434+
* rebuild if that's become false.
14121435
*/
14131436
if (!plansource->is_valid || plan != plansource->gplan || !plan->is_valid)
14141437
return false;

src/include/utils/plancache.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ extern CachedPlan *GetCachedPlan(CachedPlanSource *plansource,
223223
extern void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner);
224224

225225
extern bool CachedPlanAllowsSimpleValidityCheck(CachedPlanSource *plansource,
226-
CachedPlan *plan);
226+
CachedPlan *plan,
227+
ResourceOwner owner);
227228
extern bool CachedPlanIsSimplyValid(CachedPlanSource *plansource,
228229
CachedPlan *plan,
229230
ResourceOwner owner);

src/pl/plpgsql/src/pl_exec.c

+13-21
Original file line numberDiff line numberDiff line change
@@ -6181,14 +6181,13 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
61816181
Assert(cplan != NULL);
61826182

61836183
/*
6184-
* These tests probably can't fail either, but if they do, cope by
6184+
* This test probably can't fail either, but if it does, cope by
61856185
* declaring the plan to be non-simple. On success, we'll acquire a
61866186
* refcount on the new plan, stored in simple_eval_resowner.
61876187
*/
61886188
if (CachedPlanAllowsSimpleValidityCheck(expr->expr_simple_plansource,
6189-
cplan) &&
6190-
CachedPlanIsSimplyValid(expr->expr_simple_plansource, cplan,
6191-
estate->simple_eval_resowner))
6189+
cplan,
6190+
estate->simple_eval_resowner))
61926191
{
61936192
/* Remember that we have the refcount */
61946193
expr->expr_simple_plan = cplan;
@@ -8089,26 +8088,19 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
80898088
/*
80908089
* Verify that plancache.c thinks the plan is simple enough to use
80918090
* CachedPlanIsSimplyValid. Given the restrictions above, it's unlikely
8092-
* that this could fail, but if it does, just treat plan as not simple.
8091+
* that this could fail, but if it does, just treat plan as not simple. On
8092+
* success, save a refcount on the plan in the simple-expression resowner.
80938093
*/
8094-
if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan))
8094+
if (CachedPlanAllowsSimpleValidityCheck(plansource, cplan,
8095+
estate->simple_eval_resowner))
80958096
{
8096-
/*
8097-
* OK, use CachedPlanIsSimplyValid to save a refcount on the plan in
8098-
* the simple-expression resowner. This shouldn't fail either, but if
8099-
* somehow it does, again we can cope by treating plan as not simple.
8100-
*/
8101-
if (CachedPlanIsSimplyValid(plansource, cplan,
8102-
estate->simple_eval_resowner))
8103-
{
8104-
/* Remember that we have the refcount */
8105-
expr->expr_simple_plansource = plansource;
8106-
expr->expr_simple_plan = cplan;
8107-
expr->expr_simple_plan_lxid = MyProc->lxid;
8097+
/* Remember that we have the refcount */
8098+
expr->expr_simple_plansource = plansource;
8099+
expr->expr_simple_plan = cplan;
8100+
expr->expr_simple_plan_lxid = MyProc->lxid;
81088101

8109-
/* Share the remaining work with the replan code path */
8110-
exec_save_simple_expr(expr, cplan);
8111-
}
8102+
/* Share the remaining work with the replan code path */
8103+
exec_save_simple_expr(expr, cplan);
81128104
}
81138105

81148106
/*

0 commit comments

Comments
 (0)