Re: Why is it not sane to pass ExecStoreTuple(shouldFree=true) for tuples point into buffers - Mailing list pgsql-hackers

From Andres Freund
Subject Re: Why is it not sane to pass ExecStoreTuple(shouldFree=true) for tuples point into buffers
Date
Msg-id 20140407203850.GO4161@awork2.anarazel.de
Whole thread Raw
In response to Re: Why is it not sane to pass ExecStoreTuple(shouldFree=true) for tuples point into buffers  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Why is it not sane to pass ExecStoreTuple(shouldFree=true) for tuples point into buffers
List pgsql-hackers
On 2014-04-07 16:29:57 -0400, Tom Lane wrote:
> Andres Freund <andres@2ndquadrant.com> writes:
> > On 2014-04-07 15:58:31 -0400, Tom Lane wrote:
> >> There's an assumption that if you are asking to pin a buffer, the tuple
> >> pointer you're passing is pointing into that buffer (and is therefore not
> >> something that could be pfree'd).  If it isn't pointing into a buffer,
> >> the tuple slot is not the place to be keeping the buffer reference.
>
> > Yea. I *have* a HeapTupleData struct pointing into the buffer. It's just
> > that the lifetime of the indexscans's xs_ctup isn't sufficient for my
> > case. So I have to allocate a new HeapTupleData struct, *again* pointing
> > into the buffer. I'd like to manage the lifetime of that HeapTupleData
> > struct (*not* the entire HeapTupleHeader blob) via the slot.
> > That doesn't sound too crazy to me?
>
> In that case you should have another tuple slot of your own and let it
> keep the tuple (and buffer pin).

Maybe I am just being dense here and misunderstanding tuple slots. The
executor isn't exactly my strong suit.

But say I am doing something like:

slot = ExecInitExtraTupleSlot(estate);
ExecSetSlotDescriptor(slot, RelationGetDescr(rel));
...
while ((scantuple = index_getnext(scan, ForwardScanDirection)) != NULL)
{    /* some check */    ...    if (blurb)        ExecStoreTuple(scantuple, slot, scan->xs_cbuf, true);
}

...
index_endscan(scan); /* possibly */

/* now use the stored tuple via slot->tts_tuple */

that's not going to work, because scantuple might be free'd or pointing
to another tuple, from the next index_getnext() call. Right?
So what I now do is essentially:
while ((scantuple = index_getnext(scan, ForwardScanDirection)) != NULL)
{
...       ht = palloc(sizeof(HeapTupleData)); /* in the right context */       memcpy(ht, scantuple,
sizeof(HeapTupleData));      ExecStoreTuple(ht, slot, scan->xs_cbuf, false);       slot->tts_shouldFree = true;
 
...
}

That will a) keep the buffer pinned long enough, b) keep the
HeapTupleData struct around long enough.

That works, but seems pretty ugly. Thus I am wondering if a) there's a
way to avoid the outside manipulation of tts_shouldFree b) why there's
no builtin operation doing the palloc, memcpy and store...

Greetings,

Andres Freund

--Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



pgsql-hackers by date:

Previous
From: Peter Geoghegan
Date:
Subject: Re: B-Tree support function number 3 (strxfrm() optimization)
Next
From: Robert Haas
Date:
Subject: Re: B-Tree support function number 3 (strxfrm() optimization)