PostgreSQL Source Code git master
Loading...
Searching...
No Matches
heap_surgery.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/visibilitymap.h"
#include "access/xloginsert.h"
#include "catalog/pg_am_d.h"
#include "catalog/pg_control.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/rel.h"
Include dependency graph for heap_surgery.c:

Go to the source code of this file.

Typedefs

typedef enum HeapTupleForceOption HeapTupleForceOption
 

Enumerations

enum  HeapTupleForceOption { HEAP_FORCE_KILL , HEAP_FORCE_FREEZE }
 

Functions

 PG_MODULE_MAGIC_EXT (.name="pg_surgery",.version=PG_VERSION)
 
 PG_FUNCTION_INFO_V1 (heap_force_kill)
 
 PG_FUNCTION_INFO_V1 (heap_force_freeze)
 
static int32 tidcmp (const void *a, const void *b)
 
static Datum heap_force_common (FunctionCallInfo fcinfo, HeapTupleForceOption heap_force_opt)
 
static void sanity_check_tid_array (ArrayType *ta, int *ntids)
 
static BlockNumber find_tids_one_page (ItemPointer tids, int ntids, OffsetNumber *next_start_ptr)
 
Datum heap_force_kill (PG_FUNCTION_ARGS)
 
Datum heap_force_freeze (PG_FUNCTION_ARGS)
 

Typedef Documentation

◆ HeapTupleForceOption

Enumeration Type Documentation

◆ HeapTupleForceOption

Enumerator
HEAP_FORCE_KILL 
HEAP_FORCE_FREEZE 

Definition at line 33 of file heap_surgery.c.

