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

Commit 9a8ee1d

Browse files
committed
tableam: Add and use table_fetch_row_version().
This is essentially the tableam version of heapam_fetch(), i.e. fetching a tuple identified by a tid, performing visibility checks. Note that this different from table_index_fetch_tuple(), which is for index lookups. It therefore has to handle a tid pointing to an earlier version of a tuple if the AM uses an optimization like heap's HOT. Add comments to that end. This commit removes the stats_relation argument from heap_fetch, as it's been unused for a long time. Author: Andres Freund Reviewed-By: Haribabu Kommi Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
1 parent c77e122 commit 9a8ee1d

File tree

9 files changed

+91
-111
lines changed

9 files changed

+91
-111
lines changed

src/backend/access/heap/heapam.c

+2-7
Original file line numberDiff line numberDiff line change
@@ -1388,8 +1388,7 @@ bool
13881388
heap_fetch(Relation relation,
13891389
Snapshot snapshot,
13901390
HeapTuple tuple,
1391-
Buffer *userbuf,
1392-
Relation stats_relation)
1391+
Buffer *userbuf)
13931392
{
13941393
ItemPointer tid = &(tuple->t_self);
13951394
ItemId lp;
@@ -1468,10 +1467,6 @@ heap_fetch(Relation relation,
14681467
*/
14691468
*userbuf = buffer;
14701469

1471-
/* Count the successful fetch against appropriate rel, if any */
1472-
if (stats_relation != NULL)
1473-
pgstat_count_heap_fetch(stats_relation);
1474-
14751470
return true;
14761471
}
14771472

@@ -5097,7 +5092,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
50975092
block = ItemPointerGetBlockNumber(&tupid);
50985093
ItemPointerCopy(&tupid, &(mytup.t_self));
50995094

5100-
if (!heap_fetch(rel, SnapshotAny, &mytup, &buf, NULL))
5095+
if (!heap_fetch(rel, SnapshotAny, &mytup, &buf))
51015096
{
51025097
/*
51035098
* if we fail to find the updated version of the tuple, it's

src/backend/access/heap/heapam_handler.c

+26-1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,30 @@ heapam_index_fetch_tuple(struct IndexFetchTableData *scan,
148148
* ------------------------------------------------------------------------
149149
*/
150150

151+
static bool
152+
heapam_fetch_row_version(Relation relation,
153+
ItemPointer tid,
154+
Snapshot snapshot,
155+
TupleTableSlot *slot)
156+
{
157+
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
158+
Buffer buffer;
159+
160+
Assert(TTS_IS_BUFFERTUPLE(slot));
161+
162+
bslot->base.tupdata.t_self = *tid;
163+
if (heap_fetch(relation, snapshot, &bslot->base.tupdata, &buffer))
164+
{
165+
/* store in slot, transferring existing pin */
166+
ExecStorePinnedBufferHeapTuple(&bslot->base.tupdata, slot, buffer);
167+
slot->tts_tableOid = RelationGetRelid(relation);
168+
169+
return true;
170+
}
171+
172+
return false;
173+
}
174+
151175
static bool
152176
heapam_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot,
153177
Snapshot snapshot)
@@ -338,7 +362,7 @@ heapam_tuple_lock(Relation relation, ItemPointer tid, Snapshot snapshot,
338362
errmsg("tuple to be locked was already moved to another partition due to concurrent update")));
339363

