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

115 int ndeleted;

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 }

1168 for (; i < nchain; i++)

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)