troubleshooting pointers
With the current SRF patch, in certain circumstances selecting from a
VIEW produces "Buffer Leak" warnings, while selecting from the function
itself does not. Also the VIEW returns only one of the two expected
rows. The same SQL function when declared as "... getfoo(int) RETURNS
int AS ..." instead of "... getfoo(int) RETURNS *setof* int AS..." does
not produce the warning. Any ideas what I should be focusing on to track
this down? Does anyone have any favorite troubleshooting techniques for
this type of problem?
Thanks,
Joe
-- sql, proretset = t, prorettype = b
DROP FUNCTION getfoo(int);
DROP
CREATE FUNCTION getfoo(int) RETURNS setof int AS 'SELECT fooid FROM foo
WHERE fooid = $1;' LANGUAGE SQL;
CREATE
SELECT * FROM getfoo(1) AS t1;
getfoo
--------
1
1
(2 rows)
DROP VIEW vw_getfoo;
DROP
CREATE VIEW vw_getfoo AS SELECT * FROM getfoo(1);
CREATE
SELECT * FROM vw_getfoo;
psql:../srf-test.sql:21: WARNING: Buffer Leak: [055] (freeNext=-3,
freePrev=-3, rel=16570/123204, blockNum=1, flags=0x4, refcount=1 1)
psql:../srf-test.sql:21: WARNING: Buffer Leak: [059] (freeNext=-3,
freePrev=-3, rel=16570/123199, blockNum=0, flags=0x85, refcount=1 1)
getfoo
--------
1
(1 row)
Hello, Joe!
JC> With the current SRF patch, in certain circumstances selecting from
JC> a
JC> VIEW produces "Buffer Leak" warnings, while selecting from the
JC> function itself does not. Also the VIEW returns only one of the two
Selecting from the function produces such a warning when using it with
limit,
but it does not when the function returns less rows than specified in limit
.
e.g.
just_fun=# create table testtab(i integer, v varchar);
CREATE
just_fun=# insert into testtab values(1,'one');
INSERT 16592 1
just_fun=# insert into testtab values(2,'two');
INSERT 16593 1
just_fun=# insert into testtab values(3,'three');
INSERT 16594 1
just_fun=# insert into testtab values(1,'one again');
INSERT 16595 1
just_fun=# create function fun(integer) returns setof testtab as 'select *
from testtab where i= $1;' language 'sql';
just_fun=# select * from fun(1) as fun;
i | v
---+-----------
1 | one
1 | one again
(2 rows)
just_fun=# select * from fun(1) as fun limit 1;
WARNING: Buffer Leak: [050] (freeNext=-3, freePrev=-3, rel=16570/16587,
blockNum=0, flags=0x85, refcount=1 2)
i | v
---+-----
1 | one
(1 row)
....And there is no warning with "ORDER BY"
just_fun=# select * from fun(1) as fun order by v limit 1;
i | v
---+-----
1 | one
(1 row)
Hope this info maybe useful to solve the problem.
By the way, could you give an example of C-function returning set?
JC> expected rows. The same SQL function when declared as "...
JC> getfoo(int) RETURNS int AS ..." instead of "... getfoo(int) RETURNS
JC> *setof* int AS..." does not produce the warning. Any ideas what I
JC> should be focusing on to track this down? Does anyone have any
JC> favorite troubleshooting techniques for this type of problem?
JC> Thanks,
JC> Joe
Thank you for your work in this direction!
With best regards, Valentine Zaretsky
Valentine Zaretsky wrote:
just_fun=# select * from fun(1) as fun limit 1;
WARNING: Buffer Leak: [050] (freeNext=-3, freePrev=-3, rel=16570/16587,
blockNum=0, flags=0x85, refcount=1 2)
i | v
---+-----
1 | one
(1 row)....And there is no warning with "ORDER BY"
just_fun=# select * from fun(1) as fun order by v limit 1;
i | v
---+-----
1 | one
(1 row)Hope this info maybe useful to solve the problem.
Hmm. Yes, it looks like this is probably the same or a related issue.
By the way, could you give an example of C-function returning set?
In contrib/dblink, see dblink.c for a couple of examples (dblink(),
dblink_get_pkey()), or look at pg_stat_get_backend_idset() in the
backend code. I haven't written a C-function returning a setof composite
type yet, but probably will soon, because I'll need it for testing (and
ultimately for the regression test script).
Thanks for the help!
Joe
Joe Conway <mail@joeconway.com> writes:
With the current SRF patch, in certain circumstances selecting from a
VIEW produces "Buffer Leak" warnings, while selecting from the function
itself does not. Also the VIEW returns only one of the two expected
rows.
The buffer leak suggests failure to shut down a plan tree (ie, no
ExecutorEnd call). Probably related to not running the VIEW to
completion, but it's hard to guess at the underlying cause.
Do the plan trees (EXPLAIN display) look the same in both cases?
regards, tom lane
Tom Lane wrote:
Joe Conway <mail@joeconway.com> writes:
With the current SRF patch, in certain circumstances selecting from a
VIEW produces "Buffer Leak" warnings, while selecting from the function
itself does not. Also the VIEW returns only one of the two expected
rows.The buffer leak suggests failure to shut down a plan tree (ie, no
ExecutorEnd call). Probably related to not running the VIEW to
completion, but it's hard to guess at the underlying cause.Do the plan trees (EXPLAIN display) look the same in both cases?
Yes, but it suffers from the issue you brought up yesterday -- i.e.
EXPLAIN doesn't run from within the function, and EXPLAIN outside the
function (or VIEW which calls it) doesn't show very much:
test=# EXPLAIN SELECT * FROM vw_getfoo;
QUERY PLAN
-----------------------------------------------------------
Function Scan on getfoo (cost=0.00..0.00 rows=0 width=0)
(1 row)
test=# EXPLAIN SELECT * FROM getfoo(1);
QUERY PLAN
-----------------------------------------------------------
Function Scan on getfoo (cost=0.00..0.00 rows=0 width=0)
(1 row)
I found an explaination you gave a while back which sounds like it
explains the problem:
http://archives.postgresql.org/pgsql-bugs/2001-06/msg00051.php
I also confirmed that postquel_end(), which calls ExecutorEnd(), never
gets called for the VIEW case (or the LIMIT case that was pointed out on
an earlier post).
Just now I was looking for a way to propagate the necessary information
to call ExecutorEnd() from ExecEndFunctionScan() in the case that fmgr
doesn't. It looks like I might be able to add a member to the
ExprContext struct for this purpose. Does this sound like the correct
(or at least a reasonable) approach?
Thanks,
Joe
Joe Conway <mail@joeconway.com> writes:
Just now I was looking for a way to propagate the necessary information
to call ExecutorEnd() from ExecEndFunctionScan() in the case that fmgr
doesn't. It looks like I might be able to add a member to the
ExprContext struct for this purpose. Does this sound like the correct
(or at least a reasonable) approach?
Yeah, this is something that's bothered me in the past: with the
existing API, a function-returning-set will not get a chance to shut
down cleanly and release resources if its result is not read all the
way to completion. You can demonstrate the problem without any
use of the SRF patch. Using current CVS tip (no patch), and the
regression database:
regression=# create function foo(int) returns setof int as '
regression'# select unique1 from tenk1 where unique2 > $1'
regression-# language sql;
regression=# select foo(9990) limit 4;
WARNING: Buffer Leak: [009] (freeNext=-3, freePrev=-3, rel=16570/135224, blockNum=29, flags=0x4, refcount=1 1)
WARNING: Buffer Leak: [021] (freeNext=-3, freePrev=-3, rel=16570/18464, blockNum=232, flags=0x4, refcount=1 1)
foo
------
4093
6587
6093
429
(4 rows)
I don't much care for the thought of trawling every expression tree
looking for functions-returning-set during plan shutdown, so the thought
that comes to mind is to expect functions that want a shutdown callback
to register themselves somehow. Adding a list of callbacks to
ExprContext seems pretty reasonable, but you'd also need some link in
ReturnSetInfo to let the function find the ExprContext to register
itself with. Then FreeExprContext would call the callbacks.
Hmm ... another advantage of doing this is that the function would be
able to find the ecxt_per_query_memory associated with the ExprContext.
That would be a Good Thing.
We should also think about the fcache (FunctionCache) struct and whether
that needs to tie into this. See the FIXME in utils/fcache.h.
regards, tom lane
Tom Lane wrote:
I don't much care for the thought of trawling every expression tree
looking for functions-returning-set during plan shutdown, so the thought
that comes to mind is to expect functions that want a shutdown callback
to register themselves somehow. Adding a list of callbacks to
ExprContext seems pretty reasonable, but you'd also need some link in
ReturnSetInfo to let the function find the ExprContext to register
itself with. Then FreeExprContext would call the callbacks.
I've made changes which fix this and will send them in with a revised
SRF patch later today. Summary of design:
1.) moved the execution_state struct and ExecStatus enum to executor.h
2.) added "void *es" member to ExprContext
3.) added econtext member to ReturnSetInfo
4.) set rsi->econtext on the way in at ExecMakeFunctionResult()
5.) set rsi->econtext->es on the way in at fmgr_sql()
6.) used econtext->es on the way out at ExecFreeExprContext() to call
ExecutorEnd() if needed (because postquel_execute() never got the chance).
One note: I changed ExecFreeExprContext() because that's where all the
action was for SQL function calls. FreeExprContext() was not involved
for the test case, but it looked like it probably should have the same
changes, so I made them there also.
Hmm ... another advantage of doing this is that the function would be
able to find the ecxt_per_query_memory associated with the ExprContext.
That would be a Good Thing.
What does this allow done that can't be done today?
We should also think about the fcache (FunctionCache) struct and whether
that needs to tie into this. See the FIXME in utils/fcache.h.
While I was at it, I added an fcache member to ExprContext, and
populated it in ExecMakeFunctionResult() for SRF cases. I wasn't sure
what else to do with it at the moment, but at least it is a step in the
right direction.
Joe
Joe Conway <mail@joeconway.com> writes:
Tom Lane wrote:
Adding a list of callbacks to
ExprContext seems pretty reasonable, but you'd also need some link in
ReturnSetInfo to let the function find the ExprContext to register
itself with. Then FreeExprContext would call the callbacks.
I've made changes which fix this and will send them in with a revised
SRF patch later today. Summary of design:
1.) moved the execution_state struct and ExecStatus enum to executor.h
2.) added "void *es" member to ExprContext
3.) added econtext member to ReturnSetInfo
4.) set rsi->econtext on the way in at ExecMakeFunctionResult()
5.) set rsi->econtext->es on the way in at fmgr_sql()
6.) used econtext->es on the way out at ExecFreeExprContext() to call
ExecutorEnd() if needed (because postquel_execute() never got the chance).
Um. I don't like that; it assumes not only that ExecutorEnd is the only
kind of callback needed, but also that there is at most one function
per ExprContext that needs a shutdown callback. Neither of these
assumptions hold water IMO.
The design I had in mind was more like this: add to ExprContext a list
header field pointing to a list of structs along the lines of
struct exprcontext_callback {
struct exprcontext_callback *next;
void (*function) (Datum);
Datum arg;
}
and then call each specified function with given argument during
FreeExprContext. Probably ought to be careful to do that in reverse
order of registration. We'd also need to invent a RescanExprContext
operation to call the callbacks during a Rescan. The use of Datum
(and not, say, void *) as PG's standard callback arg type was settled on
some time ago --- originally for on_proc_exit IIRC --- and seems to have
worked well enough.
Hmm ... another advantage of doing this is that the function would be
able to find the ecxt_per_query_memory associated with the ExprContext.
That would be a Good Thing.
What does this allow done that can't be done today?
It provides a place for the function to allocate stuff that needs to
live over multiple calls, ie, until it gets its shutdown callback.
Right now a function has to use TransactionCommandContext for that,
but that's really too coarse-grained.
We should also think about the fcache (FunctionCache) struct and whether
that needs to tie into this. See the FIXME in utils/fcache.h.
While I was at it, I added an fcache member to ExprContext, and
populated it in ExecMakeFunctionResult() for SRF cases. I wasn't sure
what else to do with it at the moment, but at least it is a step in the
right direction.
Well, I was debating whether that's good or not. The existing fcache
approach is wrong (per cited FIXME); it might be better not to propagate
access of it into more places. Unless you can see a specific reason to
allow the function to have access to the fcache struct, I think I'm
inclined not to.
What's really more relevant here is that during the hypothetical new
RescanExprContext function, we ought to go around and clear any fcaches
in the context that have setArgsValid = true, so that they will be
restarted afresh during the next scan of the plan. (The fact that that
doesn't happen now is another shortcoming of the existing set-functions-
in-expressions code.) So this suggests making a callback function type
specifically to do that, and registering every fcache that is executing
a set function in the callback list...
regards, tom lane
Tom Lane wrote:
Um. I don't like that; it assumes not only that ExecutorEnd is the only
kind of callback needed, but also that there is at most one function
per ExprContext that needs a shutdown callback. Neither of these
assumptions hold water IMO.The design I had in mind was more like this: add to ExprContext a list
header field pointing to a list of structs along the lines ofstruct exprcontext_callback {
struct exprcontext_callback *next;
void (*function) (Datum);
Datum arg;
}and then call each specified function with given argument during
FreeExprContext. Probably ought to be careful to do that in reverse
order of registration. We'd also need to invent a RescanExprContext
operation to call the callbacks during a Rescan. The use of Datum
(and not, say, void *) as PG's standard callback arg type was settled on
some time ago --- originally for on_proc_exit IIRC --- and seems to have
worked well enough.
Well, I guess I set my sights too low ;-) This is a very nice design.
I have the shutdown callback working now, and will send a new patch in a
few minutes. I have not started RescanExprContext() yet, but will do it
when I address rescans in general.
What's really more relevant here is that during the hypothetical new
RescanExprContext function, we ought to go around and clear any fcaches
in the context that have setArgsValid = true, so that they will be
restarted afresh during the next scan of the plan. (The fact that that
doesn't happen now is another shortcoming of the existing set-functions-
in-expressions code.) So this suggests making a callback function type
specifically to do that, and registering every fcache that is executing
a set function in the callback list...
I also added FunctionCachePtr_callback struct and a member to
ExprContext. I have not yet created the registration or shutdown
functions, but again, I'll work on them as part of the rescan work.
I still have a couple of issues related to VIEWs that I need to figure
out, then I'll start the rescan work.
Thanks for the review and help!
Joe
Tom Lane wrote:
Um. I don't like that; it assumes not only that ExecutorEnd is the only
kind of callback needed, but also that there is at most one function
per ExprContext that needs a shutdown callback. Neither of these
assumptions hold water IMO.The design I had in mind was more like this: add to ExprContext a list
header field pointing to a list of structs along the lines ofstruct exprcontext_callback {
struct exprcontext_callback *next;
void (*function) (Datum);
Datum arg;
}and then call each specified function with given argument during
FreeExprContext. Probably ought to be careful to do that in reverse
order of registration. We'd also need to invent a RescanExprContext
operation to call the callbacks during a Rescan. The use of Datum
(and not, say, void *) as PG's standard callback arg type was settled on
some time ago --- originally for on_proc_exit IIRC --- and seems to have
worked well enough.
Here's the patch, per my post to HACKERS.
It builds cleanly on my dev box, and passes all regression tests.
Thanks,
Joe
Attachments:
srf.2002.05.10.1.patch.gzapplication/x-gzip; name=srf.2002.05.10.1.patch.gzDownload
�n�<