Commit 71bdc99d authored by Andres Freund's avatar Andres Freund

tableam: Add helper for indexes to check if a corresponding table tuples exist.

This is, likely exclusively, useful to verify that conflicts detected
in a unique index are with live tuples, rather than dead ones.

Author: Andres Freund
Discussion: https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
parent aa1419e6
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#include "postgres.h" #include "postgres.h"
#include "access/heapam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "access/nbtxlog.h" #include "access/nbtxlog.h"
#include "access/tableam.h"
#include "access/transam.h" #include "access/transam.h"
#include "access/xloginsert.h" #include "access/xloginsert.h"
#include "miscadmin.h" #include "miscadmin.h"
...@@ -431,12 +431,14 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel, ...@@ -431,12 +431,14 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
} }
/* /*
* We check the whole HOT-chain to see if there is any tuple * Check if there's any table tuples for this index entry
* that satisfies SnapshotDirty. This is necessary because we * satisfying SnapshotDirty. This is necessary because for AMs
* have just a single index entry for the entire chain. * with optimizations like heap's HOT, we have just a single
* index entry for the entire chain.
*/ */
else if (heap_hot_search(&htid, heapRel, &SnapshotDirty, else if (table_index_fetch_tuple_check(heapRel, &htid,
&all_dead)) &SnapshotDirty,
&all_dead))
{ {
TransactionId xwait; TransactionId xwait;
...@@ -489,7 +491,8 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel, ...@@ -489,7 +491,8 @@ _bt_check_unique(Relation rel, BTInsertState insertstate, Relation heapRel,
* entry. * entry.
*/ */
htid = itup->t_tid; htid = itup->t_tid;
if (heap_hot_search(&htid, heapRel, SnapshotSelf, NULL)) if (table_index_fetch_tuple_check(heapRel, &htid,
SnapshotSelf, NULL))
{ {
/* Normal case --- it's still live */ /* Normal case --- it's still live */
} }
......
...@@ -57,10 +57,10 @@ ...@@ -57,10 +57,10 @@
#include "postgres.h" #include "postgres.h"
#include "access/heapam.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "access/parallel.h" #include "access/parallel.h"
#include "access/relscan.h" #include "access/relscan.h"
#include "access/table.h"
#include "access/tableam.h" #include "access/tableam.h"
#include "access/xact.h" #include "access/xact.h"
#include "access/xlog.h" #include "access/xlog.h"
......
...@@ -176,6 +176,40 @@ table_beginscan_parallel(Relation relation, ParallelTableScanDesc parallel_scan) ...@@ -176,6 +176,40 @@ table_beginscan_parallel(Relation relation, ParallelTableScanDesc parallel_scan)
} }
/* ----------------------------------------------------------------------------
* Index scan related functions.
* ----------------------------------------------------------------------------
*/
/*
* To perform that check simply start an index scan, create the necessary
* slot, do the heap lookup, and shut everything down again. This could be
* optimized, but is unlikely to matter from a performance POV. If there
* frequently are live index pointers also matching a unique index key, the
* CPU overhead of this routine is unlikely to matter.
*/
bool
table_index_fetch_tuple_check(Relation rel,
ItemPointer tid,
Snapshot snapshot,
bool *all_dead)
{
IndexFetchTableData *scan;
TupleTableSlot *slot;
bool call_again = false;
bool found;
slot = table_slot_create(rel, NULL);
scan = table_index_fetch_begin(rel);
found = table_index_fetch_tuple(scan, tid, snapshot, slot, &call_again,
all_dead);
table_index_fetch_end(scan);
ExecDropSingleTupleTableSlot(slot);
return found;
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* Functions to make modifications a bit simpler. * Functions to make modifications a bit simpler.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
......
...@@ -256,9 +256,10 @@ typedef struct TableAmRoutine ...@@ -256,9 +256,10 @@ typedef struct TableAmRoutine
* needs be set to true by index_fetch_tuple, signalling to the caller * needs be set to true by index_fetch_tuple, signalling to the caller
* that index_fetch_tuple should be called again for the same tid. * that index_fetch_tuple should be called again for the same tid.
* *
* *all_dead should be set to true by index_fetch_tuple iff it is * *all_dead, if all_dead is not NULL, should be set to true if by
* guaranteed that no backend needs to see that tuple. Index AMs can use * index_fetch_tuple iff it is guaranteed that no backend needs to see
* that do avoid returning that tid in future searches. * that tuple. Index AMs can use that do avoid returning that tid in
* future searches.
*/ */
bool (*index_fetch_tuple) (struct IndexFetchTableData *scan, bool (*index_fetch_tuple) (struct IndexFetchTableData *scan,
ItemPointer tid, ItemPointer tid,
...@@ -594,9 +595,10 @@ table_index_fetch_end(struct IndexFetchTableData *scan) ...@@ -594,9 +595,10 @@ table_index_fetch_end(struct IndexFetchTableData *scan)
* will be set to true, signalling that table_index_fetch_tuple() should be called * will be set to true, signalling that table_index_fetch_tuple() should be called
* again for the same tid. * again for the same tid.
* *
* *all_dead will be set to true by table_index_fetch_tuple() iff it is guaranteed * *all_dead, if all_dead is not NULL, will be set to true by
* that no backend needs to see that tuple. Index AMs can use that do avoid * table_index_fetch_tuple() iff it is guaranteed that no backend needs to see
* returning that tid in future searches. * that tuple. Index AMs can use that do avoid returning that tid in future
* searches.
* *
* The difference between this function and table_fetch_row_version is that * The difference between this function and table_fetch_row_version is that
* this function returns the currently visible version of a row if the AM * this function returns the currently visible version of a row if the AM
...@@ -618,6 +620,17 @@ table_index_fetch_tuple(struct IndexFetchTableData *scan, ...@@ -618,6 +620,17 @@ table_index_fetch_tuple(struct IndexFetchTableData *scan,
all_dead); all_dead);
} }
/*
* This is a convenience wrapper around table_index_fetch_tuple() which
* returns whether there are table tuple items corresponding to an index
* entry. This likely is only useful to verify if there's a conflict in a
* unique index.
*/
extern bool table_index_fetch_tuple_check(Relation rel,
ItemPointer tid,
Snapshot snapshot,
bool *all_dead);
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Functions for non-modifying operations on individual tuples * Functions for non-modifying operations on individual tuples
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment