Skip to content

Commit 8aa02b5

Browse files
committed
Add ExecStorePinnedBufferHeapTuple.
This allows to avoid an unnecessary pin/unpin cycle when storing a tuple in an already pinned buffer into a slot, when the pin isn't further needed at the call site. Only a single caller for now (to ensure coverage), but upcoming patches will increase use of the new function. Author: Andres Freund Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
1 parent f4b6341 commit 8aa02b5

File tree

3 files changed

+60
-19
lines changed

3 files changed

+60
-19
lines changed

src/backend/executor/execTuples.c

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
7474
static pg_attribute_always_inline void
7575
slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
7676
int natts);
77-
static void tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer);
77+
static inline void tts_buffer_heap_store_tuple(TupleTableSlot *slot,
78+
HeapTuple tuple,
79+
Buffer buffer,
80+
bool transfer_pin);
81+
static void tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree);
7882

7983

8084
const TupleTableSlotOps TTSOpsVirtual;
@@ -743,7 +747,9 @@ tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
743747
}
744748
else
745749
{
746-
tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple, bsrcslot->buffer);
750+
tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple,
751+
bsrcslot->buffer, false);
752+
747753
/*
748754
* Need to materialize because the HeapTupleData portion of the tuple
749755
* might be in a foreign memory context. That's annoying, but until
@@ -792,8 +798,9 @@ tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
792798
return minimal_tuple_from_heap_tuple(bslot->base.tuple);
793799
}
794800

795-
static void
796-
tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer)
801+
static inline void
802+
tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
803+
Buffer buffer, bool transfer_pin)
797804
{
798805
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
799806

@@ -813,7 +820,9 @@ tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer
813820

814821
/*
815822
* If tuple is on a disk page, keep the page pinned as long as we hold a
816-
* pointer into it. We assume the caller already has such a pin.
823+
* pointer into it. We assume the caller already has such a pin. If
824+
* transfer_pin is true, we'll transfer that pin to this slot, if not
825+
* we'll pin it again ourselves.
817826
*
818827
* This is coded to optimize the case where the slot previously held a
819828
* tuple on the same disk page: in that case releasing and re-acquiring
@@ -824,8 +833,19 @@ tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer
824833
{
825834
if (BufferIsValid(bslot->buffer))
826835
ReleaseBuffer(bslot->buffer);
836+
827837
bslot->buffer = buffer;
828-
IncrBufferRefCount(buffer);
838+
839+
if (!transfer_pin && BufferIsValid(buffer))
840+
IncrBufferRefCount(buffer);
841+
}
842+
else if (transfer_pin && BufferIsValid(buffer))
843+
{
844+
/*
845+
* In transfer_pin mode the caller won't know about the same-page
846+
* optimization, so we gotta release its pin.
847+
*/
848+
ReleaseBuffer(buffer);
829849
}
830850
}
831851

@@ -1321,7 +1341,32 @@ ExecStoreBufferHeapTuple(HeapTuple tuple,
13211341

13221342
if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
13231343
elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1324-
tts_buffer_heap_store_tuple(slot, tuple, buffer);
1344+
tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
1345+
1346+
1347+
return slot;
1348+
}
1349+
1350+
/*
1351+
* Like ExecStoreBufferHeapTuple, but transfer an existing pin from the caller
1352+
* to the slot, i.e. the caller doesn't need to, and may not, release the pin.
1353+
*/
1354+
TupleTableSlot *
1355+
ExecStorePinnedBufferHeapTuple(HeapTuple tuple,
1356+
TupleTableSlot *slot,
1357+
Buffer buffer)
1358+
{
1359+
/*
1360+
* sanity checks
1361+
*/
1362+
Assert(tuple != NULL);
1363+
Assert(slot != NULL);
1364+
Assert(slot->tts_tupleDescriptor != NULL);
1365+
Assert(BufferIsValid(buffer));
1366+
1367+
if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1368+
elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1369+
tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
13251370

13261371
return slot;
13271372
}

src/backend/executor/nodeTidscan.c

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -379,19 +379,12 @@ TidNext(TidScanState *node)
379379
{
380380
/*
381381
* Store the scanned tuple in the scan tuple slot of the scan
382-
* state. Eventually we will only do this and not return a tuple.
382+
* state, transferring the pin to the slot.
383383
*/
384-
ExecStoreBufferHeapTuple(tuple, /* tuple to store */
385-
slot, /* slot to store in */
386-
buffer); /* buffer associated with
387-
* tuple */
388-
389-
/*
390-
* At this point we have an extra pin on the buffer, because
391-
* ExecStoreHeapTuple incremented the pin count. Drop our local
392-
* pin.
393-
*/
394-
ReleaseBuffer(buffer);
384+
ExecStorePinnedBufferHeapTuple(tuple, /* tuple to store */
385+
slot, /* slot to store in */
386+
buffer); /* buffer associated with
387+
* tuple */
395388

396389
return slot;
397390
}

src/include/executor/tuptable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ extern void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot);
305305
extern TupleTableSlot *ExecStoreBufferHeapTuple(HeapTuple tuple,
306306
TupleTableSlot *slot,
307307
Buffer buffer);
308+
extern TupleTableSlot *ExecStorePinnedBufferHeapTuple(HeapTuple tuple,
309+
TupleTableSlot *slot,
310+
Buffer buffer);
308311
extern TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup,
309312
TupleTableSlot *slot,
310313
bool shouldFree);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy