PostgreSQL Source Code: src/backend/access/heap/pruneheap.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
16
31
32
33typedef struct
34{
35
36
37
38
39
40
42
44
47
48
49
50
51
54 int nredirected;
58
63
64
65
66
67
68
69
70
71
72
73
74
79
80
81
82
83
84
85
87
88
89
90
91
92
93
94
95
96
97
99
100
101
102
104
105
106
107
108
109
110
111
112
113
114
116
117
120
121
123
124
125
126
127
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
154
155
165 bool was_normal);
167 bool was_normal);
169 bool was_normal);
171
176
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192void
194{
198 Size minfree;
199
200
201
202
203
204
206 return;
207
208
209
210
211
212
213 prune_xid = ((PageHeader) page)->pd_prune_xid;
215 return;
216
217
218
219
220
222
224 return;
225
226
227
228
229
230
231
232
233
234
235
236
237
240 minfree = Max(minfree, BLCKSZ / 10);
241
243 {
244
246 return;
247
248
249
250
251
252
254 {
257
258
259
260
261
262
264 NULL, &presult, PRUNE_ON_ACCESS, &dummy_off_loc, NULL, NULL);
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
283 }
284
285
287
288
289
290
291
292
293 }
294}
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349void
359{
363 maxoff;
366 bool do_freeze;
367 bool do_prune;
368 bool do_hint;
369 bool hint_bit_fpi;
371
372
373 prstate.vistest = vistest;
376 prstate.cutoffs = cutoffs;
377
378
379
380
381
382
383
384
385
386
387
388
394
395
398 {
399 Assert(new_relfrozen_xid && new_relmin_mxid);
404 }
405 else
406 {
407 Assert(new_relfrozen_xid == NULL && new_relmin_mxid == NULL);
412 }
413
417 prstate.hastup = false;
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
445 {
448 }
449 else
450 {
451
452
453
454
457 }
458
459
460
461
462
463
464
465
466
468
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492 for (offnum = maxoff;
495 {
498
499
500
501
502
503 *off_loc = offnum;
504
505 prstate.processed[offnum] = false;
506 prstate.htsv[offnum] = -1;
507
508
510 {
512 continue;
513 }
514
516 {
517
518
519
520
523 else
525 continue;
526 }
527
529 {
530
532 continue;
533 }
534
536
537
538
539
544
546 buffer);
547
550 else
552 }
553
554
555
556
557
559
560
561
562
563
564
565
566
567
568
569
570
572 {
574
575
577 continue;
578
579
580 *off_loc = offnum;
581
582
584 }
585
586
587
588
589
591 {
593
595 continue;
596
597
598 *off_loc = offnum;
599
600
601
602
603
604
605
606
607
608
609
610
611
612
614 {
617
619 {
623 }
624 else
625 {
626
627
628
629
630
631
632
633
634 elog(ERROR, "dead heap-only tuple (%u, %d) is not linked to from any HOT chain",
635 blockno, offnum);
636 }
637 }
638 else
640 }
641
642
643#ifdef USE_ASSERT_CHECKING
645 offnum <= maxoff;
647 {
648 *off_loc = offnum;
649
651 }
652#endif
653
654
656
658 prstate.ndead > 0 ||
660
661
662
663
664
665
668
669
670
671
672
673 do_freeze = false;
675 {
677 {
678
679
680
681
682
683 do_freeze = true;
684 }
685 else
686 {
687
688
689
690
691
692
693
694
695
696
697
698
700 {
701
702
703
704
706 {
707 if (hint_bit_fpi)
708 do_freeze = true;
709 else if (do_prune)
710 {
712 do_freeze = true;
713 }
714 else if (do_hint)
715 {
717 do_freeze = true;
718 }
719 }
720 }
721 }
722 }
723
724 if (do_freeze)
725 {
726
727
728
729
731 }
732 else if (prstate.nfrozen > 0)
733 {
734
735
736
737
739
741 prstate.nfrozen = 0;
742 }
743 else
744 {
745
746
747
748
749
750
751 }
752
753
755
756 if (do_hint)
757 {
758
759
760
761
763
764
765
766
767
768
770
771
772
773
774
775
776 if (!do_freeze && !do_prune)
778 }
779
780 if (do_prune || do_freeze)
781 {
782
783 if (do_prune)
784 {
789 }
790
791 if (do_freeze)
793
795
796
797
798
800 {
801
802
803
804
805
806
807
808
809
810
813
814
815
816
817
818
819
820 if (do_freeze)
821 {
824 else
825 {
826
829 }
830 }
831
833 conflict_xid = frz_conflict_horizon;
834 else
836
838 conflict_xid,
839 true, reason,
844 }
845 }
846
848
849
855
856
857
858
859
860
861
862
863
864
865
866
867
869 {
872 }
873 else
874 {
877 }
878
880
881
882
883
884
885
886
887
888
891 else
893
895
896
898 {
899 if (presult->nfrozen > 0)
900 {
903 }
904 else
905 {
908 }
909 }
910}
911
912
913
914
915
918{
921
923
925 return res;
926
927
928
929
930
931
932
937
938
939
940
941
942
943
944
945
948
949 return res;
950}
951
952
953
954
955
956
957
958
961{
965}
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998static void
1001{
1006
1007
1008
1009
1010
1011 int ndeadchain = 0,
1012 nchain = 0;
1013
1015
1016
1017 offnum = rootoffnum;
1018
1019
1020 for (;;)
1021 {
1024
1025
1027 break;
1028
1029
1030
1031
1032
1033 if (offnum > maxoff)
1034 break;
1035
1036
1038 break;
1039
1041
1042
1043
1044
1045
1046
1049
1050
1051
1052
1053
1054
1056 {
1057 if (nchain > 0)
1058 break;
1059 chainitems[nchain++] = offnum;
1061 continue;
1062 }
1063
1065
1067
1068
1069
1070
1073 break;
1074
1075
1076
1077
1078 chainitems[nchain++] = offnum;
1079
1081 {
1083
1084
1085 ndeadchain = nchain;
1088
1089 break;
1090
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109 break;
1110
1114 goto process_chain;
1115
1116 default:
1117 elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result");
1118 goto process_chain;
1119 }
1120
1121
1122
1123
1124
1126 goto process_chain;
1127
1128
1130
1131
1132
1133
1137 }
1138
1140 {
1141
1142
1143
1144
1145
1146
1147
1148
1150 return;
1151 }
1152
1153process_chain:
1154
1155 if (ndeadchain == 0)
1156 {
1157
1158
1159
1160
1161 int i = 0;
1162
1164 {
1166 i++;
1167 }
1170 }
1171 else if (ndeadchain == nchain)
1172 {
1173
1174
1175
1176
1178 for (int i = 1; i < nchain; i++)
1180 }
1181 else
1182 {
1183
1184
1185
1186
1187
1190 for (int i = 1; i < ndeadchain; i++)
1192
1193
1194 for (int i = ndeadchain; i < nchain; i++)
1196 }
1197}
1198
1199
1200static void
1202{
1203
1204
1205
1206
1211}
1212
1213
1214static void
1217 bool was_normal)
1218{
1220 prstate->processed[offnum] = true;
1221
1222
1223
1224
1225
1226
1230
1232
1233
1234
1235
1236
1237
1238 if (was_normal)
1240
1241 prstate->hastup = true;
1242}
1243
1244
1245static void
1247 bool was_normal)
1248{
1250 prstate->processed[offnum] = true;
1251
1254 prstate->ndead++;
1255
1256
1257
1258
1259
1260
1261
1263
1264
1265
1266
1267
1268
1269 if (was_normal)
1271}
1272
1273
1274
1275
1276
1277
1278
1279static void
1281 bool was_normal)
1282{
1283
1284
1285
1286
1287
1288
1291 else
1293}
1294
1295
1296static void
1298{
1300 prstate->processed[offnum] = true;
1301
1305
1306
1307
1308
1309
1310
1311 if (was_normal)
1313}
1314
1315
1316
1317
1318static void
1320{
1322 prstate->processed[offnum] = true;
1323}
1324
1325
1326
1327
1328
1329static void
1331{
1333
1335 prstate->processed[offnum] = true;
1336
1337 prstate->hastup = true;
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1360
1361 switch (prstate->htsv[offnum])
1362 {
1364
1365
1366
1367
1368
1370
1371
1372
1373
1374
1375
1376
1377
1378
1380 {
1382
1384 {
1386 break;
1387 }
1388
1389
1390
1391
1392
1393
1394
1395
1397
1398
1399
1400
1401
1402
1403
1406 {
1408 break;
1409 }
1410
1411
1415 }
1416 break;
1417
1421
1422
1423
1424
1425
1428 break;
1429
1431
1432
1433
1434
1435
1436
1437
1438
1440
1441
1442
1443
1444
1445
1446
1447 break;
1448
1450
1451
1452
1453
1454
1455
1458
1459
1460
1461
1462
1465 break;
1466
1467 default:
1468
1469
1470
1471
1472
1473 elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result %d",
1474 prstate->htsv[offnum]);
1475 break;
1476 }
1477
1478
1479 if (prstate->freeze)
1480 {
1481 bool totally_frozen;
1482
1487 &totally_frozen)))
1488 {
1489
1491 }
1492
1493
1494
1495
1496
1497
1498 if (!totally_frozen)
1500 }
1501}
1502
1503
1504
1505
1506
1507static void
1509{
1511 prstate->processed[offnum] = true;
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1530}
1531
1532
1533
1534
1535static void
1537{
1538
1539
1540
1541
1542
1543
1544
1545
1547 prstate->processed[offnum] = true;
1548}
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560void
1565{
1569
1570
1571 Assert(nredirected > 0 || ndead > 0 || nunused > 0);
1572
1573
1574 Assert(!lp_truncate_only || (nredirected == 0 && ndead == 0));
1575
1576
1577 offnum = redirected;
1578 for (int i = 0; i < nredirected; i++)
1579 {
1584
1585#ifdef USE_ASSERT_CHECKING
1586
1587
1588
1589
1590
1591
1592
1593
1595 {
1597
1600 }
1601 else
1602 {
1603
1605 }
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1628#endif
1629
1631 }
1632
1633
1634 offnum = nowdead;
1635 for (int i = 0; i < ndead; i++)
1636 {
1639
1640#ifdef USE_ASSERT_CHECKING
1641
1642
1643
1644
1645
1646
1647
1648
1650 {
1654 }
1655 else
1656 {
1657
1659 }
1660#endif
1661
1663 }
1664
1665
1666 offnum = nowunused;
1667 for (int i = 0; i < nunused; i++)
1668 {
1671
1672#ifdef USE_ASSERT_CHECKING
1673
1674 if (lp_truncate_only)
1675 {
1676
1678 }
1679 else
1680 {
1681
1682
1683
1684
1685
1686
1687
1688
1689 if (ndead > 0)
1690 {
1694 }
1695 else
1697 }
1698
1699#endif
1700
1702 }
1703
1704 if (lp_truncate_only)
1706 else
1707 {
1708
1709
1710
1711
1713
1714
1715
1716
1717
1719 }
1720}
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736static void
1738{
1739#ifdef USE_ASSERT_CHECKING
1742
1745 offnum <= maxoff;
1747 {
1752
1754 continue;
1755
1758
1764 }
1765#endif
1766}
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784void
1786{
1788 maxoff;
1789
1792
1795 {
1800
1801
1803 continue;
1804
1806 {
1808
1809
1810
1811
1812
1813
1815 continue;
1816
1817
1818
1819
1820
1821 root_offsets[offnum - 1] = offnum;
1822
1823
1825 continue;
1826
1827
1830 }
1831 else
1832 {
1833
1835
1838 }
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848 for (;;)
1849 {
1850
1852 break;
1853
1854
1855
1856
1857
1858 if (offnum > maxoff)
1859 break;
1860
1862
1863
1865 break;
1866
1868
1871 break;
1872
1873
1874 root_offsets[nextoffnum - 1] = offnum;
1875
1876
1878 break;
1879
1880
1882
1885 }
1886 }
1887}
1888
1889
1890
1891
1892
1893
1894
1895static inline bool
1897{
1898 if (plan->xmax == frz->xmax &&
1902 return true;
1903
1904
1905 return false;
1906}
1907
1908
1909
1910
1911static int
1913{
1916
1917 if (frz1->xmax < frz2->xmax)
1918 return -1;
1919 else if (frz1->xmax > frz2->xmax)
1920 return 1;
1921
1923 return -1;
1925 return 1;
1926
1928 return -1;
1930 return 1;
1931
1933 return -1;
1935 return 1;
1936
1937
1938
1939
1940
1941
1942
1943
1945 return -1;
1947 return 1;
1948
1950 return 0;
1951}
1952
1953
1954
1955
1956
1957static inline void
1959{
1964 plan->ntuples = 1;
1965}
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977static int
1981{
1982 int nplans = 0;
1983
1984
1986
1987 for (int i = 0; i < ntuples; i++)
1988 {
1990
1991 if (i == 0)
1992 {
1993
1995 nplans++;
1996 }
1998 {
1999
2002 }
2003 else
2004 {
2005
2006 plans_out++;
2007
2008
2010 nplans++;
2011 }
2012
2013
2014
2015
2016
2017
2018
2019
2020 offsets_out[i] = frz->offset;
2021 }
2022
2023 Assert(nplans > 0 && nplans <= ntuples);
2024
2025 return nplans;
2026}
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052void
2055 bool cleanup_lock,
2061{
2065
2066
2073
2074 xlrec.flags = 0;
2075
2076
2077
2078
2079
2080
2083 if (nfrozen > 0)
2084 {
2085 int nplans;
2086
2088
2089
2090
2091
2092
2094
2095 freeze_plans.nplans = nplans;
2100 }
2101 if (nredirected > 0)
2102 {
2104
2105 redirect_items.ntargets = nredirected;
2110 }
2111 if (ndead > 0)
2112 {
2114
2115 dead_items.ntargets = ndead;
2120 }
2121 if (nunused > 0)
2122 {
2124
2125 unused_items.ntargets = nunused;
2130 }
2131 if (nfrozen > 0)
2134
2135
2136
2137
2138
2143 if (cleanup_lock)
2145 else
2146 {
2147 Assert(nredirected == 0 && ndead == 0);
2148
2149 }
2153
2154 switch (reason)
2155 {
2158 break;
2161 break;
2164 break;
2165 default:
2166 elog(ERROR, "unrecognized prune reason: %d", (int) reason);
2167 break;
2168 }
2169 recptr = XLogInsert(RM_HEAP2_ID, info);
2170
2172}
BlockNumber BufferGetBlockNumber(Buffer buffer)
void MarkBufferDirty(Buffer buffer)
void LockBuffer(Buffer buffer, int mode)
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
bool ConditionalLockBufferForCleanup(Buffer buffer)
#define BUFFER_LOCK_UNLOCK
static Page BufferGetPage(Buffer buffer)
Size PageGetHeapFreeSpace(const PageData *page)
void PageRepairFragmentation(Page page)
void PageTruncateLinePointerArray(Page page)
PageHeaderData * PageHeader
static void PageClearFull(Page page)
static Item PageGetItem(const PageData *page, const ItemIdData *itemId)
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
static void PageSetLSN(Page page, XLogRecPtr lsn)
static bool PageIsFull(const PageData *page)
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
#define PG_USED_FOR_ASSERTS_ONLY
TransactionId MultiXactId
#define MemSet(start, val, len)
Assert(PointerIsAligned(start, uint64))
void HeapTupleHeaderAdvanceConflictHorizon(HeapTupleHeader tuple, TransactionId *snapshotConflictHorizon)
void heap_freeze_prepared_tuples(Buffer buffer, HeapTupleFreeze *tuples, int ntuples)
bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, const struct VacuumCutoffs *cutoffs, HeapPageFreeze *pagefrz, HeapTupleFreeze *frz, bool *totally_frozen)
void heap_pre_freeze_checks(Buffer buffer, HeapTupleFreeze *tuples, int ntuples)
#define HEAP_PAGE_PRUNE_FREEZE
@ HEAPTUPLE_RECENTLY_DEAD
@ HEAPTUPLE_INSERT_IN_PROGRESS
@ HEAPTUPLE_DELETE_IN_PROGRESS
#define HEAP_PAGE_PRUNE_MARK_UNUSED_NOW
HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
#define XLHP_HAS_CONFLICT_HORIZON
#define XLHP_HAS_FREEZE_PLANS
#define XLHP_HAS_NOW_UNUSED_ITEMS
#define XLHP_HAS_REDIRECTIONS
#define XLOG_HEAP2_PRUNE_VACUUM_SCAN
#define XLOG_HEAP2_PRUNE_ON_ACCESS
#define XLHP_CLEANUP_LOCK
#define XLHP_HAS_DEAD_ITEMS
#define XLOG_HEAP2_PRUNE_VACUUM_CLEANUP
#define XLHP_IS_CATALOG_REL
HeapTupleHeaderData * HeapTupleHeader
static bool HeapTupleHeaderIsHeapOnly(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
static bool HeapTupleHeaderIndicatesMovedPartitions(const HeapTupleHeaderData *tup)
static bool HeapTupleHeaderIsHotUpdated(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)
#define MaxHeapTuplesPerPage
static bool HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
#define ItemIdGetLength(itemId)
#define ItemIdSetRedirect(itemId, link)
#define ItemIdIsNormal(itemId)
#define ItemIdGetRedirect(itemId)
#define ItemIdIsDead(itemId)
#define ItemIdSetDead(itemId)
#define ItemIdIsUsed(itemId)
#define ItemIdSetUnused(itemId)
#define ItemIdIsRedirected(itemId)
#define ItemIdHasStorage(itemId)
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
#define START_CRIT_SECTION()
#define END_CRIT_SECTION()
#define InvalidMultiXactId
#define InvalidOffsetNumber
#define OffsetNumberNext(offsetNumber)
#define FirstOffsetNumber
#define OffsetNumberPrev(offsetNumber)
void pgstat_update_heap_dead_tuples(Relation rel, int delta)
#define qsort(a, b, c, d)
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
GlobalVisState * GlobalVisTestFor(Relation rel)
static void heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff, OffsetNumber rootoffnum, PruneState *prstate)
static void heap_prune_record_unchanged_lp_dead(Page page, PruneState *prstate, OffsetNumber offnum)
void heap_get_root_tuples(Page page, OffsetNumber *root_offsets)
void heap_page_prune_opt(Relation relation, Buffer buffer)
void heap_page_prune_and_freeze(Relation relation, Buffer buffer, GlobalVisState *vistest, int options, struct VacuumCutoffs *cutoffs, PruneFreezeResult *presult, PruneReason reason, OffsetNumber *off_loc, TransactionId *new_relfrozen_xid, MultiXactId *new_relmin_mxid)
static HTSV_Result htsv_get_valid_status(int status)
static int heap_log_freeze_plan(HeapTupleFreeze *tuples, int ntuples, xlhp_freeze_plan *plans_out, OffsetNumber *offsets_out)
static void page_verify_redirects(Page page)
static void heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal)
static void heap_prune_record_redirect(PruneState *prstate, OffsetNumber offnum, OffsetNumber rdoffnum, bool was_normal)
static void heap_prune_record_unchanged_lp_normal(Page page, PruneState *prstate, OffsetNumber offnum)
static int heap_log_freeze_cmp(const void *arg1, const void *arg2)
void log_heap_prune_and_freeze(Relation relation, Buffer buffer, TransactionId conflict_xid, bool cleanup_lock, PruneReason reason, HeapTupleFreeze *frozen, int nfrozen, OffsetNumber *redirected, int nredirected, OffsetNumber *dead, int ndead, OffsetNumber *unused, int nunused)
static void heap_prune_record_dead(PruneState *prstate, OffsetNumber offnum, bool was_normal)
static bool heap_log_freeze_eq(xlhp_freeze_plan *plan, HeapTupleFreeze *frz)
static void heap_prune_record_prunable(PruneState *prstate, TransactionId xid)
static void heap_prune_record_unchanged_lp_unused(Page page, PruneState *prstate, OffsetNumber offnum)
static void heap_log_freeze_new_plan(xlhp_freeze_plan *plan, HeapTupleFreeze *frz)
static HTSV_Result heap_prune_satisfies_vacuum(PruneState *prstate, HeapTuple tup, Buffer buffer)
static void heap_prune_record_dead_or_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal)
void heap_page_prune_execute(Buffer buffer, bool lp_truncate_only, OffsetNumber *redirected, int nredirected, OffsetNumber *nowdead, int ndead, OffsetNumber *nowunused, int nunused)
static void heap_prune_record_unchanged_lp_redirect(PruneState *prstate, OffsetNumber offnum)
#define RelationGetRelid(relation)
#define RelationGetTargetPageFreeSpace(relation, defaultff)
#define RelationIsAccessibleInLogicalDecoding(relation)
#define RelationNeedsWAL(relation)
#define HEAP_DEFAULT_FILLFACTOR
MultiXactId NoFreezePageRelminMxid
TransactionId FreezePageRelfrozenXid
MultiXactId FreezePageRelminMxid
TransactionId NoFreezePageRelfrozenXid
TransactionId vm_conflict_horizon
OffsetNumber deadoffsets[MaxHeapTuplesPerPage]
bool processed[MaxHeapTuplesPerPage+1]
OffsetNumber heaponly_items[MaxHeapTuplesPerPage]
TransactionId new_prune_xid
OffsetNumber nowdead[MaxHeapTuplesPerPage]
OffsetNumber nowunused[MaxHeapTuplesPerPage]
TransactionId visibility_cutoff_xid
struct VacuumCutoffs * cutoffs
HeapTupleFreeze frozen[MaxHeapTuplesPerPage]
OffsetNumber redirected[MaxHeapTuplesPerPage *2]
int8 htsv[MaxHeapTuplesPerPage+1]
TransactionId latest_xid_removed
OffsetNumber root_items[MaxHeapTuplesPerPage]
OffsetNumber * deadoffsets
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
#define TransactionIdRetreat(dest)
#define InvalidTransactionId
#define TransactionIdEquals(id1, id2)
#define NormalTransactionIdPrecedes(id1, id2)
#define TransactionIdIsValid(xid)
#define TransactionIdIsNormal(xid)
bool RecoveryInProgress(void)
#define XLogHintBitIsNeeded()
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
bool XLogCheckBufferNeedsBackup(Buffer buffer)
void XLogRegisterData(const void *data, uint32 len)
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
void XLogBeginInsert(void)