340364
tuple->t_self = *tid;
341-
if (heap_fetch(relation, &SnapshotDirty, tuple, &buffer, NULL))
365+
if (heap_fetch(relation, &SnapshotDirty, tuple, &buffer))
342366
{
343367
/*
344368
* If xmin isn't what we're expecting, the slot must have
@@ -517,6 +541,7 @@ static const TableAmRoutine heapam_methods = {
517541
.tuple_update = heapam_tuple_update,
518542
.tuple_lock = heapam_tuple_lock,
519543

544+
.tuple_fetch_row_version = heapam_fetch_row_version,
520545
.tuple_satisfies_snapshot = heapam_tuple_satisfies_snapshot,
521546
};
522547

src/backend/access/table/tableamapi.c

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ GetTableAmRoutine(Oid amhandler)
6262
Assert(routine->index_fetch_end != NULL);
6363
Assert(routine->index_fetch_tuple != NULL);
6464

65+
Assert(routine->tuple_fetch_row_version != NULL);
6566
Assert(routine->tuple_satisfies_snapshot != NULL);
6667

6768
Assert(routine->tuple_insert != NULL);

src/backend/commands/trigger.c

+12-57
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
#include "postgres.h"
1515

1616
#include "access/genam.h"
17-
#include "access/heapam.h"
18-
#include "access/tableam.h"
19-
#include "access/sysattr.h"
2017
#include "access/htup_details.h"
18+
#include "access/relation.h"
19+
#include "access/sysattr.h"
20+
#include "access/table.h"
21+
#include "access/tableam.h"
2122
#include "access/xact.h"
2223
#include "catalog/catalog.h"
2324
#include "catalog/dependency.h"
@@ -3379,42 +3380,12 @@ GetTupleForTrigger(EState *estate,
33793380
}
33803381
else
33813382
{
3382-
Page page;
3383-
ItemId lp;
3384-
Buffer buffer;
3385-
BufferHeapTupleTableSlot *boldslot;
3386-
HeapTuple tuple;
3387-
3388-
Assert(TTS_IS_BUFFERTUPLE(oldslot));
3389-
ExecClearTuple(oldslot);
3390-
boldslot = (BufferHeapTupleTableSlot *) oldslot;
3391-
tuple = &boldslot->base.tupdata;
3392-
3393-
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
3394-
33953383
/*
3396-
* Although we already know this tuple is valid, we must lock the
3397-
* buffer to ensure that no one has a buffer cleanup lock; otherwise
3398-
* they might move the tuple while we try to copy it. But we can
3399-
* release the lock before actually doing the heap_copytuple call,
3400-
* since holding pin is sufficient to prevent anyone from getting a
3401-
* cleanup lock they don't already hold.
3384+
* We expect the tuple to be present, thus very simple error handling
3385+
* suffices.
34023386
*/
3403-
LockBuffer(buffer, BUFFER_LOCK_SHARE);
3404-
3405-
page = BufferGetPage(buffer);
3406-
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
3407-
3408-
Assert(ItemIdIsNormal(lp));
3409-
3410-
tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
3411-
tuple->t_len = ItemIdGetLength(lp);
3412-
tuple->t_self = *tid;
3413-
tuple->t_tableOid = RelationGetRelid(relation);
3414-
3415-
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
3416-
3417-
ExecStorePinnedBufferHeapTuple(tuple, oldslot, buffer);
3387+
if (!table_fetch_row_version(relation, tid, SnapshotAny, oldslot))
3388+
elog(ERROR, "failed to fetch tuple for trigger");
34183389
}
34193390

