Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita9c35cf

Browse files
committed
Change function call information to be variable length.
Before this change FunctionCallInfoData, the struct arguments etc forV1 function calls are stored in, always had space forFUNC_MAX_ARGS/100 arguments, storing datums and their nullness in twoarrays. For nearly every function call 100 arguments is far more thanneeded, therefore wasting memory. Arg and argnull being two separatearrays also guarantees that to access a single argument, twocachelines have to be touched.Change the layout so there's a single variable-length array with pairsof value / isnull. That drastically reduces memory consumption formost function calls (on x86-64 a two argument function now uses64bytes, previously 936 bytes), and makes it very likely that argumentvalue and its nullness are on the same cacheline.Arguments are stored in a new NullableDatum struct, which, due topadding, needs more memory per argument than before. But as usuallyfar fewer arguments are stored, and individual arguments are cheaperto access, that's still a clear win. It's likely that there's otherplaces where conversion to NullableDatum arrays would make sense,e.g. TupleTableSlots, but that's for another commit.Because the function call information is now variable-lengthallocations have to take the number of arguments into account. Forheap allocations that can be done with SizeForFunctionCallInfoData(),for on-stack allocations there's a new LOCAL_FCINFO(name, nargs) macrothat helps to allocate an appropriately sized and aligned variable.Some places with stack allocation function call information don't knowthe number of arguments at compile time, and currently variably sizedstack allocations aren't allowed in postgres. Therefore allow forFUNC_MAX_ARGS space in these cases. They're not that common, so fornow that seems acceptable.Because of the need to allocate FunctionCallInfo of the appropriatesize, older extensions may need to update their code. To avoid subtlebreakages, the FunctionCallInfoData struct has been renamed toFunctionCallInfoBaseData. Most code only references FunctionCallInfo,so that shouldn't cause much collateral damage.This change is also a prerequisite for more efficient expression JITcompilation (by allocating the function call information on the stack,allowing LLVM to optimize it away); previously the size of the callinformation caused problems inside LLVM's optimizer.Author: Andres FreundReviewed-By: Tom LaneDiscussion:https://postgr.es/m/20180605172952.x34m5uz6ju6enaem@alap3.anarazel.de
1 parent6d3ede5 commita9c35cf

40 files changed

+957
-1054
lines changed

‎contrib/hstore/hstore_op.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ hstore_to_matrix(PG_FUNCTION_ARGS)
854854