34{
HeapTupleForceOption
@ HEAP_FORCE_KILL
@ HEAP_FORCE_FREEZE

Function Documentation

◆ find_tids_one_page()

static BlockNumber find_tids_one_page ( ItemPointer  tids,
int  ntids,
OffsetNumber next_start_ptr 
)
static

Definition at line 416 of file heap_surgery.c.

417{
418 int i;
420 blkno;
421
423
424 for (i = *next_start_ptr; i < ntids; i++)
425 {
426 ItemPointerData tid = tids[i];
427
429
430 if (i == *next_start_ptr)
431 prev_blkno = blkno;
432
433 if (prev_blkno != blkno)
434 break;
435 }
436
437 *next_start_ptr = i;
438 return prev_blkno;
439}
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
int i
Definition isn.c:77
static BlockNumber ItemPointerGetBlockNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:93
static int fb(int x)

References fb(), i, InvalidBlockNumber, and ItemPointerGetBlockNumberNoCheck().

Referenced by heap_force_common().

◆ heap_force_common()

static Datum heap_force_common ( FunctionCallInfo  fcinfo,
HeapTupleForceOption  heap_force_opt 
)
static

Definition at line 86 of file heap_surgery.c.

87{
88 Oid relid = PG_GETARG_OID(0);
90 ItemPointer tids;
91 int ntids,
92 nblocks;
93 Relation rel;
97
101 errmsg("recovery is in progress"),
102 errhint("Heap surgery functions cannot be executed during recovery.")));
103
104 /* Check inputs. */
105 sanity_check_tid_array(ta, &ntids);
106
107 rel = relation_open(relid, RowExclusiveLock);
108
109 /*
110 * Check target relation.
111 */
112 if (!RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
115 errmsg("cannot operate on relation \"%s\"",
118
119 if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
122 errmsg("only heap AM is supported")));
123
124 /* Must be owner of the table or superuser. */
127 get_relkind_objtype(rel->rd_rel->relkind),
129
130 tids = ((ItemPointer) ARR_DATA_PTR(ta));
131
132 /*
133 * If there is more than one TID in the array, sort them so that we can
134 * easily fetch all the TIDs belonging to one particular page from the
135 * array.
136 */
137 if (ntids > 1)
138 qsort(tids, ntids, sizeof(ItemPointerData), tidcmp);
139
141 nblocks = RelationGetNumberOfBlocks(rel);
142
143 /*
144 * Loop, performing the necessary actions for each block.
145 */
146 while (next_start_ptr != ntids)
147 {
148 Buffer buf;
150 bool unlock_vmbuf = false;
151 Page page;
152 BlockNumber blkno;
155 int i;
156 bool did_modify_page = false;
157 bool did_modify_vm = false;
158
160
161 /*
162 * Find all the TIDs belonging to one particular page starting from
163 * next_start_ptr and process them one by one.
164 */
165 blkno = find_tids_one_page(tids, ntids, &next_start_ptr);
166
167 /* Check whether the block number is valid. */
168 if (blkno >= nblocks)
169 {
170 /* Update the current_start_ptr before moving to the next page. */
172
175 errmsg("skipping block %u for relation \"%s\" because the block number is out of range",
176 blkno, RelationGetRelationName(rel))));
177 continue;
178 }
179
180 buf = ReadBuffer(rel, blkno);
182
183 page = BufferGetPage(buf);
184
186
187 /*
188 * Figure out which TIDs we are going to process and which ones we are
189 * going to skip.
190 */
192 for (i = curr_start_ptr; i < next_start_ptr; i++)
193 {
195 ItemId itemid;
196
197 /* Check whether the offset number is valid. */
199 {
201 errmsg("skipping tid (%u, %u) for relation \"%s\" because the item number is out of range",
202 blkno, offno, RelationGetRelationName(rel)));
203 continue;
204 }
205
206 itemid = PageGetItemId(page, offno);
207
208 /* Only accept an item ID that is used. */
209 if (ItemIdIsRedirected(itemid))
210 {
212 errmsg("skipping tid (%u, %u) for relation \"%s\" because it redirects to item %u",
213 blkno, offno, RelationGetRelationName(rel),
214 ItemIdGetRedirect(itemid)));
215 continue;
216 }
217 else if (ItemIdIsDead(itemid))
218 {
220 (errmsg("skipping tid (%u, %u) for relation \"%s\" because it is marked dead",
221 blkno, offno, RelationGetRelationName(rel))));
222 continue;
223 }
224 else if (!ItemIdIsUsed(itemid))
225 {
227 (errmsg("skipping tid (%u, %u) for relation \"%s\" because it is marked unused",
228 blkno, offno, RelationGetRelationName(rel))));
229 continue;
230 }
231
232 /* Mark it for processing. */
234 include_this_tid[offno - 1] = true;
235 }
236
237 /*
238 * Before entering the critical section, pin and lock the visibility
239 * map page if it appears to be necessary.
240 */
242 {
243 visibilitymap_pin(rel, blkno, &vmbuf);
245 unlock_vmbuf = true;
246 }
247
248 /* No ereport(ERROR) from here until all the changes are logged. */
250
253 {
254 ItemId itemid;
255
256 if (!include_this_tid[curoff - 1])
257 continue;
258
259 itemid = PageGetItemId(page, curoff);
260 Assert(ItemIdIsNormal(itemid));
261
262 did_modify_page = true;
263
265 {
266 ItemIdSetDead(itemid);
267
268 /*
269 * If the page is marked all-visible, we must clear
270 * PD_ALL_VISIBLE flag on the page header and an all-visible
271 * bit on the visibility map corresponding to the page.
272 */
273 if (PageIsAllVisible(page))
274 {
275 if (visibilitymap_clear(rel->rd_locator, blkno, vmbuf,
277 did_modify_vm = true;
278
280 }
281 }
282 else
283 {
284 HeapTupleHeader htup;
285
287
288 htup = (HeapTupleHeader) PageGetItem(page, itemid);
289
290 /*
291 * Reset all visibility-related fields of the tuple. This
292 * logic should mimic heap_execute_freeze_tuple(), but we
293 * choose to reset xmin and ctid just to be sure that no
294 * potentially-garbled data is left behind.
295 */
296 ItemPointerSet(&htup->t_ctid, blkno, curoff);
299 if (htup->t_infomask & HEAP_MOVED)
300 {
301 if (htup->t_infomask & HEAP_MOVED_OFF)
303 else
305 }
306
307 /*
308 * Clear all the visibility-related bits of this tuple and
309 * mark it as frozen. Also, get rid of HOT_UPDATED and
310 * KEYS_UPDATES bits.
311 */
316 }
317 }
318
319 /*
320 * If the page was modified, only then, we mark the buffer dirty or do
321 * the WAL logging.
322 */
323 if (did_modify_page)
324 {
325 /* Mark buffer dirty before we write WAL. */
327
328 /* XLOG stuff */
329 if (RelationNeedsWAL(rel))
330 {
332
335 /* Include the VM page if it was modified */
336 if (did_modify_vm)
339 if (did_modify_vm)
342 }
343 }
344
346
348
349 if (unlock_vmbuf)
351
352 if (BufferIsValid(vmbuf))
354
355 /* Update the current_start_ptr before moving to the next page. */
357 }
358
360
361 pfree(ta);
362
364}
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4156
#define PG_GETARG_ARRAYTYPE_P_COPY(n)
Definition array.h:264
#define ARR_DATA_PTR(a)
Definition array.h:322
int Buffer
Definition buf.h:23
#define InvalidBuffer
Definition buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5609
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5626
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3170
void LockBufferForCleanup(Buffer buffer)
Definition bufmgr.c:6693
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:879
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:309
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:468
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:222
@ BUFFER_LOCK_UNLOCK
Definition bufmgr.h:207
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:419
static bool PageIsAllVisible(const PageData *page)
Definition bufpage.h:454
static void PageClearAllVisible(Page page)
Definition bufpage.h:464
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:268
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:378
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:416
PageData * Page
Definition bufpage.h:81
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:396
#define Assert(condition)
Definition c.h:1002
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define NOTICE
Definition elog.h:36
#define ereport(elevel,...)
Definition elog.h:152
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_OID(n)
Definition fmgr.h:275
static int32 tidcmp(const void *a, const void *b)
static BlockNumber find_tids_one_page(ItemPointer tids, int ntids, OffsetNumber *next_start_ptr)
static void sanity_check_tid_array(ArrayType *ta, int *ntids)
HeapTupleHeaderData * HeapTupleHeader
Definition htup.h:23
#define HEAP_MOVED_OFF
#define HEAP_XMIN_FROZEN
#define HEAP_MOVED
static void HeapTupleHeaderSetXvac(HeapTupleHeaderData *tup, TransactionId xid)
#define HEAP_XMAX_INVALID
#define MaxHeapTuplesPerPage
static void HeapTupleHeaderSetXmin(HeapTupleHeaderData *tup, TransactionId xid)
static void HeapTupleHeaderSetXmax(HeapTupleHeaderData *tup, TransactionId xid)
#define ItemIdIsNormal(itemId)
Definition itemid.h:99
#define ItemIdGetRedirect(itemId)
Definition itemid.h:78
#define ItemIdIsDead(itemId)
Definition itemid.h:113
#define ItemIdSetDead(itemId)
Definition itemid.h:164
#define ItemIdIsUsed(itemId)
Definition itemid.h:92
#define ItemIdIsRedirected(itemId)
Definition itemid.h:106
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition itemptr.h:135
static OffsetNumber ItemPointerGetOffsetNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:114
ItemPointerData * ItemPointer
Definition itemptr.h:49
#define RowExclusiveLock
Definition lockdefs.h:38
void pfree(void *pointer)
Definition mcxt.c:1619
#define START_CRIT_SECTION()
Definition miscadmin.h:152
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
#define END_CRIT_SECTION()
Definition miscadmin.h:154
Oid GetUserId(void)
Definition miscinit.c:470
static char * errmsg
ObjectType get_relkind_objtype(char relkind)
#define InvalidOffsetNumber
Definition off.h:26
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
#define XLOG_FPI
Definition pg_control.h:83
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define qsort(a, b, c, d)
Definition port.h:496
unsigned int Oid
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationNeedsWAL(relation)
Definition rel.h:639
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48
ItemPointerData t_ctid
RelFileLocator rd_locator
Definition rel.h:57
Form_pg_class rd_rel
Definition rel.h:111
#define FrozenTransactionId
Definition transam.h:33
#define InvalidTransactionId
Definition transam.h:31
bool visibilitymap_clear(RelFileLocator rlocator, BlockNumber heapBlk, Buffer vmbuf, uint8 flags)
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
#define VISIBILITYMAP_VALID_BITS
bool RecoveryInProgress(void)
Definition xlog.c:6835
uint64 XLogRecPtr
Definition xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:482
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:246
void XLogBeginInsert(void)
Definition xloginsert.c:153
#define REGBUF_STANDARD
Definition xloginsert.h:35
#define REGBUF_FORCE_IMAGE
Definition xloginsert.h:32

References aclcheck_error(), ACLCHECK_NOT_OWNER, ARR_DATA_PTR, Assert, buf, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage(), BufferIsValid(), CHECK_FOR_INTERRUPTS, END_CRIT_SECTION, ereport, errcode(), errdetail_relkind_not_supported(), errhint(), errmsg, ERROR, fb(), find_tids_one_page(), FirstOffsetNumber, FrozenTransactionId, get_relkind_objtype(), GetUserId(), HEAP_FORCE_FREEZE, HEAP_FORCE_KILL, HEAP_MOVED, HEAP_MOVED_OFF, HEAP_XMAX_INVALID, HEAP_XMIN_FROZEN, HeapTupleHeaderSetXmax(), HeapTupleHeaderSetXmin(), HeapTupleHeaderSetXvac(), i, InvalidBuffer, InvalidOffsetNumber, InvalidTransactionId, ItemIdGetRedirect, ItemIdIsDead, ItemIdIsNormal, ItemIdIsRedirected, ItemIdIsUsed, ItemIdSetDead, ItemPointerGetOffsetNumberNoCheck(), ItemPointerSet(), LockBuffer(), LockBufferForCleanup(), MarkBufferDirty(), MaxHeapTuplesPerPage, NOTICE, object_ownercheck(), OffsetNumberNext, PageClearAllVisible(), PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PageIsAllVisible(), PageSetLSN(), pfree(), PG_GETARG_ARRAYTYPE_P_COPY, PG_GETARG_OID, PG_RETURN_VOID, qsort, RelationData::rd_locator, RelationData::rd_rel, ReadBuffer(), RecoveryInProgress(), REGBUF_FORCE_IMAGE, REGBUF_STANDARD, relation_close(), relation_open(), RelationGetNumberOfBlocks, RelationGetRelationName, RelationGetRelid, RelationNeedsWAL, ReleaseBuffer(), RowExclusiveLock, sanity_check_tid_array(), START_CRIT_SECTION, HeapTupleHeaderData::t_ctid, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, tidcmp(), UnlockReleaseBuffer(), visibilitymap_clear(), visibilitymap_pin(), VISIBILITYMAP_VALID_BITS, XLOG_FPI, XLogBeginInsert(), XLogInsert(), and XLogRegisterBuffer().

Referenced by heap_force_freeze(), and heap_force_kill().

◆ heap_force_freeze()

Datum heap_force_freeze ( PG_FUNCTION_ARGS  )

Definition at line 74 of file heap_surgery.c.

75{
77}
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
static Datum heap_force_common(FunctionCallInfo fcinfo, HeapTupleForceOption heap_force_opt)

References heap_force_common(), HEAP_FORCE_FREEZE, and PG_RETURN_DATUM.

◆ heap_force_kill()

Datum heap_force_kill ( PG_FUNCTION_ARGS  )

Definition at line 59 of file heap_surgery.c.

References heap_force_common(), HEAP_FORCE_KILL, and PG_RETURN_DATUM.

◆ PG_FUNCTION_INFO_V1() [1/2]

PG_FUNCTION_INFO_V1 ( heap_force_freeze  )

◆ PG_FUNCTION_INFO_V1() [2/2]

PG_FUNCTION_INFO_V1 ( heap_force_kill  )

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "pg_surgery",
version = PG_VERSION 
)

◆ sanity_check_tid_array()

static void sanity_check_tid_array ( ArrayType ta,
int ntids 
)
static

Definition at line 391 of file heap_surgery.c.

392{
396 errmsg("array must not contain nulls")));
397
398 if (ARR_NDIM(ta) > 1)
401 errmsg("argument must be empty or one-dimensional array")));
402
403 *ntids = ArrayGetNItems(ARR_NDIM(ta), ARR_DIMS(ta));
404}
#define ARR_NDIM(a)
Definition array.h:290
#define ARR_DIMS(a)
Definition array.h:294
#define ARR_HASNULL(a)
Definition array.h:291
bool array_contains_nulls(const ArrayType *array)
int ArrayGetNItems(int ndim, const int *dims)
Definition arrayutils.c:57

References ARR_DIMS, ARR_HASNULL, ARR_NDIM, array_contains_nulls(), ArrayGetNItems(), ereport, errcode(), errmsg, ERROR, and fb().

Referenced by heap_force_common().

◆ tidcmp()

static int32 tidcmp ( const void a,
const void b 
)
static

Definition at line 375 of file heap_surgery.c.

376{
377 const ItemPointerData *iptr1 = a;
378 const ItemPointerData *iptr2 = b;
379
381}
int b
Definition isn.c:74
int a
Definition isn.c:73
int32 ItemPointerCompare(const ItemPointerData *arg1, const ItemPointerData *arg2)
Definition itemptr.c:51

References a, b, fb(), and ItemPointerCompare().

Referenced by heap_force_common().