34203391
return true;
@@ -4193,8 +4164,6 @@ AfterTriggerExecute(EState *estate,
41934164
AfterTriggerShared evtshared = GetTriggerSharedData(event);
41944165
Oid tgoid = evtshared->ats_tgoid;
41954166
TriggerData LocTriggerData;
4196-
HeapTupleData tuple1;
4197-
HeapTupleData tuple2;
41984167
HeapTuple rettuple;
41994168
int tgindx;
42004169
bool should_free_trig = false;
@@ -4271,19 +4240,12 @@ AfterTriggerExecute(EState *estate,
42714240
default:
42724241
if (ItemPointerIsValid(&(event->ate_ctid1)))
42734242
{
4274-
Buffer buffer;
4275-
42764243
LocTriggerData.tg_trigslot = ExecGetTriggerOldSlot(estate, relInfo);
42774244

4278-
ItemPointerCopy(&(event->ate_ctid1), &(tuple1.t_self));
4279-
if (!heap_fetch(rel, SnapshotAny, &tuple1, &buffer, NULL))
4245+
if (!table_fetch_row_version(rel, &(event->ate_ctid1), SnapshotAny, LocTriggerData.tg_trigslot))
42804246
elog(ERROR, "failed to fetch tuple1 for AFTER trigger");
4281-
ExecStorePinnedBufferHeapTuple(&tuple1,
4282-
LocTriggerData.tg_trigslot,
4283-
buffer);
42844247
LocTriggerData.tg_trigtuple =
4285-
ExecFetchSlotHeapTuple(LocTriggerData.tg_trigslot, false,
4286-
&should_free_trig);
4248+
ExecFetchSlotHeapTuple(LocTriggerData.tg_trigslot, false, &should_free_trig);
42874249
}
42884250
else
42894251
{
@@ -4295,19 +4257,12 @@ AfterTriggerExecute(EState *estate,
42954257
AFTER_TRIGGER_2CTID &&
42964258
ItemPointerIsValid(&(event->ate_ctid2)))
42974259
{
4298-
Buffer buffer;
4299-
43004260
LocTriggerData.tg_newslot = ExecGetTriggerNewSlot(estate, relInfo);
43014261

4302-
ItemPointerCopy(&(event->ate_ctid2), &(tuple2.t_self));
4303-
if (!heap_fetch(rel, SnapshotAny, &tuple2, &buffer, NULL))
4262+
if (!table_fetch_row_version(rel, &(event->ate_ctid2), SnapshotAny, LocTriggerData.tg_newslot))
43044263
elog(ERROR, "failed to fetch tuple2 for AFTER trigger");
4305-
ExecStorePinnedBufferHeapTuple(&tuple2,
4306-
LocTriggerData.tg_newslot,
4307-
buffer);
43084264
LocTriggerData.tg_newtuple =
4309-
ExecFetchSlotHeapTuple(LocTriggerData.tg_newslot, false,
4310-
&should_free_new);
4265+
ExecFetchSlotHeapTuple(LocTriggerData.tg_newslot, false, &should_free_new);
43114266
}
43124267
else
43134268
{

src/backend/executor/execMain.c

+3-10
Original file line numberDiff line numberDiff line change
@@ -2649,17 +2649,10 @@ EvalPlanQualFetchRowMarks(EPQState *epqstate)
26492649
else
26502650
{
26512651
/* ordinary table, fetch the tuple */
2652-
HeapTupleData tuple;
2653-
Buffer buffer;
2654-
2655-
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
2656-
if (!heap_fetch(erm->relation, SnapshotAny, &tuple, &buffer,
2657-
NULL))
2652+
if (!table_fetch_row_version(erm->relation,
2653+
(ItemPointer) DatumGetPointer(datum),
2654+
SnapshotAny, slot))
26582655
elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
2659-
2660-
/* successful, store tuple */
2661-
ExecStorePinnedBufferHeapTuple(&tuple, slot, buffer);
2662-
ExecMaterializeSlot(slot);
26632656
}
26642657
}
26652658
else

src/backend/executor/nodeModifyTable.c

+3-19
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,13 @@ ExecCheckTIDVisible(EState *estate,
229229
TupleTableSlot *tempSlot)
230230
{
231231
Relation rel = relinfo->ri_RelationDesc;
232-
Buffer buffer;
233-
HeapTupleData tuple;
234232

235233
/* Redundantly check isolation level */
236234
if (!IsolationUsesXactSnapshot())
237235
return;
238236

239-
tuple.t_self = *tid;
240-
if (!heap_fetch(rel, SnapshotAny, &tuple, &buffer, NULL))
237+
if (!table_fetch_row_version(rel, tid, SnapshotAny, tempSlot))
241238
elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
242-
ExecStorePinnedBufferHeapTuple(&tuple, tempSlot, buffer);
243239
ExecCheckTupleVisible(estate, rel, tempSlot);
244240
ExecClearTuple(tempSlot);
245241
}
@@ -874,21 +870,9 @@ ldelete:;
874870
}
875871
else
876872
{
877-
BufferHeapTupleTableSlot *bslot;
878-
HeapTuple deltuple;
879-
Buffer buffer;
880-
881-
Assert(TTS_IS_BUFFERTUPLE(slot));
882-
ExecClearTuple(slot);
883-
bslot = (BufferHeapTupleTableSlot *) slot;
884-
deltuple = &bslot->base.tupdata;
885-
886-
deltuple->t_self = *tupleid;
887-
if (!heap_fetch(resultRelationDesc, SnapshotAny,
888-
deltuple, &buffer, NULL))
873+
if (!table_fetch_row_version(resultRelationDesc, tupleid,
874+
SnapshotAny, slot))
889875
elog(ERROR, "failed to fetch deleted tuple for DELETE RETURNING");
890-
891-
ExecStorePinnedBufferHeapTuple(deltuple, slot, buffer);
892876
}
893877
}
894878

src/backend/executor/nodeTidscan.c

+3-13
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ TidNext(TidScanState *node)
310310
Relation heapRelation;
311311
HeapTuple tuple;
312312
TupleTableSlot *slot;
313-
Buffer buffer = InvalidBuffer;
314313
ItemPointerData *tidList;
315314
int numTids;
316315
bool bBackward;
@@ -376,19 +375,10 @@ TidNext(TidScanState *node)
376375
if (node->tss_isCurrentOf)
377376
heap_get_latest_tid(heapRelation, snapshot, &tuple->t_self);
378377

379-
if (heap_fetch(heapRelation, snapshot, tuple, &buffer, NULL))
380-
{
381-
/*
382-
* Store the scanned tuple in the scan tuple slot of the scan
383-
* state, transferring the pin to the slot.
384-
*/
385-
ExecStorePinnedBufferHeapTuple(tuple, /* tuple to store */
386-
slot, /* slot to store in */
387-
buffer); /* buffer associated with
388-
* tuple */
389-
378+
if (table_fetch_row_version(heapRelation, &tuple->t_self, snapshot,
379+
slot))
390380
return slot;
391-
}
381+
392382
/* Bad TID or failed snapshot qual; try next */
393383
if (bBackward)
394384
node->tss_TidPtr--;

src/include/access/heapam.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ extern bool heap_getnextslot(TableScanDesc sscan,
128128
ScanDirection direction, struct TupleTableSlot *slot);
129129

130130
extern bool heap_fetch(Relation relation, Snapshot snapshot,
131-
HeapTuple tuple, Buffer *userbuf, Relation stats_relation);
131+
HeapTuple tuple, Buffer *userbuf);
132132
extern bool heap_hot_search_buffer(ItemPointer tid, Relation relation,
133133
Buffer buffer, Snapshot snapshot, HeapTuple heapTuple,
134134
bool *all_dead, bool first_call);

src/include/access/tableam.h

+40-3
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,17 @@ typedef struct TableAmRoutine
271271
* ------------------------------------------------------------------------
272272
*/
273273

274+
275+
/*
276+
* Fetch tuple at `tid` into `slot, after doing a visibility test
277+
* according to `snapshot`. If a tuple was found and passed the visibility
278+
* test, returns true, false otherwise.
279+
*/
280+
bool (*tuple_fetch_row_version) (Relation rel,
281+
ItemPointer tid,
282+
Snapshot snapshot,
283+
TupleTableSlot *slot);
284+
274285
/*
275286
* Does the tuple in `slot` satisfy `snapshot`? The slot needs to be of
276287
* the appropriate type for the AM.
@@ -574,9 +585,9 @@ table_index_fetch_end(struct IndexFetchTableData *scan)
574585
}
575586

576587
/*
577-
* Fetches tuple at `tid` into `slot`, after doing a visibility test according
578-
* to `snapshot`. If a tuple was found and passed the visibility test, returns
579-
* true, false otherwise.
588+
* Fetches, as part of an index scan, tuple at `tid` into `slot`, after doing
589+
* a visibility test according to `snapshot`. If a tuple was found and passed
590+
* the visibility test, returns true, false otherwise.
580591
*
581592
* *call_again needs to be false on the first call to table_index_fetch_tuple() for
582593
* a tid. If there potentially is another tuple matching the tid, *call_again
@@ -586,6 +597,13 @@ table_index_fetch_end(struct IndexFetchTableData *scan)
586597
* *all_dead will be set to true by table_index_fetch_tuple() iff it is guaranteed
587598
* that no backend needs to see that tuple. Index AMs can use that do avoid
588599
* returning that tid in future searches.
600+
*
601+
* The difference between this function and table_fetch_row_version is that
602+
* this function returns the currently visible version of a row if the AM
603+
* supports storing multiple row versions reachable via a single index entry
604+
* (like heap's HOT). Whereas table_fetch_row_version only evaluates the the
605+
* tuple exactly at `tid`. Outside of index entry ->table tuple lookups,
606+
* table_fetch_row_version is what's usually needed.
589607
*/
590608
static inline bool
591609
table_index_fetch_tuple(struct IndexFetchTableData *scan,
@@ -606,6 +624,25 @@ table_index_fetch_tuple(struct IndexFetchTableData *scan,
606624
* ------------------------------------------------------------------------
607625
*/
608626

627+
628+
/*
629+
* Fetch tuple at `tid` into `slot, after doing a visibility test according to
630+
* `snapshot`. If a tuple was found and passed the visibility test, returns
631+
* true, false otherwise.
632+
*
633+
* See table_index_fetch_tuple's comment about what the difference between
634+
* these functions is. This function is the correct to use outside of
635+
* index entry->table tuple lookups.
636+
*/
637+
static inline bool
638+
table_fetch_row_version(Relation rel,
639+
ItemPointer tid,
640+
Snapshot snapshot,
641+
TupleTableSlot *slot)
642+
{
643+
return rel->rd_tableam->tuple_fetch_row_version(rel, tid, snapshot, slot);
644+
}
645+
609646
/*
610647
* Return true iff tuple in slot satisfies the snapshot.
611648
*

0 commit comments

Comments
 (0)