855855
staticvoid
856856
setup_firstcall(FuncCallContext*funcctx,HStore*hs,
857-
FunctionCallInfoData*fcinfo)
857+
FunctionCallInfofcinfo)
858858
{
859859
MemoryContextoldcontext;
860860
HStore*st;

‎doc/src/sgml/plhandler.sgml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@
3434
<para>
3535
The call handler is called in the same way as any other function:
3636
It receives a pointer to a
37-
<structname>FunctionCallInfoData</structname> <type>struct</type> containing
37+
<structname>FunctionCallInfoBaseData</structname> <type>struct</type> containing
3838
argument values and information about the called function, and it
3939
is expected to return a <type>Datum</type> result (and possibly
4040
set the <structfield>isnull</structfield> field of the
41-
<structname>FunctionCallInfoData</structname> structure, if it wishes
41+
<structname>FunctionCallInfoBaseData</structname> structure, if it wishes
4242
to return an SQL null result). The difference between a call
4343
handler and an ordinary callee function is that the
4444
<structfield>flinfo-&gt;fn_oid</structfield> field of the
45-
<structname>FunctionCallInfoData</structname> structure will contain
45+
<structname>FunctionCallInfoBaseData</structname> structure will contain
4646
the OID of the actual function to be called, not of the call
4747
handler itself. The call handler must use this field to determine
4848
which function to execute. Also, the passed argument list has
@@ -87,7 +87,7 @@
8787
<para>
8888
When a procedural-language function is invoked as a trigger, no arguments
8989
are passed in the usual way, but the
90-
<structname>FunctionCallInfoData</structname>'s
90+
<structname>FunctionCallInfoBaseData</structname>'s
9191
<structfield>context</structfield> field points at a
9292
<structname>TriggerData</structname> structure, rather than being <symbol>NULL</symbol>
9393
as it is in a plain function call. A language handler should

‎src/backend/commands/event_trigger.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,9 +1055,9 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
10551055
/* Call each event trigger. */
10561056
foreach(lc,fn_oid_list)
10571057
{
1058+
LOCAL_FCINFO(fcinfo,0);
10581059
Oidfnoid=lfirst_oid(lc);
10591060
FmgrInfoflinfo;
1060-
FunctionCallInfoDatafcinfo;
10611061
PgStat_FunctionCallUsagefcusage;
10621062

10631063
elog(DEBUG1,"EventTriggerInvoke %u",fnoid);
@@ -1077,10 +1077,10 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
10771077
fmgr_info(fnoid,&flinfo);
10781078

10791079
/* Call the function, passing no arguments but setting a context. */
1080-
InitFunctionCallInfoData(fcinfo,&flinfo,0,
1080+
InitFunctionCallInfoData(*fcinfo,&flinfo,0,
10811081
InvalidOid, (Node*)trigdata,NULL);
1082-
pgstat_init_function_usage(&fcinfo,&fcusage);
1083-
FunctionCallInvoke(&fcinfo);
1082+
pgstat_init_function_usage(fcinfo,&fcusage);
1083+
FunctionCallInvoke(fcinfo);
10841084
pgstat_end_function_usage(&fcusage, true);
10851085

10861086
/* Reclaim memory. */

‎src/backend/commands/functioncmds.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,13 +2216,13 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
22162216
void
22172217
ExecuteCallStmt(CallStmt*stmt,ParamListInfoparams,boolatomic,DestReceiver*dest)
22182218
{
2219+
LOCAL_FCINFO(fcinfo,FUNC_MAX_ARGS);
22192220
ListCell*lc;
22202221
FuncExpr*fexpr;
22212222
intnargs;
22222223
inti;
22232224
AclResultaclresult;
22242225
FmgrInfoflinfo;
2225-
FunctionCallInfoDatafcinfo;
22262226
CallContext*callcontext;
22272227
EState*estate;
22282228
ExprContext*econtext;
@@ -2297,7 +2297,8 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
22972297
InvokeFunctionExecuteHook(fexpr->funcid);
22982298
fmgr_info(fexpr->funcid,&flinfo);
22992299
fmgr_info_set_expr((Node*)fexpr,&flinfo);
2300-
InitFunctionCallInfoData(fcinfo,&flinfo,nargs,fexpr->inputcollid, (Node*)callcontext,NULL);
2300+
InitFunctionCallInfoData(*fcinfo,&flinfo,nargs,fexpr->inputcollid,
2301+
(Node*)callcontext,NULL);
23012302

23022303
/*
23032304
* Evaluate procedure arguments inside a suitable execution context. Note
@@ -2318,14 +2319,14 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
23182319

23192320
val=ExecEvalExprSwitchContext(exprstate,econtext,&isnull);
23202321

2321-
fcinfo.arg[i]=val;
2322-
fcinfo.argnull[i]=isnull;
2322+
fcinfo->args[i].value=val;
2323+
fcinfo->args[i].isnull=isnull;
23232324

23242325
i++;
23252326
}
23262327

2327-
pgstat_init_function_usage(&fcinfo,&fcusage);
2328-
retval=FunctionCallInvoke(&fcinfo);
2328+
pgstat_init_function_usage(fcinfo,&fcusage);
2329+
retval=FunctionCallInvoke(fcinfo);
23292330
pgstat_end_function_usage(&fcusage, true);
23302331

23312332
if (fexpr->funcresulttype==VOIDOID)
@@ -2346,7 +2347,7 @@ ExecuteCallStmt(CallStmt *stmt, ParamListInfo params, bool atomic, DestReceiver
23462347
TupOutputState*tstate;
23472348
TupleTableSlot*slot;
23482349

2349-
if (fcinfo.isnull)
2350+
if (fcinfo->isnull)
23502351
elog(ERROR,"procedure returned null record");
23512352

23522353
td=DatumGetHeapTupleHeader(retval);

‎src/backend/commands/tablecmds.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8879,15 +8879,15 @@ validateForeignKeyConstraint(char *conname,
88798879

88808880
while ((tuple=heap_getnext(scan,ForwardScanDirection))!=NULL)
88818881
{
8882-
FunctionCallInfoDatafcinfo;
8882+
LOCAL_FCINFO(fcinfo,0);
88838883
TriggerDatatrigdata;
88848884

88858885
/*
88868886
* Make a call to the trigger function
88878887
*
88888888
* No parameters are passed, but we do set a context
88898889
*/
8890-
MemSet(&fcinfo,0,sizeof(fcinfo));
8890+
MemSet(fcinfo,0,SizeForFunctionCallInfo(0));
88918891

88928892
/*
88938893
* We assume RI_FKey_check_ins won't look at flinfo...
@@ -8901,9 +8901,9 @@ validateForeignKeyConstraint(char *conname,
89018901
trigdata.tg_trigtuplebuf=scan->rs_cbuf;
89028902
trigdata.tg_newtuplebuf=InvalidBuffer;
89038903

8904-
fcinfo.context= (Node*)&trigdata;
8904+
fcinfo->context= (Node*)&trigdata;
89058905

8906-
RI_FKey_check_ins(&fcinfo);
8906+
RI_FKey_check_ins(fcinfo);
89078907
}
89088908

89098909
heap_endscan(scan);

‎src/backend/commands/trigger.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,7 +2357,7 @@ ExecCallTriggerFunc(TriggerData *trigdata,
23572357
Instrumentation*instr,
23582358
MemoryContextper_tuple_context)
23592359
{
2360-
FunctionCallInfoDatafcinfo;
2360+
LOCAL_FCINFO(fcinfo,0);
23612361
PgStat_FunctionCallUsagefcusage;
23622362
Datumresult;
23632363
MemoryContextoldContext;
@@ -2402,15 +2402,15 @@ ExecCallTriggerFunc(TriggerData *trigdata,
24022402
/*
24032403
* Call the function, passing no arguments but setting a context.
24042404
*/
2405-
InitFunctionCallInfoData(fcinfo,finfo,0,
2405+
InitFunctionCallInfoData(*fcinfo,finfo,0,
24062406
InvalidOid, (Node*)trigdata,NULL);
24072407

2408-
pgstat_init_function_usage(&fcinfo,&fcusage);
2408+
pgstat_init_function_usage(fcinfo,&fcusage);
24092409

24102410
MyTriggerDepth++;
24112411
PG_TRY();
24122412
{
2413-
result=FunctionCallInvoke(&fcinfo);
2413+
result=FunctionCallInvoke(fcinfo);
24142414
}
24152415
PG_CATCH();
24162416
{
@@ -2428,11 +2428,11 @@ ExecCallTriggerFunc(TriggerData *trigdata,
24282428
* Trigger protocol allows function to return a null pointer, but NOT to
24292429
* set the isnull result flag.
24302430
*/
2431-
if (fcinfo.isnull)
2431+
if (fcinfo->isnull)
24322432
ereport(ERROR,
24332433
(errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
24342434
errmsg("trigger function %u returned null value",
2435-
fcinfo.flinfo->fn_oid)));
2435+
fcinfo->flinfo->fn_oid)));
24362436

24372437
/*
24382438
* If doing EXPLAIN ANALYZE, stop charging time to this trigger, and count

‎src/backend/executor/README

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ For example, "a + b" (one OpExpr, with two Var expressions) would be
124124
represented as two steps to fetch the Var values, and one step for the
125125
evaluation of the function underlying the + operator. The steps for the
126126
Vars would have their resvalue/resnull pointing directly to the appropriate
127-
arg[] and argnull[] arrayelements in theFunctionCallInfoData struct that
127+
args[].value .isnullelements in theFunctionCallInfoBaseData struct that
128128
is used by the function evaluation step, thus avoiding extra work to copy
129129
the result values around.
130130

@@ -145,7 +145,7 @@ sub-expressions.
145145
Each ExecInitExprRec() call has to specify where that subexpression's
146146
results are to be stored (via the resv/resnull parameters). This allows
147147
the above scenario of evaluating a (sub-)expression directly into
148-
fcinfo->arg/argnull, but also requires some care: target Datum/isnull
148+
fcinfo->args[].value/isnull, but also requires some care: target Datum/isnull
149149
variables may not be shared with another ExecInitExprRec() unless the
150150
results are only needed by steps executing before further usages of those
151151
target Datum/isnull variables. Due to the non-recursiveness of the
@@ -158,7 +158,7 @@ not enough space. Because of that it is *not* allowed to point directly
158158
into any of the steps during expression initialization. Therefore, the
159159
resv/resnull for a subexpression usually point to some storage that is
160160
palloc'd separately from the steps array. For instance, the
161-
FunctionCallInfoData for a function call step is separately allocated
161+
FunctionCallInfoBaseData for a function call step is separately allocated
162162
rather than being part of the ExprEvalStep array. The overall result
163163
of a complete expression is typically returned into the resvalue/resnull
164164
fields of the ExprState node itself.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp