PostgreSQL Source Code git master
Loading...
Searching...
No Matches
tableam.c
Go to the documentation of this file.
1/*----------------------------------------------------------------------
2 *
3 * tableam.c
4 * Table access method routines too big to be inline functions.
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/access/table/tableam.c
12 *
13 * NOTES
14 * Note that most functions in here are documented in tableam.h, rather than
15 * here. That's because there's a lot of inline functions in tableam.h and
16 * it'd be harder to understand if one constantly had to switch between files.
17 *
18 *----------------------------------------------------------------------
19 */
20#include "postgres.h"
21
22#include <math.h>
23
24#include "access/syncscan.h"
25#include "access/tableam.h"
26#include "access/xact.h"
27#include "optimizer/optimizer.h"
28#include "optimizer/plancat.h"
29#include "port/pg_bitutils.h"
30#include "storage/bufmgr.h"
31#include "storage/shmem.h"
32#include "storage/smgr.h"
33
34/*
35 * Constants to control the behavior of block allocation to parallel workers
36 * during a parallel seqscan. Technically these values do not need to be
37 * powers of 2, but having them as powers of 2 makes the math more optimal
38 * and makes the ramp-down stepping more even.
39 */
40
41/* The number of I/O chunks we try to break a parallel seqscan down into */
42#define PARALLEL_SEQSCAN_NCHUNKS 2048
43/* Ramp down size of allocations when we've only this number of chunks left */
44#define PARALLEL_SEQSCAN_RAMPDOWN_CHUNKS 64
45/* Cap the size of parallel I/O chunks to this number of blocks */
46#define PARALLEL_SEQSCAN_MAX_CHUNK_SIZE 8192
47
48/* GUC variables */
51
52
53/* ----------------------------------------------------------------------------
54 * Slot functions.
55 * ----------------------------------------------------------------------------
56 */
57
60{
62
63 if (relation->rd_tableam)
64 tts_cb = relation->rd_tableam->slot_callbacks(relation);
65 else if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
66 {
67 /*
68 * Historically FDWs expect to store heap tuples in slots. Continue
69 * handing them one, to make it less painful to adapt FDWs to new
70 * versions. The cost of a heap slot over a virtual slot is pretty
71 * small.
72 */
74 }
75 else
76 {
77 /*
78 * These need to be supported, as some parts of the code (like COPY)
79 * need to create slots for such relations too. It seems better to
80 * centralize the knowledge that a heap slot is the right thing in
81 * that case here.
82 */
83 Assert(relation->rd_rel->relkind == RELKIND_VIEW ||
84 relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
86 }
87
88 return tts_cb;
89}
90
93{
95 TupleTableSlot *slot;
96
97 tts_cb = table_slot_callbacks(relation);
99
100 if (reglist)
101 *reglist = lappend(*reglist, slot);
102
103 return slot;
104}
105
106
107/* ----------------------------------------------------------------------------
108 * Table scan functions.
109 * ----------------------------------------------------------------------------
110 */
111
114{
115 uint32 flags = SO_TYPE_SEQSCAN |
117 Oid relid = RelationGetRelid(relation);
119
120 return table_beginscan_common(relation, snapshot, nkeys, key,
121 NULL, flags, SO_NONE);
122}
123
124
125/* ----------------------------------------------------------------------------
126 * Parallel table scan related functions.
127 * ----------------------------------------------------------------------------
128 */
129
130Size
132{
133 Size sz = 0;
134
135 if (IsMVCCSnapshot(snapshot))
136 sz = add_size(sz, EstimateSnapshotSpace(snapshot));
137 else
138 Assert(snapshot == SnapshotAny);
139
141
142 return sz;
143}
144
145void
147 Snapshot snapshot)
148{
150
151 pscan->phs_snapshot_off = snapshot_off;
152
153 if (IsMVCCSnapshot(snapshot))
154 {
155 SerializeSnapshot(snapshot, (char *) pscan + pscan->phs_snapshot_off);
156 pscan->phs_snapshot_any = false;
157 }
158 else
159 {
160 Assert(snapshot == SnapshotAny);
161 pscan->phs_snapshot_any = true;
162 }
163}
164
167 uint32 flags)
168{
169 Snapshot snapshot;
172
173 Assert(RelFileLocatorEquals(relation->rd_locator, pscan->phs_locator));
174
175 if (!pscan->phs_snapshot_any)
176 {
177 /* Snapshot was serialized -- restore it */
178 snapshot = RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
179 RegisterSnapshot(snapshot);
181 }
182 else
183 {
184 /* SnapshotAny passed by caller (not serialized) */
185 snapshot = SnapshotAny;
186 }
187
188 return table_beginscan_common(relation, snapshot, 0, NULL,
189 pscan, internal_flags, flags);
190}
191
195 uint32 flags)
196{
197 Snapshot snapshot;
200
201 Assert(RelFileLocatorEquals(relation->rd_locator, pscan->phs_locator));
202
203 /* disable syncscan in parallel tid range scan. */
204 pscan->phs_syncscan = false;
205
206 if (!pscan->phs_snapshot_any)
207 {
208 /* Snapshot was serialized -- restore it */
209 snapshot = RestoreSnapshot((char *) pscan + pscan->phs_snapshot_off);
210 RegisterSnapshot(snapshot);
212 }
213 else
214 {
215 /* SnapshotAny passed by caller (not serialized) */
216 snapshot = SnapshotAny;
217 }
218
219 sscan = table_beginscan_common(relation, snapshot, 0, NULL,
220 pscan, internal_flags, flags);
221 return sscan;
222}
223
224
225/* ----------------------------------------------------------------------------
226 * Index scan related functions.
227 * ----------------------------------------------------------------------------
228 */
229
230/*
231 * To perform that check simply start an index scan, create the necessary
232 * slot, do the heap lookup, and shut everything down again. This could be
233 * optimized, but is unlikely to matter from a performance POV. If there
234 * frequently are live index pointers also matching a unique index key, the
235 * CPU overhead of this routine is unlikely to matter.
236 *
237 * Note that *tid may be modified when we return true if the AM supports
238 * storing multiple row versions reachable via a single index entry (like
239 * heap's HOT).
240 */
241bool
243 ItemPointer tid,
244 Snapshot snapshot,
245 bool *all_dead)
246{
248 TupleTableSlot *slot;
249 bool call_again = false;
250 bool found;
251
252 slot = table_slot_create(rel, NULL);
253 scan = table_index_fetch_begin(rel, SO_NONE);
254 found = table_index_fetch_tuple(scan, tid, snapshot, slot, &call_again,
255 all_dead);
258
259 return found;
260}
261
262
263/* ------------------------------------------------------------------------
264 * Functions for non-modifying operations on individual tuples
265 * ------------------------------------------------------------------------
266 */
267
268void
270{
271 Relation rel = scan->rs_rd;
272 const TableAmRoutine *tableam = rel->rd_tableam;
273
274 /*
275 * Since this can be called with user-supplied TID, don't trust the input
276 * too much.
277 */
278 if (!tableam->tuple_tid_valid(scan, tid))
281 errmsg("tid (%u, %u) is not valid for relation \"%s\"",
285
286 tableam->tuple_get_latest_tid(scan, tid);
287}
288
289
290/* ----------------------------------------------------------------------------
291 * Functions to make modifications a bit simpler.
292 * ----------------------------------------------------------------------------
293 */
294
295/*
296 * simple_table_tuple_insert - insert a tuple
297 *
298 * Currently, this routine differs from table_tuple_insert only in supplying a
299 * default command ID and not allowing access to the speedup options.
300 */
301void
306
307/*
308 * simple_table_tuple_delete - delete a tuple
309 *
310 * This routine may be used to delete a tuple when concurrent updates of
311 * the target tuple are not expected (for example, because we have a lock
312 * on the relation associated with the tuple). Any failure is reported
313 * via ereport().
314 */
315void
317{
319 TM_FailureData tmfd;
320
321 result = table_tuple_delete(rel, tid,
323 0, snapshot, InvalidSnapshot,
324 true /* wait for commit */ ,
325 &tmfd);
326
327 switch (result)
328 {
329 case TM_SelfModified:
330 /* Tuple was already updated in current command? */
331 elog(ERROR, "tuple already updated by self");
332 break;
333
334 case TM_Ok:
335 /* done successfully */
336 break;
337
338 case TM_Updated:
339 elog(ERROR, "tuple concurrently updated");
340 break;
341
342 case TM_Deleted:
343 elog(ERROR, "tuple concurrently deleted");
344 break;
345
346 default:
347 elog(ERROR, "unrecognized table_tuple_delete status: %u", result);
348 break;
349 }
350}
351
352/*
353 * simple_table_tuple_update - replace a tuple
354 *
355 * This routine may be used to update a tuple when concurrent updates of
356 * the target tuple are not expected (for example, because we have a lock
357 * on the relation associated with the tuple). Any failure is reported
358 * via ereport().
359 */
360void
362 TupleTableSlot *slot,
363 Snapshot snapshot,
365{
367 TM_FailureData tmfd;
368 LockTupleMode lockmode;
369
370 result = table_tuple_update(rel, otid, slot,
372 0, snapshot, InvalidSnapshot,
373 true /* wait for commit */ ,
374 &tmfd, &lockmode, update_indexes);
375
376 switch (result)
377 {
378 case TM_SelfModified:
379 /* Tuple was already updated in current command? */
380 elog(ERROR, "tuple already updated by self");
381 break;
382
383 case TM_Ok:
384 /* done successfully */
385 break;
386
387 case TM_Updated:
388 elog(ERROR, "tuple concurrently updated");
389 break;
390
391 case TM_Deleted:
392 elog(ERROR, "tuple concurrently deleted");
393 break;
394
395 default:
396 elog(ERROR, "unrecognized table_tuple_update status: %u", result);
397 break;
398 }
399}
400
401
402/* ----------------------------------------------------------------------------
403 * Helper functions to implement parallel scans for block oriented AMs.
404 * ----------------------------------------------------------------------------
405 */
406
407Size
412
413Size
415{
417
419 bpscan->phs_nblocks = RelationGetNumberOfBlocks(rel);
420 /* compare phs_syncscan initialization to similar logic in initscan */
421 bpscan->base.phs_syncscan = synchronize_seqscans &&
423 bpscan->phs_nblocks > NBuffers / 4;
424 SpinLockInit(&bpscan->phs_mutex);
425 bpscan->phs_startblock = InvalidBlockNumber;
426 bpscan->phs_numblock = InvalidBlockNumber;
427 pg_atomic_init_u64(&bpscan->phs_nallocated, 0);
428
429 return sizeof(ParallelBlockTableScanDescData);
430}
431
432void
439
440/*
441 * find and set the scan's startblock
442 *
443 * Determine where the parallel seq scan should start. This function may be
444 * called many times, once by each parallel worker. We must be careful only
445 * to set the phs_startblock and phs_numblock fields once.
446 *
447 * Callers may optionally specify a non-InvalidBlockNumber value for
448 * 'startblock' to force the scan to start at the given page. Likewise,
449 * 'numblocks' can be specified as a non-InvalidBlockNumber to limit the
450 * number of blocks to scan to that many blocks.
451 */
452void
456 BlockNumber startblock,
458{
459 StaticAssertDecl(MaxBlockNumber <= 0xFFFFFFFE,
460 "pg_nextpower2_32 may be too small for non-standard BlockNumber width");
461
464
465 /* Reset the state we use for controlling allocation size. */
466 memset(pbscanwork, 0, sizeof(*pbscanwork));
467
468retry:
469 /* Grab the spinlock. */
470 SpinLockAcquire(&pbscan->phs_mutex);
471
472 /*
473 * When the caller specified a limit on the number of blocks to scan, set
474 * that in the ParallelBlockTableScanDesc, if it's not been done by
475 * another worker already.
476 */
478 pbscan->phs_numblock == InvalidBlockNumber)
479 {
480 pbscan->phs_numblock = numblocks;
481 }
482
483 /*
484 * If the scan's phs_startblock has not yet been initialized, we must do
485 * so now. If a startblock was specified, start there, otherwise if this
486 * is not a synchronized scan, we just start at block 0, but if it is a
487 * synchronized scan, we must get the starting position from the
488 * synchronized scan machinery. We can't hold the spinlock while doing
489 * that, though, so release the spinlock, get the information we need, and
490 * retry. If nobody else has initialized the scan in the meantime, we'll
491 * fill in the value we fetched on the second time through.
492 */
493 if (pbscan->phs_startblock == InvalidBlockNumber)
494 {
495 if (startblock != InvalidBlockNumber)
496 pbscan->phs_startblock = startblock;
497 else if (!pbscan->base.phs_syncscan)
498 pbscan->phs_startblock = 0;
500 pbscan->phs_startblock = sync_startpage;
501 else
502 {
503 SpinLockRelease(&pbscan->phs_mutex);
504 sync_startpage = ss_get_location(rel, pbscan->phs_nblocks);
505 goto retry;
506 }
507 }
508 SpinLockRelease(&pbscan->phs_mutex);
509
510 /*
511 * Figure out how many blocks we're going to scan; either all of them, or
512 * just phs_numblock's worth, if a limit has been imposed.
513 */
514 if (pbscan->phs_numblock == InvalidBlockNumber)
515 scan_nblocks = pbscan->phs_nblocks;
516 else
517 scan_nblocks = pbscan->phs_numblock;
518
519 /*
520 * We determine the chunk size based on scan_nblocks. First we split
521 * scan_nblocks into PARALLEL_SEQSCAN_NCHUNKS chunks then we calculate the
522 * next highest power of 2 number of the result. This means we split the
523 * blocks we're scanning into somewhere between PARALLEL_SEQSCAN_NCHUNKS
524 * and PARALLEL_SEQSCAN_NCHUNKS / 2 chunks.
525 */
526 pbscanwork->phsw_chunk_size = pg_nextpower2_32(Max(scan_nblocks /
528
529 /*
530 * Ensure we don't go over the maximum chunk size with larger tables. This
531 * means we may get much more than PARALLEL_SEQSCAN_NCHUNKS for larger
532 * tables. Too large a chunk size has been shown to be detrimental to
533 * sequential scan performance.
534 */
535 pbscanwork->phsw_chunk_size = Min(pbscanwork->phsw_chunk_size,
537}
538
539/*
540 * get the next page to scan
541 *
542 * Get the next page to scan. Even if there are no pages left to scan,
543 * another backend could have grabbed a page to scan and not yet finished
544 * looking at it, so it doesn't follow that the scan is done when the first
545 * backend gets an InvalidBlockNumber return.
546 */
551{
553 BlockNumber page;
554 uint64 nallocated;
555
556 /*
557 * The logic below allocates block numbers out to parallel workers in a
558 * way that each worker will receive a set of consecutive block numbers to
559 * scan. Earlier versions of this would allocate the next highest block
560 * number to the next worker to call this function. This would generally
561 * result in workers never receiving consecutive block numbers. Some
562 * operating systems would not detect the sequential I/O pattern due to
563 * each backend being a different process which could result in poor
564 * performance due to inefficient or no readahead. To work around this
565 * issue, we now allocate a range of block numbers for each worker and
566 * when they come back for another block, we give them the next one in
567 * that range until the range is complete. When the worker completes the
568 * range of blocks we then allocate another range for it and return the
569 * first block number from that range.
570 *
571 * Here we name these ranges of blocks "chunks". The initial size of
572 * these chunks is determined in table_block_parallelscan_startblock_init
573 * based on the number of blocks to scan. Towards the end of the scan, we
574 * start making reductions in the size of the chunks in order to attempt
575 * to divide the remaining work over all the workers as evenly as
576 * possible.
577 *
578 * Here pbscanwork is local worker memory. phsw_chunk_remaining tracks
579 * the number of blocks remaining in the chunk. When that reaches 0 then
580 * we must allocate a new chunk for the worker.
581 *
582 * phs_nallocated tracks how many blocks have been allocated to workers
583 * already. When phs_nallocated >= rs_nblocks, all blocks have been
584 * allocated.
585 *
586 * Because we use an atomic fetch-and-add to fetch the current value, the
587 * phs_nallocated counter will exceed rs_nblocks, because workers will
588 * still increment the value, when they try to allocate the next block but
589 * all blocks have been allocated already. The counter must be 64 bits
590 * wide because of that, to avoid wrapping around when scan_nblocks is
591 * close to 2^32.
592 *
593 * The actual block to return is calculated by adding the counter to the
594 * starting block number, modulo phs_nblocks.
595 */
596
597 /* First, figure out how many blocks we're planning on scanning */
598 if (pbscan->phs_numblock == InvalidBlockNumber)
599 scan_nblocks = pbscan->phs_nblocks;
600 else
601 scan_nblocks = pbscan->phs_numblock;
602
603 /*
604 * Now check if we have any remaining blocks in a previous chunk for this
605 * worker. We must consume all of the blocks from that before we allocate
606 * a new chunk to the worker.
607 */
608 if (pbscanwork->phsw_chunk_remaining > 0)
609 {
610 /*
611 * Give them the next block in the range and update the remaining
612 * number of blocks.
613 */
614 nallocated = ++pbscanwork->phsw_nallocated;
615 pbscanwork->phsw_chunk_remaining--;
616 }
617 else
618 {
619 /*
620 * When we've only got PARALLEL_SEQSCAN_RAMPDOWN_CHUNKS chunks
621 * remaining in the scan, we half the chunk size. Since we reduce the
622 * chunk size here, we'll hit this again after doing
623 * PARALLEL_SEQSCAN_RAMPDOWN_CHUNKS at the new size. After a few
624 * iterations of this, we'll end up doing the last few blocks with the
625 * chunk size set to 1.
626 */
627 if (pbscanwork->phsw_chunk_size > 1 &&
628 pbscanwork->phsw_nallocated > scan_nblocks -
629 (pbscanwork->phsw_chunk_size * PARALLEL_SEQSCAN_RAMPDOWN_CHUNKS))
630 pbscanwork->phsw_chunk_size >>= 1;
631
632 nallocated = pbscanwork->phsw_nallocated =
633 pg_atomic_fetch_add_u64(&pbscan->phs_nallocated,
634 pbscanwork->phsw_chunk_size);
635
636 /*
637 * Set the remaining number of blocks in this chunk so that subsequent
638 * calls from this worker continue on with this chunk until it's done.
639 */
640 pbscanwork->phsw_chunk_remaining = pbscanwork->phsw_chunk_size - 1;
641 }
642
643 /* Check if we've run out of blocks to scan */
644 if (nallocated >= scan_nblocks)
645 page = InvalidBlockNumber; /* all blocks have been allocated */
646 else
647 page = (nallocated + pbscan->phs_startblock) % pbscan->phs_nblocks;
648
649 /*
650 * Report scan location. Normally, we report the current page number.
651 * When we reach the end of the scan, though, we report the starting page,
652 * not the ending page, just so the starting positions for later scans
653 * doesn't slew backwards. We only report the position at the end of the
654 * scan once, though: subsequent callers will report nothing.
655 */
656 if (pbscan->base.phs_syncscan)
657 {
658 if (page != InvalidBlockNumber)
659 ss_report_location(rel, page);
660 else if (nallocated == pbscan->phs_nblocks)
661 ss_report_location(rel, pbscan->phs_startblock);
662 }
663
664 return page;
665}
666
667/* ----------------------------------------------------------------------------
668 * Helper functions to implement relation sizing for block oriented AMs.
669 * ----------------------------------------------------------------------------
670 */
671
672/*
673 * table_block_relation_size
674 *
675 * If a table AM uses the various relation forks as the sole place where data
676 * is stored, and if it uses them in the expected manner (e.g. the actual data
677 * is in the main fork rather than some other), it can use this implementation
678 * of the relation_size callback rather than implementing its own.
679 */
680uint64
682{
683 uint64 nblocks = 0;
684
685 /* InvalidForkNumber indicates returning the size for all forks */
687 {
688 for (int i = 0; i < MAX_FORKNUM; i++)
689 nblocks += smgrnblocks(RelationGetSmgr(rel), i);
690 }
691 else
692 nblocks = smgrnblocks(RelationGetSmgr(rel), forkNumber);
693
694 return nblocks * BLCKSZ;
695}
696
697/*
698 * table_block_relation_estimate_size
699 *
700 * This function can't be directly used as the implementation of the
701 * relation_estimate_size callback, because it has a few additional parameters.
702 * Instead, it is intended to be used as a helper function; the caller can
703 * pass through the arguments to its relation_estimate_size function plus the
704 * additional values required here.
705 *
706 * overhead_bytes_per_tuple should contain the approximate number of bytes
707 * of storage required to store a tuple above and beyond what is required for
708 * the tuple data proper. Typically, this would include things like the
709 * size of the tuple header and item pointer. This is only used for query
710 * planning, so a table AM where the value is not constant could choose to
711 * pass a "best guess".
712 *
713 * usable_bytes_per_page should contain the approximate number of bytes per
714 * page usable for tuple data, excluding the page header and any anticipated
715 * special space.
716 */
717void
719 BlockNumber *pages, double *tuples,
720 double *allvisfrac,
723{
725 BlockNumber relpages;
726 double reltuples;
727 BlockNumber relallvisible;
728 double density;
729
730 /* it should have storage, so we can call the smgr */
732
733 /* coerce values in pg_class to more desirable types */
734 relpages = (BlockNumber) rel->rd_rel->relpages;
735 reltuples = (double) rel->rd_rel->reltuples;
736 relallvisible = (BlockNumber) rel->rd_rel->relallvisible;
737
738 /*
739 * HACK: if the relation has never yet been vacuumed, use a minimum size
740 * estimate of 10 pages. The idea here is to avoid assuming a
741 * newly-created table is really small, even if it currently is, because
742 * that may not be true once some data gets loaded into it. Once a vacuum
743 * or analyze cycle has been done on it, it's more reasonable to believe
744 * the size is somewhat stable.
745 *
746 * (Note that this is only an issue if the plan gets cached and used again
747 * after the table has been filled. What we're trying to avoid is using a
748 * nestloop-type plan on a table that has grown substantially since the
749 * plan was made. Normally, autovacuum/autoanalyze will occur once enough
750 * inserts have happened and cause cached-plan invalidation; but that
751 * doesn't happen instantaneously, and it won't happen at all for cases
752 * such as temporary tables.)
753 *
754 * We test "never vacuumed" by seeing whether reltuples < 0.
755 *
756 * If the table has inheritance children, we don't apply this heuristic.
757 * Totally empty parent tables are quite common, so we should be willing
758 * to believe that they are empty.
759 */
760 if (curpages < 10 &&
761 reltuples < 0 &&
762 !rel->rd_rel->relhassubclass)
763 curpages = 10;
764
765 /* report estimated # pages */
766 *pages = curpages;
767 /* quick exit if rel is clearly empty */
768 if (curpages == 0)
769 {
770 *tuples = 0;
771 *allvisfrac = 0;
772 return;
773 }
774
775 /* estimate number of tuples from previous tuple density */
776 if (reltuples >= 0 && relpages > 0)
777 density = reltuples / (double) relpages;
778 else
779 {
780 /*
781 * When we have no data because the relation was never yet vacuumed,
782 * estimate tuple width from attribute datatypes. We assume here that
783 * the pages are completely full, which is OK for tables but is
784 * probably an overestimate for indexes. Fortunately
785 * get_relation_info() can clamp the overestimate to the parent
786 * table's size.
787 *
788 * Note: this code intentionally disregards alignment considerations,
789 * because (a) that would be gilding the lily considering how crude
790 * the estimate is, (b) it creates platform dependencies in the
791 * default plans which are kind of a headache for regression testing,
792 * and (c) different table AMs might use different padding schemes.
793 */
795 int fillfactor;
796
797 /*
798 * Without reltuples/relpages, we also need to consider fillfactor.
799 * The other branch considers it implicitly by calculating density
800 * from actual relpages/reltuples statistics.
801 */
803
806 /* note: integer division is intentional here */
808 /* There's at least one row on the page, even with low fillfactor. */
810 }
811 *tuples = rint(density * (double) curpages);
812
813 /*
814 * We use relallvisible as-is, rather than scaling it up like we do for
815 * the pages and tuples counts, on the theory that any pages added since
816 * the last VACUUM are most likely not marked all-visible. But costsize.c
817 * wants it converted to a fraction.
818 */
819 if (relallvisible == 0 || curpages <= 0)
820 *allvisfrac = 0;
821 else if ((double) relallvisible >= curpages)
822 *allvisfrac = 1;
823 else
824 *allvisfrac = (double) relallvisible / curpages;
825}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:485
static uint64 pg_atomic_fetch_add_u64(volatile pg_atomic_uint64 *ptr, int64 add_)
Definition atomics.h:532
static void pg_atomic_init_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:453
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
#define MaxBlockNumber
Definition block.h:35
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:309
#define Min(x, y)
Definition c.h:1091
#define Max(x, y)
Definition c.h:1085
#define Assert(condition)
Definition c.h:943
int32_t int32
Definition c.h:620
uint64_t uint64
Definition c.h:625
uint32_t uint32
Definition c.h:624
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1008
size_t Size
Definition c.h:689
uint32 result
double clamp_row_est(double nrows)
Definition costsize.c:214
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsHeapTuple
Definition execTuples.c:85
int NBuffers
Definition globals.c:144
int i
Definition isn.c:77
static OffsetNumber ItemPointerGetOffsetNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:114
static BlockNumber ItemPointerGetBlockNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:93
List * lappend(List *list, void *datum)
Definition list.c:339
LockTupleMode
Definition lockoptions.h:51
static char * errmsg
static uint32 pg_nextpower2_32(uint32 num)
static int fillfactor
Definition pgbench.c:188
int32 get_rel_data_width(Relation rel, int32 *attr_widths)
Definition plancat.c:1430
unsigned int Oid
static int fb(int x)
#define RelationGetRelid(relation)
Definition rel.h:516
static SMgrRelation RelationGetSmgr(Relation rel)
Definition rel.h:578
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetFillFactor(relation, defaultff)
Definition rel.h:376
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationUsesLocalBuffers(relation)
Definition rel.h:648
#define HEAP_DEFAULT_FILLFACTOR
Definition rel.h:362
#define RelFileLocatorEquals(locator1, locator2)
ForkNumber
Definition relpath.h:56
@ InvalidForkNumber
Definition relpath.h:57
#define MAX_FORKNUM
Definition relpath.h:70
struct ParallelBlockTableScanDescData * ParallelBlockTableScanDesc
Definition relscan.h:109
Size add_size(Size s1, Size s2)
Definition shmem.c:1048
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:819
void SerializeSnapshot(Snapshot snapshot, char *start_address)
Definition snapmgr.c:1736
Snapshot GetCatalogSnapshot(Oid relid)
Definition snapmgr.c:385
Snapshot RestoreSnapshot(char *start_address)
Definition snapmgr.c:1793
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:824
Size EstimateSnapshotSpace(Snapshot snapshot)
Definition snapmgr.c:1712
#define SnapshotAny
Definition snapmgr.h:33
#define IsMVCCSnapshot(snapshot)
Definition snapmgr.h:59
#define InvalidSnapshot
Definition snapshot.h:119
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
Definition pg_list.h:54
ParallelTableScanDescData base
Definition relscan.h:99
RelFileLocator phs_locator
Definition relscan.h:87
const struct TableAmRoutine * rd_tableam
Definition rel.h:189
RelFileLocator rd_locator
Definition rel.h:57
Form_pg_class rd_rel
Definition rel.h:111
Size(* parallelscan_initialize)(Relation rel, ParallelTableScanDesc pscan)
Definition tableam.h:432
void(* tuple_get_latest_tid)(TableScanDesc scan, ItemPointer tid)
Definition tableam.h:524
const TupleTableSlotOps *(* slot_callbacks)(Relation rel)
Definition tableam.h:335
bool(* tuple_tid_valid)(TableScanDesc scan, ItemPointer tid)
Definition tableam.h:517
Size(* parallelscan_estimate)(Relation rel)
Definition tableam.h:425
Relation rs_rd
Definition relscan.h:36
void ss_report_location(Relation rel, BlockNumber location)
Definition syncscan.c:287
BlockNumber ss_get_location(Relation rel, BlockNumber relnblocks)
Definition syncscan.c:252
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition tableam.c:92
#define PARALLEL_SEQSCAN_MAX_CHUNK_SIZE
Definition tableam.c:46
void simple_table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, Snapshot snapshot, TU_UpdateIndexes *update_indexes)
Definition tableam.c:361
bool table_index_fetch_tuple_check(Relation rel, ItemPointer tid, Snapshot snapshot, bool *all_dead)
Definition tableam.c:242
Size table_block_parallelscan_initialize(Relation rel, ParallelTableScanDesc pscan)
Definition tableam.c:414
TableScanDesc table_beginscan_parallel_tidrange(Relation relation, ParallelTableScanDesc pscan, uint32 flags)
Definition tableam.c:193
void simple_table_tuple_insert(Relation rel, TupleTableSlot *slot)
Definition tableam.c:302
#define PARALLEL_SEQSCAN_RAMPDOWN_CHUNKS
Definition tableam.c:44
TableScanDesc table_beginscan_parallel(Relation relation, ParallelTableScanDesc pscan, uint32 flags)
Definition tableam.c:166
char * default_table_access_method
Definition tableam.c:49
void table_tuple_get_latest_tid(TableScanDesc scan, ItemPointer tid)
Definition tableam.c:269
void simple_table_tuple_delete(Relation rel, ItemPointer tid, Snapshot snapshot)
Definition tableam.c:316
void table_block_parallelscan_reinitialize(Relation rel, ParallelTableScanDesc pscan)
Definition tableam.c:433
uint64 table_block_relation_size(Relation rel, ForkNumber forkNumber)
Definition tableam.c:681
Size table_parallelscan_estimate(Relation rel, Snapshot snapshot)
Definition tableam.c:131
TableScanDesc table_beginscan_catalog(Relation relation, int nkeys, ScanKeyData *key)
Definition tableam.c:113
Size table_block_parallelscan_estimate(Relation rel)
Definition tableam.c:408
void table_block_parallelscan_startblock_init(Relation rel, ParallelBlockTableScanWorker pbscanwork, ParallelBlockTableScanDesc pbscan, BlockNumber startblock, BlockNumber numblocks)
Definition tableam.c:453
#define PARALLEL_SEQSCAN_NCHUNKS
Definition tableam.c:42
void table_parallelscan_initialize(Relation rel, ParallelTableScanDesc pscan, Snapshot snapshot)
Definition tableam.c:146
const TupleTableSlotOps * table_slot_callbacks(Relation relation)
Definition tableam.c:59
BlockNumber table_block_parallelscan_nextpage(Relation rel, ParallelBlockTableScanWorker pbscanwork, ParallelBlockTableScanDesc pbscan)
Definition tableam.c:548
void table_block_relation_estimate_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac, Size overhead_bytes_per_tuple, Size usable_bytes_per_page)
Definition tableam.c:718
bool synchronize_seqscans
Definition tableam.c:50
#define DEFAULT_TABLE_ACCESS_METHOD
Definition tableam.h:29
@ SO_ALLOW_STRAT
Definition tableam.h:61
@ SO_TYPE_TIDRANGESCAN
Definition tableam.h:56
@ SO_TEMP_SNAPSHOT
Definition tableam.h:68
@ SO_ALLOW_PAGEMODE
Definition tableam.h:65
@ SO_ALLOW_SYNC
Definition tableam.h:63
@ SO_NONE
Definition tableam.h:49
@ SO_TYPE_SEQSCAN
Definition tableam.h:52
TU_UpdateIndexes
Definition tableam.h:133
TM_Result
Definition tableam.h:95
@ TM_Ok
Definition tableam.h:100
@ TM_Deleted
Definition tableam.h:115
@ TM_Updated
Definition tableam.h:112
@ TM_SelfModified
Definition tableam.h:106
static TableScanDesc table_beginscan_common(Relation rel, Snapshot snapshot, int nkeys, ScanKeyData *key, ParallelTableScanDesc pscan, uint32 flags, uint32 user_flags)
Definition tableam.h:917
static void table_index_fetch_end(struct IndexFetchTableData *scan)
Definition tableam.h:1275
static bool table_index_fetch_tuple(struct IndexFetchTableData *scan, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, bool *call_again, bool *all_dead)
Definition tableam.h:1305
static void table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid, uint32 options, BulkInsertStateData *bistate)
Definition tableam.h:1458
static TM_Result table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, CommandId cid, uint32 options, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes)
Definition tableam.h:1600
static IndexFetchTableData * table_index_fetch_begin(Relation rel, uint32 flags)
Definition tableam.h:1246
static TM_Result table_tuple_delete(Relation rel, ItemPointer tid, CommandId cid, uint32 options, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd)
Definition tableam.h:1549
CommandId GetCurrentCommandId(bool used)
Definition xact.c:831