Coverage Report

Created: 2026-08-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/access/nbtree/nbtpage.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * nbtpage.c
4
 *    BTree-specific page management code for the Postgres btree access
5
 *    method.
6
 *
7
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8
 * Portions Copyright (c) 1994, Regents of the University of California
9
 *
10
 *
11
 * IDENTIFICATION
12
 *    src/backend/access/nbtree/nbtpage.c
13
 *
14
 *  NOTES
15
 *     Postgres btree pages look like ordinary relation pages.  The opaque
16
 *     data at high addresses includes pointers to left and right siblings
17
 *     and flag data describing page state.  The first page in a btree, page
18
 *     zero, is special -- it stores meta-information describing the tree.
19
 *     Pages one and higher store the actual tree data.
20
 *
21
 *-------------------------------------------------------------------------
22
 */
23
#include "postgres.h"
24
25
#include "access/nbtree.h"
26
#include "access/nbtxlog.h"
27
#include "access/tableam.h"
28
#include "access/transam.h"
29
#include "access/xlog.h"
30
#include "access/xloginsert.h"
31
#include "common/int.h"
32
#include "miscadmin.h"
33
#include "storage/indexfsm.h"
34
#include "storage/predicate.h"
35
#include "storage/procarray.h"
36
#include "utils/injection_point.h"
37
#include "utils/memdebug.h"
38
#include "utils/memutils.h"
39
#include "utils/snapmgr.h"
40
41
static BTMetaPageData *_bt_getmeta(Relation rel, Buffer metabuf);
42
static void _bt_delitems_delete(Relation rel, Buffer buf,
43
                TransactionId snapshotConflictHorizon,
44
                bool isCatalogRel,
45
                OffsetNumber *deletable, int ndeletable,
46
                BTVacuumPosting *updatable, int nupdatable);
47
static char *_bt_delitems_update(BTVacuumPosting *updatable, int nupdatable,
48
                 OffsetNumber *updatedoffsets,
49
                 Size *updatedbuflen, bool needswal);
50
static bool _bt_mark_page_halfdead(Relation rel, Relation heaprel,
51
                   Buffer leafbuf, BTStack stack);
52
static bool _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf,
53
                   BlockNumber scanblkno,
54
                   bool *rightsib_empty,
55
                   BTVacState *vstate);
56
static bool _bt_lock_subtree_parent(Relation rel, Relation heaprel,
57
                  BlockNumber child, BTStack stack,
58
                  Buffer *subtreeparent, OffsetNumber *poffset,
59
                  BlockNumber *topparent,
60
                  BlockNumber *topparentrightsib);
61
static void _bt_pendingfsm_add(BTVacState *vstate, BlockNumber target,
62
                 FullTransactionId safexid);
63
64
/*
65
 *  _bt_initmetapage() -- Fill a page buffer with a correct metapage image
66
 */
67
void
68
_bt_initmetapage(Page page, BlockNumber rootbknum, uint32 level,
69
         bool allequalimage)
70
0
{
71
0
  BTMetaPageData *metad;
72
0
  BTPageOpaque metaopaque;
73
74
0
  _bt_pageinit(page, BLCKSZ);
75
76
0
  metad = BTPageGetMeta(page);
77
0
  metad->btm_magic = BTREE_MAGIC;
78
0
  metad->btm_version = BTREE_VERSION;
79
0
  metad->btm_root = rootbknum;
80
0
  metad->btm_level = level;
81
0
  metad->btm_fastroot = rootbknum;
82
0
  metad->btm_fastlevel = level;
83
0
  metad->btm_last_cleanup_num_delpages = 0;
84
0
  metad->btm_last_cleanup_num_heap_tuples = -1.0;
85
0
  metad->btm_allequalimage = allequalimage;
86
87
0
  metaopaque = BTPageGetOpaque(page);
88
0
  metaopaque->btpo_flags = BTP_META;
89
90
  /*
91
   * Set pd_lower just past the end of the metadata.  This is essential,
92
   * because without doing so, metadata will be lost if xlog.c compresses
93
   * the page.
94
   */
95
0
  ((PageHeader) page)->pd_lower =
96
0
    ((char *) metad + sizeof(BTMetaPageData)) - (char *) page;
97
0
}
98
99
/*
100
 *  _bt_upgrademetapage() -- Upgrade a meta-page from an old format to version
101
 *    3, the last version that can be updated without broadly affecting
102
 *    on-disk compatibility.  (A REINDEX is required to upgrade to v4.)
103
 *
104
 *    This routine does purely in-memory image upgrade.  Caller is
105
 *    responsible for locking, WAL-logging etc.
106
 */
107
void
108
_bt_upgrademetapage(Page page)
109
0
{
110
0
  BTMetaPageData *metad;
111
0
  BTPageOpaque metaopaque PG_USED_FOR_ASSERTS_ONLY;
112
113
0
  metad = BTPageGetMeta(page);
114
0
  metaopaque = BTPageGetOpaque(page);
115
116
  /* It must be really a meta page of upgradable version */
117
0
  Assert(metaopaque->btpo_flags & BTP_META);
118
0
  Assert(metad->btm_version < BTREE_NOVAC_VERSION);
119
0
  Assert(metad->btm_version >= BTREE_MIN_VERSION);
120
121
  /* Set version number and fill extra fields added into version 3 */
122
0
  metad->btm_version = BTREE_NOVAC_VERSION;
123
0
  metad->btm_last_cleanup_num_delpages = 0;
124
0
  metad->btm_last_cleanup_num_heap_tuples = -1.0;
125
  /* Only a REINDEX can set this field */
126
0
  Assert(!metad->btm_allequalimage);
127
0
  metad->btm_allequalimage = false;
128
129
  /* Adjust pd_lower (see _bt_initmetapage() for details) */
130
0
  ((PageHeader) page)->pd_lower =
131
0
    ((char *) metad + sizeof(BTMetaPageData)) - (char *) page;
132
0
}
133
134
/*
135
 * Get metadata from share-locked buffer containing metapage, while performing
136
 * standard sanity checks.
137
 *
138
 * Callers that cache data returned here in local cache should note that an
139
 * on-the-fly upgrade using _bt_upgrademetapage() can change the version field
140
 * and BTREE_NOVAC_VERSION specific fields without invalidating local cache.
141
 */
142
static BTMetaPageData *
143
_bt_getmeta(Relation rel, Buffer metabuf)
144
0
{
145
0
  Page    metapg;
146
0
  BTPageOpaque metaopaque;
147
0
  BTMetaPageData *metad;
148
149
0
  metapg = BufferGetPage(metabuf);
150
0
  metaopaque = BTPageGetOpaque(metapg);
151
0
  metad = BTPageGetMeta(metapg);
152
153
  /* sanity-check the metapage */
154
0
  if (!P_ISMETA(metaopaque) ||
155
0
    metad->btm_magic != BTREE_MAGIC)
156
0
    ereport(ERROR,
157
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
158
0
         errmsg("index \"%s\" is not a btree",
159
0
            RelationGetRelationName(rel))));
160
161
0
  if (metad->btm_version < BTREE_MIN_VERSION ||
162
0
    metad->btm_version > BTREE_VERSION)
163
0
    ereport(ERROR,
164
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
165
0
         errmsg("version mismatch in index \"%s\": file version %d, "
166
0
            "current version %d, minimal supported version %d",
167
0
            RelationGetRelationName(rel),
168
0
            metad->btm_version, BTREE_VERSION, BTREE_MIN_VERSION)));
169
170
0
  return metad;
171
0
}
172
173
/*
174
 * _bt_vacuum_needs_cleanup() -- Checks if index needs cleanup
175
 *
176
 * Called by btvacuumcleanup when btbulkdelete was never called because no
177
 * index tuples needed to be deleted.
178
 */
179
bool
180
_bt_vacuum_needs_cleanup(Relation rel)
181
0
{
182
0
  Buffer    metabuf;
183
0
  Page    metapg;
184
0
  BTMetaPageData *metad;
185
0
  uint32    btm_version;
186
0
  BlockNumber prev_num_delpages;
187
188
  /*
189
   * Copy details from metapage to local variables quickly.
190
   *
191
   * Note that we deliberately avoid using cached version of metapage here.
192
   */
193
0
  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
194
0
  metapg = BufferGetPage(metabuf);
195
0
  metad = BTPageGetMeta(metapg);
196
0
  btm_version = metad->btm_version;
197
198
0
  if (btm_version < BTREE_NOVAC_VERSION)
199
0
  {
200
    /*
201
     * Metapage needs to be dynamically upgraded to store fields that are
202
     * only present when btm_version >= BTREE_NOVAC_VERSION
203
     */
204
0
    _bt_relbuf(rel, metabuf);
205
0
    return true;
206
0
  }
207
208
0
  prev_num_delpages = metad->btm_last_cleanup_num_delpages;
209
0
  _bt_relbuf(rel, metabuf);
210
211
  /*
212
   * Trigger cleanup in rare cases where prev_num_delpages exceeds 5% of the
213
   * total size of the index.  We can reasonably expect (though are not
214
   * guaranteed) to be able to recycle this many pages if we decide to do a
215
   * btvacuumscan call during the ongoing btvacuumcleanup.  For further
216
   * details see the nbtree/README section on placing deleted pages in the
217
   * FSM.
218
   */
219
0
  if (prev_num_delpages > 0 &&
220
0
    prev_num_delpages > RelationGetNumberOfBlocks(rel) / 20)
221
0
    return true;
222
223
0
  return false;
224
0
}
225
226
/*
227
 * _bt_set_cleanup_info() -- Update metapage for btvacuumcleanup.
228
 *
229
 * Called at the end of btvacuumcleanup, when num_delpages value has been
230
 * finalized.
231
 */
232
void
233
_bt_set_cleanup_info(Relation rel, BlockNumber num_delpages)
234
0
{
235
0
  Buffer    metabuf;
236
0
  Page    metapg;
237
0
  BTMetaPageData *metad;
238
0
  XLogRecPtr  recptr;
239
240
  /*
241
   * On-disk compatibility note: The btm_last_cleanup_num_delpages metapage
242
   * field started out as a TransactionId field called btm_oldest_btpo_xact.
243
   * Both "versions" are just uint32 fields.  It was convenient to repurpose
244
   * the field when we began to use 64-bit XIDs in deleted pages.
245
   *
246
   * It's possible that a pg_upgrade'd database will contain an XID value in
247
   * what is now recognized as the metapage's btm_last_cleanup_num_delpages
248
   * field.  _bt_vacuum_needs_cleanup() may even believe that this value
249
   * indicates that there are lots of pages that it needs to recycle, when
250
   * in reality there are only one or two.  The worst that can happen is
251
   * that there will be a call to btvacuumscan a little earlier, which will
252
   * set btm_last_cleanup_num_delpages to a sane value when we're called.
253
   *
254
   * Note also that the metapage's btm_last_cleanup_num_heap_tuples field is
255
   * no longer used as of PostgreSQL 14.  We set it to -1.0 on rewrite, just
256
   * to be consistent.
257
   */
258
0
  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
259
0
  metapg = BufferGetPage(metabuf);
260
0
  metad = BTPageGetMeta(metapg);
261
262
  /* Don't miss chance to upgrade index/metapage when BTREE_MIN_VERSION */
263
0
  if (metad->btm_version >= BTREE_NOVAC_VERSION &&
264
0
    metad->btm_last_cleanup_num_delpages == num_delpages)
265
0
  {
266
    /* Usually means index continues to have num_delpages of 0 */
267
0
    _bt_relbuf(rel, metabuf);
268
0
    return;
269
0
  }
270
271
  /* trade in our read lock for a write lock */
272
0
  _bt_unlockbuf(rel, metabuf);
273
0
  _bt_lockbuf(rel, metabuf, BT_WRITE);
274
275
0
  START_CRIT_SECTION();
276
277
  /* upgrade meta-page if needed */
278
0
  if (metad->btm_version < BTREE_NOVAC_VERSION)
279
0
    _bt_upgrademetapage(metapg);
280
281
  /* update cleanup-related information */
282
0
  metad->btm_last_cleanup_num_delpages = num_delpages;
283
0
  metad->btm_last_cleanup_num_heap_tuples = -1.0;
284
0
  MarkBufferDirty(metabuf);
285
286
  /* write wal record if needed */
287
0
  if (RelationNeedsWAL(rel))
288
0
  {
289
0
    xl_btree_metadata md;
290
291
0
    XLogBeginInsert();
292
0
    XLogRegisterBuffer(0, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
293
294
0
    Assert(metad->btm_version >= BTREE_NOVAC_VERSION);
295
0
    md.version = metad->btm_version;
296
0
    md.root = metad->btm_root;
297
0
    md.level = metad->btm_level;
298
0
    md.fastroot = metad->btm_fastroot;
299
0
    md.fastlevel = metad->btm_fastlevel;
300
0
    md.last_cleanup_num_delpages = num_delpages;
301
0
    md.allequalimage = metad->btm_allequalimage;
302
303
0
    XLogRegisterBufData(0, &md, sizeof(xl_btree_metadata));
304
305
0
    recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_META_CLEANUP);
306
0
  }
307
0
  else
308
0
    recptr = XLogGetFakeLSN(rel);
309
310
0
  PageSetLSN(metapg, recptr);
311
312
0
  END_CRIT_SECTION();
313
314
0
  _bt_relbuf(rel, metabuf);
315
0
}
316
317
/*
318
 *  _bt_getroot() -- Get the root page of the btree.
319
 *
320
 *    Since the root page can move around the btree file, we have to read
321
 *    its location from the metadata page, and then read the root page
322
 *    itself.  If no root page exists yet, we have to create one.
323
 *
324
 *    The access type parameter (BT_READ or BT_WRITE) controls whether
325
 *    a new root page will be created or not.  If access = BT_READ,
326
 *    and no root page exists, we just return InvalidBuffer.  For
327
 *    BT_WRITE, we try to create the root page if it doesn't exist.
328
 *    NOTE that the returned root page will have only a read lock set
329
 *    on it even if access = BT_WRITE!
330
 *
331
 *    If access = BT_WRITE, heaprel must be set; otherwise caller can just
332
 *    pass NULL.  See _bt_allocbuf for an explanation.
333
 *
334
 *    The returned page is not necessarily the true root --- it could be
335
 *    a "fast root" (a page that is alone in its level due to deletions).
336
 *    Also, if the root page is split while we are "in flight" to it,
337
 *    what we will return is the old root, which is now just the leftmost
338
 *    page on a probably-not-very-wide level.  For most purposes this is
339
 *    as good as or better than the true root, so we do not bother to
340
 *    insist on finding the true root.  We do, however, guarantee to
341
 *    return a live (not deleted or half-dead) page.
342
 *
343
 *    On successful return, the root page is pinned and read-locked.
344
 *    The metadata page is not locked or pinned on exit.
345
 */
346
Buffer
347
_bt_getroot(Relation rel, Relation heaprel, int access)
348
0
{
349
0
  Buffer    metabuf;
350
0
  Buffer    rootbuf;
351
0
  Page    rootpage;
352
0
  BTPageOpaque rootopaque;
353
0
  BlockNumber rootblkno;
354
0
  uint32    rootlevel;
355
0
  BTMetaPageData *metad;
356
0
  XLogRecPtr  recptr;
357
358
0
  Assert(access == BT_READ || heaprel != NULL);
359
360
  /*
361
   * Try to use previously-cached metapage data to find the root.  This
362
   * normally saves one buffer access per index search, which is a very
363
   * helpful savings in bufmgr traffic and hence contention.
364
   */
365
0
  if (rel->rd_amcache != NULL)
366
0
  {
367
0
    metad = (BTMetaPageData *) rel->rd_amcache;
368
    /* We shouldn't have cached it if any of these fail */
369
0
    Assert(metad->btm_magic == BTREE_MAGIC);
370
0
    Assert(metad->btm_version >= BTREE_MIN_VERSION);
371
0
    Assert(metad->btm_version <= BTREE_VERSION);
372
0
    Assert(!metad->btm_allequalimage ||
373
0
         metad->btm_version > BTREE_NOVAC_VERSION);
374
0
    Assert(metad->btm_root != P_NONE);
375
376
0
    rootblkno = metad->btm_fastroot;
377
0
    Assert(rootblkno != P_NONE);
378
0
    rootlevel = metad->btm_fastlevel;
379
380
0
    rootbuf = _bt_getbuf(rel, rootblkno, BT_READ);
381
0
    rootpage = BufferGetPage(rootbuf);
382
0
    rootopaque = BTPageGetOpaque(rootpage);
383
384
    /*
385
     * Since the cache might be stale, we check the page more carefully
386
     * here than normal.  We *must* check that it's not deleted. If it's
387
     * not alone on its level, then we reject too --- this may be overly
388
     * paranoid but better safe than sorry.  Note we don't check P_ISROOT,
389
     * because that's not set in a "fast root".
390
     */
391
0
    if (!P_IGNORE(rootopaque) &&
392
0
      rootopaque->btpo_level == rootlevel &&
393
0
      P_LEFTMOST(rootopaque) &&
394
0
      P_RIGHTMOST(rootopaque))
395
0
    {
396
      /* OK, accept cached page as the root */
397
0
      return rootbuf;
398
0
    }
399
0
    _bt_relbuf(rel, rootbuf);
400
    /* Cache is stale, throw it away */
401
0
    if (rel->rd_amcache)
402
0
      pfree(rel->rd_amcache);
403
0
    rel->rd_amcache = NULL;
404
0
  }
405
406
0
  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
407
0
  metad = _bt_getmeta(rel, metabuf);
408
409
  /* if no root page initialized yet, do it */
410
0
  if (metad->btm_root == P_NONE)
411
0
  {
412
0
    Page    metapg;
413
414
    /* If access = BT_READ, caller doesn't want us to create root yet */
415
0
    if (access == BT_READ)
416
0
    {
417
0
      _bt_relbuf(rel, metabuf);
418
0
      return InvalidBuffer;
419
0
    }
420
421
    /* trade in our read lock for a write lock */
422
0
    _bt_unlockbuf(rel, metabuf);
423
0
    _bt_lockbuf(rel, metabuf, BT_WRITE);
424
425
    /*
426
     * Race condition:  if someone else initialized the metadata between
427
     * the time we released the read lock and acquired the write lock, we
428
     * must avoid doing it again.
429
     */
430
0
    if (metad->btm_root != P_NONE)
431
0
    {
432
      /*
433
       * Metadata initialized by someone else.  In order to guarantee no
434
       * deadlocks, we have to release the metadata page and start all
435
       * over again.  (Is that really true? But it's hardly worth trying
436
       * to optimize this case.)
437
       */
438
0
      _bt_relbuf(rel, metabuf);
439
0
      return _bt_getroot(rel, heaprel, access);
440
0
    }
441
442
    /*
443
     * Get, initialize, write, and leave a lock of the appropriate type on
444
     * the new root page.  Since this is the first page in the tree, it's
445
     * a leaf as well as the root.
446
     */
447
0
    rootbuf = _bt_allocbuf(rel, heaprel);
448
0
    rootblkno = BufferGetBlockNumber(rootbuf);
449
0
    rootpage = BufferGetPage(rootbuf);
450
0
    rootopaque = BTPageGetOpaque(rootpage);
451
0
    rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;
452
0
    rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT);
453
0
    rootopaque->btpo_level = 0;
454
0
    rootopaque->btpo_cycleid = 0;
455
    /* Get raw page pointer for metapage */
456
0
    metapg = BufferGetPage(metabuf);
457
458
    /* NO ELOG(ERROR) till meta is updated */
459
0
    START_CRIT_SECTION();
460
461
    /* upgrade metapage if needed */
462
0
    if (metad->btm_version < BTREE_NOVAC_VERSION)
463
0
      _bt_upgrademetapage(metapg);
464
465
0
    metad->btm_root = rootblkno;
466
0
    metad->btm_level = 0;
467
0
    metad->btm_fastroot = rootblkno;
468
0
    metad->btm_fastlevel = 0;
469
0
    metad->btm_last_cleanup_num_delpages = 0;
470
0
    metad->btm_last_cleanup_num_heap_tuples = -1.0;
471
472
0
    MarkBufferDirty(rootbuf);
473
0
    MarkBufferDirty(metabuf);
474
475
    /* XLOG stuff */
476
0
    if (RelationNeedsWAL(rel))
477
0
    {
478
0
      xl_btree_newroot xlrec;
479
0
      xl_btree_metadata md;
480
481
0
      XLogBeginInsert();
482
0
      XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT);
483
0
      XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
484
485
0
      Assert(metad->btm_version >= BTREE_NOVAC_VERSION);
486
0
      md.version = metad->btm_version;
487
0
      md.root = rootblkno;
488
0
      md.level = 0;
489
0
      md.fastroot = rootblkno;
490
0
      md.fastlevel = 0;
491
0
      md.last_cleanup_num_delpages = 0;
492
0
      md.allequalimage = metad->btm_allequalimage;
493
494
0
      XLogRegisterBufData(2, &md, sizeof(xl_btree_metadata));
495
496
0
      xlrec.rootblk = rootblkno;
497
0
      xlrec.level = 0;
498
499
0
      XLogRegisterData(&xlrec, SizeOfBtreeNewroot);
500
501
0
      recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT);
502
0
    }
503
0
    else
504
0
      recptr = XLogGetFakeLSN(rel);
505
506
0
    PageSetLSN(rootpage, recptr);
507
0
    PageSetLSN(metapg, recptr);
508
509
0
    END_CRIT_SECTION();
510
511
    /*
512
     * swap root write lock for read lock.  There is no danger of anyone
513
     * else accessing the new root page while it's unlocked, since no one
514
     * else knows where it is yet.
515
     */
516
0
    _bt_unlockbuf(rel, rootbuf);
517
0
    _bt_lockbuf(rel, rootbuf, BT_READ);
518
519
    /* okay, metadata is correct, release lock on it without caching */
520
0
    _bt_relbuf(rel, metabuf);
521
0
  }
522
0
  else
523
0
  {
524
0
    rootblkno = metad->btm_fastroot;
525
0
    Assert(rootblkno != P_NONE);
526
0
    rootlevel = metad->btm_fastlevel;
527
528
    /*
529
     * Cache the metapage data for next time
530
     */
531
0
    rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt,
532
0
                       sizeof(BTMetaPageData));
533
0
    memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData));
534
535
    /*
536
     * We are done with the metapage; arrange to release it via first
537
     * _bt_relandgetbuf call
538
     */
539
0
    rootbuf = metabuf;
540
541
0
    for (;;)
542
0
    {
543
0
      rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);
544
0
      rootpage = BufferGetPage(rootbuf);
545
0
      rootopaque = BTPageGetOpaque(rootpage);
546
547
0
      if (!P_IGNORE(rootopaque))
548
0
        break;
549
550
      /* it's dead, Jim.  step right one page */
551
0
      if (P_RIGHTMOST(rootopaque))
552
0
        elog(ERROR, "no live root page found in index \"%s\"",
553
0
           RelationGetRelationName(rel));
554
0
      rootblkno = rootopaque->btpo_next;
555
0
    }
556
557
0
    if (rootopaque->btpo_level != rootlevel)
558
0
      elog(ERROR, "root page %u of index \"%s\" has level %u, expected %u",
559
0
         rootblkno, RelationGetRelationName(rel),
560
0
         rootopaque->btpo_level, rootlevel);
561
0
  }
562
563
  /*
564
   * By here, we have a pin and read lock on the root page, and no lock set
565
   * on the metadata page.  Return the root page's buffer.
566
   */
567
0
  return rootbuf;
568
0
}
569
570
/*
571
 *  _bt_gettrueroot() -- Get the true root page of the btree.
572
 *
573
 *    This is the same as the BT_READ case of _bt_getroot(), except
574
 *    we follow the true-root link not the fast-root link.
575
 *
576
 * By the time we acquire lock on the root page, it might have been split and
577
 * not be the true root anymore.  This is okay for the present uses of this
578
 * routine; we only really need to be able to move up at least one tree level
579
 * from whatever non-root page we were at.  If we ever do need to lock the
580
 * one true root page, we could loop here, re-reading the metapage on each
581
 * failure.  (Note that it wouldn't do to hold the lock on the metapage while
582
 * moving to the root --- that'd deadlock against any concurrent root split.)
583
 */
584
Buffer
585
_bt_gettrueroot(Relation rel)
586
0
{
587
0
  Buffer    metabuf;
588
0
  Buffer    rootbuf;
589
0
  Page    rootpage;
590
0
  BTPageOpaque rootopaque;
591
0
  BlockNumber rootblkno;
592
0
  uint32    rootlevel;
593
0
  BTMetaPageData *metad;
594
595
  /*
596
   * We don't try to use cached metapage data here, since (a) this path is
597
   * not performance-critical, and (b) if we are here it suggests our cache
598
   * is out-of-date anyway.  In light of point (b), it's probably safest to
599
   * actively flush any cached metapage info.
600
   */
601
0
  if (rel->rd_amcache)
602
0
    pfree(rel->rd_amcache);
603
0
  rel->rd_amcache = NULL;
604
605
0
  metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
606
0
  metad = _bt_getmeta(rel, metabuf);
607
608
  /* if no root page initialized yet, fail */
609
0
  if (metad->btm_root == P_NONE)
610
0
  {
611
0
    _bt_relbuf(rel, metabuf);
612
0
    return InvalidBuffer;
613
0
  }
614
615
0
  rootblkno = metad->btm_root;
616
0
  rootlevel = metad->btm_level;
617
618
  /*
619
   * We are done with the metapage; arrange to release it via first
620
   * _bt_relandgetbuf call
621
   */
622
0
  rootbuf = metabuf;
623
624
0
  for (;;)
625
0
  {
626
0
    rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);
627
0
    rootpage = BufferGetPage(rootbuf);
628
0
    rootopaque = BTPageGetOpaque(rootpage);
629
630
0
    if (!P_IGNORE(rootopaque))
631
0
      break;
632
633
    /* it's dead, Jim.  step right one page */
634
0
    if (P_RIGHTMOST(rootopaque))
635
0
      elog(ERROR, "no live root page found in index \"%s\"",
636
0
         RelationGetRelationName(rel));
637
0
    rootblkno = rootopaque->btpo_next;
638
0
  }
639
640
0
  if (rootopaque->btpo_level != rootlevel)
641
0
    elog(ERROR, "root page %u of index \"%s\" has level %u, expected %u",
642
0
       rootblkno, RelationGetRelationName(rel),
643
0
       rootopaque->btpo_level, rootlevel);
644
645
0
  return rootbuf;
646
0
}
647
648
/*
649
 *  _bt_getrootheight() -- Get the height of the btree search tree.
650
 *
651
 *    We return the level (counting from zero) of the current fast root.
652
 *    This represents the number of tree levels we'd have to descend through
653
 *    to start any btree index search.
654
 *
655
 *    This is used by the planner for cost-estimation purposes.  Since it's
656
 *    only an estimate, slightly-stale data is fine, hence we don't worry
657
 *    about updating previously cached data.
658
 */
659
int
660
_bt_getrootheight(Relation rel)
661
0
{
662
0
  BTMetaPageData *metad;
663
664
0
  if (rel->rd_amcache == NULL)
665
0
  {
666
0
    Buffer    metabuf;
667
668
0
    metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
669
0
    metad = _bt_getmeta(rel, metabuf);
670
671
    /*
672
     * If there's no root page yet, _bt_getroot() doesn't expect a cache
673
     * to be made, so just stop here and report the index height is zero.
674
     * (XXX perhaps _bt_getroot() should be changed to allow this case.)
675
     */
676
0
    if (metad->btm_root == P_NONE)
677
0
    {
678
0
      _bt_relbuf(rel, metabuf);
679
0
      return 0;
680
0
    }
681
682
    /*
683
     * Cache the metapage data for next time
684
     */
685
0
    rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt,
686
0
                       sizeof(BTMetaPageData));
687
0
    memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData));
688
0
    _bt_relbuf(rel, metabuf);
689
0
  }
690
691
  /* Get cached page */
692
0
  metad = (BTMetaPageData *) rel->rd_amcache;
693
  /* We shouldn't have cached it if any of these fail */
694
0
  Assert(metad->btm_magic == BTREE_MAGIC);
695
0
  Assert(metad->btm_version >= BTREE_MIN_VERSION);
696
0
  Assert(metad->btm_version <= BTREE_VERSION);
697
0
  Assert(!metad->btm_allequalimage ||
698
0
       metad->btm_version > BTREE_NOVAC_VERSION);
699
0
  Assert(metad->btm_fastroot != P_NONE);
700
701
0
  return metad->btm_fastlevel;
702
0
}
703
704
/*
705
 *  _bt_metaversion() -- Get version/status info from metapage.
706
 *
707
 *    Sets caller's *heapkeyspace and *allequalimage arguments using data
708
 *    from the B-Tree metapage (could be locally-cached version).  This
709
 *    information needs to be stashed in insertion scankey, so we provide a
710
 *    single function that fetches both at once.
711
 *
712
 *    This is used to determine the rules that must be used to descend a
713
 *    btree.  Version 4 indexes treat heap TID as a tiebreaker attribute.
714
 *    pg_upgrade'd version 3 indexes need extra steps to preserve reasonable
715
 *    performance when inserting a new BTScanInsert-wise duplicate tuple
716
 *    among many leaf pages already full of such duplicates.
717
 *
718
 *    Also sets allequalimage field, which indicates whether or not it is
719
 *    safe to apply deduplication.  We rely on the assumption that
720
 *    btm_allequalimage will be zero'ed on heapkeyspace indexes that were
721
 *    pg_upgrade'd from Postgres 12.
722
 */
723
void
724
_bt_metaversion(Relation rel, bool *heapkeyspace, bool *allequalimage)
725
0
{
726
0
  BTMetaPageData *metad;
727
728
0
  if (rel->rd_amcache == NULL)
729
0
  {
730
0
    Buffer    metabuf;
731
732
0
    metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);
733
0
    metad = _bt_getmeta(rel, metabuf);
734
735
    /*
736
     * If there's no root page yet, _bt_getroot() doesn't expect a cache
737
     * to be made, so just stop here.  (XXX perhaps _bt_getroot() should
738
     * be changed to allow this case.)
739
     */
740
0
    if (metad->btm_root == P_NONE)
741
0
    {
742
0
      *heapkeyspace = metad->btm_version > BTREE_NOVAC_VERSION;
743
0
      *allequalimage = metad->btm_allequalimage;
744
745
0
      _bt_relbuf(rel, metabuf);
746
0
      return;
747
0
    }
748
749
    /*
750
     * Cache the metapage data for next time
751
     *
752
     * An on-the-fly version upgrade performed by _bt_upgrademetapage()
753
     * can change the nbtree version for an index without invalidating any
754
     * local cache.  This is okay because it can only happen when moving
755
     * from version 2 to version 3, both of which are !heapkeyspace
756
     * versions.
757
     */
758
0
    rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt,
759
0
                       sizeof(BTMetaPageData));
760
0
    memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData));
761
0
    _bt_relbuf(rel, metabuf);
762
0
  }
763
764
  /* Get cached page */
765
0
  metad = (BTMetaPageData *) rel->rd_amcache;
766
  /* We shouldn't have cached it if any of these fail */
767
0
  Assert(metad->btm_magic == BTREE_MAGIC);
768
0
  Assert(metad->btm_version >= BTREE_MIN_VERSION);
769
0
  Assert(metad->btm_version <= BTREE_VERSION);
770
0
  Assert(!metad->btm_allequalimage ||
771
0
       metad->btm_version > BTREE_NOVAC_VERSION);
772
0
  Assert(metad->btm_fastroot != P_NONE);
773
774
0
  *heapkeyspace = metad->btm_version > BTREE_NOVAC_VERSION;
775
0
  *allequalimage = metad->btm_allequalimage;
776
0
}
777
778
/*
779
 *  _bt_checkpage() -- Verify that a freshly-read page looks sane.
780
 */
781
void
782
_bt_checkpage(Relation rel, Buffer buf)
783
0
{
784
0
  Page    page = BufferGetPage(buf);
785
786
  /*
787
   * ReadBuffer verifies that every newly-read page passes
788
   * PageHeaderIsValid, which means it either contains a reasonably sane
789
   * page header or is all-zero.  We have to defend against the all-zero
790
   * case, however.
791
   */
792
0
  if (PageIsNew(page))
793
0
    ereport(ERROR,
794
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
795
0
         errmsg("index \"%s\" contains unexpected zero page at block %u",
796
0
            RelationGetRelationName(rel),
797
0
            BufferGetBlockNumber(buf)),
798
0
         errhint("Please REINDEX it.")));
799
800
  /*
801
   * Additionally check that the special area looks sane.
802
   */
803
0
  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(BTPageOpaqueData)))
804
0
    ereport(ERROR,
805
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
806
0
         errmsg("index \"%s\" contains corrupted page at block %u",
807
0
            RelationGetRelationName(rel),
808
0
            BufferGetBlockNumber(buf)),
809
0
         errhint("Please REINDEX it.")));
810
0
}
811
812
/*
813
 *  _bt_getbuf() -- Get an existing block in a buffer, for read or write.
814
 *
815
 *    The general rule in nbtree is that it's never okay to access a
816
 *    page without holding both a buffer pin and a buffer lock on
817
 *    the page's buffer.
818
 *
819
 *    When this routine returns, the appropriate lock is set on the
820
 *    requested buffer and its reference count has been incremented
821
 *    (ie, the buffer is "locked and pinned").  Also, we apply
822
 *    _bt_checkpage to sanity-check the page, and perform Valgrind
823
 *    client requests that help Valgrind detect unsafe page accesses.
824
 *
825
 *    Note: raw LockBuffer() calls are disallowed in nbtree; all
826
 *    buffer lock requests need to go through wrapper functions such
827
 *    as _bt_lockbuf().
828
 */
829
Buffer
830
_bt_getbuf(Relation rel, BlockNumber blkno, int access)
831
0
{
832
0
  Buffer    buf;
833
834
0
  Assert(BlockNumberIsValid(blkno));
835
836
  /* Read an existing block of the relation */
837
0
  buf = ReadBuffer(rel, blkno);
838
0
  _bt_lockbuf(rel, buf, access);
839
0
  _bt_checkpage(rel, buf);
840
841
0
  return buf;
842
0
}
843
844
/*
845
 *  _bt_allocbuf() -- Allocate a new block/page.
846
 *
847
 * Returns a write-locked buffer containing an unallocated nbtree page.
848
 *
849
 * Callers are required to pass a valid heaprel.  We need heaprel so that we
850
 * can handle generating a snapshotConflictHorizon that makes reusing a page
851
 * from the FSM safe for queries that may be running on standbys.
852
 */
853
Buffer
854
_bt_allocbuf(Relation rel, Relation heaprel)
855
0
{
856
0
  Buffer    buf;
857
0
  BlockNumber blkno;
858
0
  Page    page;
859
860
0
  Assert(heaprel != NULL);
861
862
  /*
863
   * First see if the FSM knows of any free pages.
864
   *
865
   * We can't trust the FSM's report unreservedly; we have to check that the
866
   * page is still free.  (For example, an already-free page could have been
867
   * re-used between the time the last VACUUM scanned it and the time the
868
   * VACUUM made its FSM updates.)
869
   *
870
   * In fact, it's worse than that: we can't even assume that it's safe to
871
   * take a lock on the reported page.  If somebody else has a lock on it,
872
   * or even worse our own caller does, we could deadlock.  (The own-caller
873
   * scenario is actually not improbable. Consider an index on a serial or
874
   * timestamp column.  Nearly all splits will be at the rightmost page, so
875
   * it's entirely likely that _bt_split will call us while holding a lock
876
   * on the page most recently acquired from FSM. A VACUUM running
877
   * concurrently with the previous split could well have placed that page
878
   * back in FSM.)
879
   *
880
   * To get around that, we ask for only a conditional lock on the reported
881
   * page.  If we fail, then someone else is using the page, and we may
882
   * reasonably assume it's not free.  (If we happen to be wrong, the worst
883
   * consequence is the page will be lost to use till the next VACUUM, which
884
   * is no big problem.)
885
   */
886
0
  for (;;)
887
0
  {
888
0
    blkno = GetFreeIndexPage(rel);
889
0
    if (blkno == InvalidBlockNumber)
890
0
      break;
891
0
    buf = ReadBuffer(rel, blkno);
892
0
    if (_bt_conditionallockbuf(rel, buf))
893
0
    {
894
0
      page = BufferGetPage(buf);
895
896
      /*
897
       * It's possible to find an all-zeroes page in an index.  For
898
       * example, a backend might successfully extend the relation one
899
       * page and then crash before it is able to make a WAL entry for
900
       * adding the page.  If we find a zeroed page then reclaim it
901
       * immediately.
902
       */
903
0
      if (PageIsNew(page))
904
0
      {
905
        /* Okay to use page.  Initialize and return it. */
906
0
        _bt_pageinit(page, BufferGetPageSize(buf));
907
0
        return buf;
908
0
      }
909
910
0
      if (BTPageIsRecyclable(page, heaprel))
911
0
      {
912
        /*
913
         * If we are generating WAL for Hot Standby then create a WAL
914
         * record that will allow us to conflict with queries running
915
         * on standby, in case they have snapshots older than safexid
916
         * value
917
         */
918
0
        if (RelationNeedsWAL(rel) && XLogStandbyInfoActive())
919
0
        {
920
0
          xl_btree_reuse_page xlrec_reuse;
921
922
          /*
923
           * Note that we don't register the buffer with the record,
924
           * because this operation doesn't modify the page (that
925
           * already happened, back when VACUUM deleted the page).
926
           * This record only exists to provide a conflict point for
927
           * Hot Standby.  See record REDO routine comments.
928
           */
929
0
          xlrec_reuse.locator = rel->rd_locator;
930
0
          xlrec_reuse.block = blkno;
931
0
          xlrec_reuse.snapshotConflictHorizon = BTPageGetDeleteXid(page);
932
0
          xlrec_reuse.isCatalogRel =
933
0
            RelationIsAccessibleInLogicalDecoding(heaprel);
934
935
0
          XLogBeginInsert();
936
0
          XLogRegisterData(&xlrec_reuse, SizeOfBtreeReusePage);
937
938
0
          XLogInsert(RM_BTREE_ID, XLOG_BTREE_REUSE_PAGE);
939
0
        }
940
941
        /* Okay to use page.  Re-initialize and return it. */
942
0
        _bt_pageinit(page, BufferGetPageSize(buf));
943
0
        return buf;
944
0
      }
945
0
      elog(DEBUG2, "FSM returned nonrecyclable page");
946
0
      _bt_relbuf(rel, buf);
947
0
    }
948
0
    else
949
0
    {
950
0
      elog(DEBUG2, "FSM returned nonlockable page");
951
      /* couldn't get lock, so just drop pin */
952
0
      ReleaseBuffer(buf);
953
0
    }
954
0
  }
955
956
  /*
957
   * Extend the relation by one page. Need to use RBM_ZERO_AND_LOCK or we
958
   * risk a race condition against btvacuumscan --- see comments therein.
959
   * This forces us to repeat the valgrind request that _bt_lockbuf()
960
   * otherwise would make, as we can't use _bt_lockbuf() without introducing
961
   * a race.
962
   */
963
0
  buf = ExtendBufferedRel(BMR_REL(rel), MAIN_FORKNUM, NULL, EB_LOCK_FIRST);
964
0
  if (!RelationUsesLocalBuffers(rel))
965
0
    VALGRIND_MAKE_MEM_DEFINED(BufferGetPage(buf), BLCKSZ);
966
967
  /* Initialize the new page before returning it */
968
0
  page = BufferGetPage(buf);
969
0
  Assert(PageIsNew(page));
970
0
  _bt_pageinit(page, BufferGetPageSize(buf));
971
972
0
  return buf;
973
0
}
974
975
/*
976
 *  _bt_relandgetbuf() -- release a locked buffer and get another one.
977
 *
978
 * This is equivalent to _bt_relbuf followed by _bt_getbuf.  Also, if obuf is
979
 * InvalidBuffer then it reduces to just _bt_getbuf; allowing this case
980
 * simplifies some callers.
981
 *
982
 * The original motivation for using this was to avoid two entries to the
983
 * bufmgr when one would do.  However, now it's mainly just a notational
984
 * convenience.  The only case where it saves work over _bt_relbuf/_bt_getbuf
985
 * is when the target page is the same one already in the buffer.
986
 */
987
Buffer
988
_bt_relandgetbuf(Relation rel, Buffer obuf, BlockNumber blkno, int access)
989
0
{
990
0
  Buffer    buf;
991
992
0
  Assert(BlockNumberIsValid(blkno));
993
0
  if (BufferIsValid(obuf))
994
0
  {
995
0
    if (BufferGetBlockNumber(obuf) == blkno)
996
0
    {
997
      /* trade in old lock mode for new lock */
998
0
      _bt_unlockbuf(rel, obuf);
999
0
      buf = obuf;
1000
0
    }
1001
0
    else
1002
0
    {
1003
      /* release lock and pin at once, that's a bit more efficient */
1004
0
      _bt_relbuf(rel, obuf);
1005
0
      buf = ReadBuffer(rel, blkno);
1006
0
    }
1007
0
  }
1008
0
  else
1009
0
    buf = ReadBuffer(rel, blkno);
1010
1011
0
  _bt_lockbuf(rel, buf, access);
1012
0
  _bt_checkpage(rel, buf);
1013
1014
0
  return buf;
1015
0
}
1016
1017
/*
1018
 *  _bt_relbuf() -- release a locked buffer.
1019
 *
1020
 * Lock and pin (refcount) are both dropped. This is a bit more efficient than
1021
 * doing the two operations separately.
1022
 */
1023
void
1024
_bt_relbuf(Relation rel, Buffer buf)
1025
0
{
1026
  /*
1027
   * Buffer is pinned and locked, which means that it is expected to be
1028
   * defined and addressable.  Check that proactively.
1029
   */
1030
0
  VALGRIND_CHECK_MEM_IS_DEFINED(BufferGetPage(buf), BLCKSZ);
1031
0
  if (!RelationUsesLocalBuffers(rel))
1032
0
    VALGRIND_MAKE_MEM_NOACCESS(BufferGetPage(buf), BLCKSZ);
1033
1034
0
  UnlockReleaseBuffer(buf);
1035
0
}
1036
1037
/*
1038
 *  _bt_lockbuf() -- lock a pinned buffer.
1039
 *
1040
 * Lock is acquired without acquiring another pin.  This is like a raw
1041
 * LockBuffer() call, but performs extra steps needed by Valgrind.
1042
 *
1043
 * Note: Caller may need to call _bt_checkpage() with buf when pin on buf
1044
 * wasn't originally acquired in _bt_getbuf() or _bt_relandgetbuf().
1045
 */
1046
void
1047
_bt_lockbuf(Relation rel, Buffer buf, int access)
1048
0
{
1049
  /* LockBuffer() asserts that pin is held by this backend */
1050
0
  LockBuffer(buf, access);
1051
1052
  /*
1053
   * It doesn't matter that _bt_unlockbuf() won't get called in the event of
1054
   * an nbtree error (e.g. a unique violation error).  That won't cause
1055
   * Valgrind false positives.
1056
   *
1057
   * The nbtree client requests are superimposed on top of the bufmgr.c
1058
   * buffer pin client requests.  In the event of an nbtree error the buffer
1059
   * will certainly get marked as defined when the backend once again
1060
   * acquires its first pin on the buffer. (Of course, if the backend never
1061
   * touches the buffer again then it doesn't matter that it remains
1062
   * non-accessible to Valgrind.)
1063
   *
1064
   * Note: When an IndexTuple C pointer gets computed using an ItemId read
1065
   * from a page while a lock was held, the C pointer becomes unsafe to
1066
   * dereference forever as soon as the lock is released.  Valgrind can only
1067
   * detect cases where the pointer gets dereferenced with no _current_
1068
   * lock/pin held, though.
1069
   */
1070
0
  if (!RelationUsesLocalBuffers(rel))
1071
0
    VALGRIND_MAKE_MEM_DEFINED(BufferGetPage(buf), BLCKSZ);
1072
0
}
1073
1074
/*
1075
 *  _bt_unlockbuf() -- unlock a pinned buffer.
1076
 */
1077
void
1078
_bt_unlockbuf(Relation rel, Buffer buf)
1079
0
{
1080
  /*
1081
   * Buffer is pinned and locked, which means that it is expected to be
1082
   * defined and addressable.  Check that proactively.
1083
   */
1084
0
  VALGRIND_CHECK_MEM_IS_DEFINED(BufferGetPage(buf), BLCKSZ);
1085
1086
  /* LockBuffer() asserts that pin is held by this backend */
1087
0
  LockBuffer(buf, BUFFER_LOCK_UNLOCK);
1088
1089
0
  if (!RelationUsesLocalBuffers(rel))
1090
0
    VALGRIND_MAKE_MEM_NOACCESS(BufferGetPage(buf), BLCKSZ);
1091
0
}
1092
1093
/*
1094
 *  _bt_conditionallockbuf() -- conditionally BT_WRITE lock pinned
1095
 *  buffer.
1096
 *
1097
 * Note: Caller may need to call _bt_checkpage() with buf when pin on buf
1098
 * wasn't originally acquired in _bt_getbuf() or _bt_relandgetbuf().
1099
 */
1100
bool
1101
_bt_conditionallockbuf(Relation rel, Buffer buf)
1102
0
{
1103
  /* ConditionalLockBuffer() asserts that pin is held by this backend */
1104
0
  if (!ConditionalLockBuffer(buf))
1105
0
    return false;
1106
1107
0
  if (!RelationUsesLocalBuffers(rel))
1108
0
    VALGRIND_MAKE_MEM_DEFINED(BufferGetPage(buf), BLCKSZ);
1109
1110
0
  return true;
1111
0
}
1112
1113
/*
1114
 *  _bt_upgradelockbufcleanup() -- upgrade lock to a full cleanup lock.
1115
 */
1116
void
1117
_bt_upgradelockbufcleanup(Relation rel, Buffer buf)
1118
0
{
1119
  /*
1120
   * Buffer is pinned and locked, which means that it is expected to be
1121
   * defined and addressable.  Check that proactively.
1122
   */
1123
0
  VALGRIND_CHECK_MEM_IS_DEFINED(BufferGetPage(buf), BLCKSZ);
1124
1125
  /* LockBuffer() asserts that pin is held by this backend */
1126
0
  LockBuffer(buf, BUFFER_LOCK_UNLOCK);
1127
0
  LockBufferForCleanup(buf);
1128
0
}
1129
1130
/*
1131
 *  _bt_pageinit() -- Initialize a new page.
1132
 *
1133
 * On return, the page header is initialized; data space is empty;
1134
 * special space is zeroed out.
1135
 */
1136
void
1137
_bt_pageinit(Page page, Size size)
1138
0
{
1139
0
  PageInit(page, size, sizeof(BTPageOpaqueData));
1140
0
}
1141
1142
/*
1143
 * Delete item(s) from a btree leaf page during VACUUM.
1144
 *
1145
 * This routine assumes that the caller already has a full cleanup lock on
1146
 * the buffer.  Also, the given deletable and updatable arrays *must* be
1147
 * sorted in ascending order.
1148
 *
1149
 * Routine deals with deleting TIDs when some (but not all) of the heap TIDs
1150
 * in an existing posting list item are to be removed.  This works by
1151
 * updating/overwriting an existing item with caller's new version of the item
1152
 * (a version that lacks the TIDs that are to be deleted).
1153
 *
1154
 * We record VACUUMs and b-tree deletes differently in WAL.  Deletes must
1155
 * generate their own snapshotConflictHorizon directly from the tableam,
1156
 * whereas VACUUMs rely on the initial VACUUM table scan performing
1157
 * WAL-logging that takes care of the issue for the table's indexes
1158
 * indirectly.  Also, we remove the VACUUM cycle ID from pages, which b-tree
1159
 * deletes don't do.
1160
 */
1161
void
1162
_bt_delitems_vacuum(Relation rel, Buffer buf,
1163
          OffsetNumber *deletable, int ndeletable,
1164
          BTVacuumPosting *updatable, int nupdatable)
1165
0
{
1166
0
  Page    page = BufferGetPage(buf);
1167
0
  BTPageOpaque opaque;
1168
0
  bool    needswal = RelationNeedsWAL(rel);
1169
0
  char     *updatedbuf = NULL;
1170
0
  Size    updatedbuflen = 0;
1171
0
  OffsetNumber updatedoffsets[MaxIndexTuplesPerPage];
1172
0
  XLogRecPtr  recptr;
1173
1174
  /* Shouldn't be called unless there's something to do */
1175
0
  Assert(ndeletable > 0 || nupdatable > 0);
1176
1177
  /* Generate new version of posting lists without deleted TIDs */
1178
0
  if (nupdatable > 0)
1179
0
    updatedbuf = _bt_delitems_update(updatable, nupdatable,
1180
0
                     updatedoffsets, &updatedbuflen,
1181
0
                     needswal);
1182
1183
  /* No ereport(ERROR) until changes are logged */
1184
0
  START_CRIT_SECTION();
1185
1186
  /*
1187
   * Handle posting tuple updates.
1188
   *
1189
   * Deliberately do this before handling simple deletes.  If we did it the
1190
   * other way around (i.e. WAL record order -- simple deletes before
1191
   * updates) then we'd have to make compensating changes to the 'updatable'
1192
   * array of offset numbers.
1193
   *
1194
   * PageIndexTupleOverwrite() won't unset each item's LP_DEAD bit when it
1195
   * happens to already be set.  It's important that we not interfere with
1196
   * any future simple index tuple deletion operations.
1197
   */
1198
0
  for (int i = 0; i < nupdatable; i++)
1199
0
  {
1200
0
    OffsetNumber updatedoffset = updatedoffsets[i];
1201
0
    IndexTuple  itup;
1202
0
    Size    itemsz;
1203
1204
0
    itup = updatable[i]->itup;
1205
0
    itemsz = MAXALIGN(IndexTupleSize(itup));
1206
0
    if (!PageIndexTupleOverwrite(page, updatedoffset, itup, itemsz))
1207
0
      elog(PANIC, "failed to update partially dead item in block %u of index \"%s\"",
1208
0
         BufferGetBlockNumber(buf), RelationGetRelationName(rel));
1209
0
  }
1210
1211
  /* Now handle simple deletes of entire tuples */
1212
0
  if (ndeletable > 0)
1213
0
    PageIndexMultiDelete(page, deletable, ndeletable);
1214
1215
  /*
1216
   * We can clear the vacuum cycle ID since this page has certainly been
1217
   * processed by the current vacuum scan.
1218
   */
1219
0
  opaque = BTPageGetOpaque(page);
1220
0
  opaque->btpo_cycleid = 0;
1221
1222
  /*
1223
   * Clear the BTP_HAS_GARBAGE page flag.
1224
   *
1225
   * This flag indicates the presence of LP_DEAD items on the page (though
1226
   * not reliably).  Note that we only rely on it with pg_upgrade'd
1227
   * !heapkeyspace indexes.  That's why clearing it here won't usually
1228
   * interfere with simple index tuple deletion.
1229
   */
1230
0
  opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
1231
1232
0
  MarkBufferDirty(buf);
1233
1234
  /* XLOG stuff */
1235
0
  if (needswal)
1236
0
  {
1237
0
    xl_btree_vacuum xlrec_vacuum;
1238
1239
0
    xlrec_vacuum.ndeleted = ndeletable;
1240
0
    xlrec_vacuum.nupdated = nupdatable;
1241
1242
0
    XLogBeginInsert();
1243
0
    XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
1244
0
    XLogRegisterData(&xlrec_vacuum, SizeOfBtreeVacuum);
1245
1246
0
    if (ndeletable > 0)
1247
0
      XLogRegisterBufData(0, deletable,
1248
0
                ndeletable * sizeof(OffsetNumber));
1249
1250
0
    if (nupdatable > 0)
1251
0
    {
1252
0
      XLogRegisterBufData(0, updatedoffsets,
1253
0
                nupdatable * sizeof(OffsetNumber));
1254
0
      XLogRegisterBufData(0, updatedbuf, updatedbuflen);
1255
0
    }
1256
1257
0
    recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_VACUUM);
1258
0
  }
1259
0
  else
1260
0
    recptr = XLogGetFakeLSN(rel);
1261
1262
0
  PageSetLSN(page, recptr);
1263
1264
0
  END_CRIT_SECTION();
1265
1266
  /* can't leak memory here */
1267
0
  if (updatedbuf != NULL)
1268
0
    pfree(updatedbuf);
1269
  /* free tuples allocated within _bt_delitems_update() */
1270
0
  for (int i = 0; i < nupdatable; i++)
1271
0
    pfree(updatable[i]->itup);
1272
0
}
1273
1274
/*
1275
 * Delete item(s) from a btree leaf page during single-page cleanup.
1276
 *
1277
 * This routine assumes that the caller has pinned and write locked the
1278
 * buffer.  Also, the given deletable and updatable arrays *must* be sorted in
1279
 * ascending order.
1280
 *
1281
 * Routine deals with deleting TIDs when some (but not all) of the heap TIDs
1282
 * in an existing posting list item are to be removed.  This works by
1283
 * updating/overwriting an existing item with caller's new version of the item
1284
 * (a version that lacks the TIDs that are to be deleted).
1285
 *
1286
 * This is nearly the same as _bt_delitems_vacuum as far as what it does to
1287
 * the page, but it needs its own snapshotConflictHorizon and isCatalogRel
1288
 * (from the tableam).  This is used by the REDO routine to generate recovery
1289
 * conflicts.  The other difference is that only _bt_delitems_vacuum will
1290
 * clear page's VACUUM cycle ID.
1291
 */
1292
static void
1293
_bt_delitems_delete(Relation rel, Buffer buf,
1294
          TransactionId snapshotConflictHorizon, bool isCatalogRel,
1295
          OffsetNumber *deletable, int ndeletable,
1296
          BTVacuumPosting *updatable, int nupdatable)
1297
0
{
1298
0
  Page    page = BufferGetPage(buf);
1299
0
  BTPageOpaque opaque;
1300
0
  bool    needswal = RelationNeedsWAL(rel);
1301
0
  char     *updatedbuf = NULL;
1302
0
  Size    updatedbuflen = 0;
1303
0
  OffsetNumber updatedoffsets[MaxIndexTuplesPerPage];
1304
0
  XLogRecPtr  recptr;
1305
1306
  /* Shouldn't be called unless there's something to do */
1307
0
  Assert(ndeletable > 0 || nupdatable > 0);
1308
1309
  /* Generate new versions of posting lists without deleted TIDs */
1310
0
  if (nupdatable > 0)
1311
0
    updatedbuf = _bt_delitems_update(updatable, nupdatable,
1312
0
                     updatedoffsets, &updatedbuflen,
1313
0
                     needswal);
1314
1315
  /* No ereport(ERROR) until changes are logged */
1316
0
  START_CRIT_SECTION();
1317
1318
  /* Handle updates and deletes just like _bt_delitems_vacuum */
1319
0
  for (int i = 0; i < nupdatable; i++)
1320
0
  {
1321
0
    OffsetNumber updatedoffset = updatedoffsets[i];
1322
0
    IndexTuple  itup;
1323
0
    Size    itemsz;
1324
1325
0
    itup = updatable[i]->itup;
1326
0
    itemsz = MAXALIGN(IndexTupleSize(itup));
1327
0
    if (!PageIndexTupleOverwrite(page, updatedoffset, itup, itemsz))
1328
0
      elog(PANIC, "failed to update partially dead item in block %u of index \"%s\"",
1329
0
         BufferGetBlockNumber(buf), RelationGetRelationName(rel));
1330
0
  }
1331
1332
0
  if (ndeletable > 0)
1333
0
    PageIndexMultiDelete(page, deletable, ndeletable);
1334
1335
  /*
1336
   * Unlike _bt_delitems_vacuum, we *must not* clear the vacuum cycle ID at
1337
   * this point.  The VACUUM command alone controls vacuum cycle IDs.
1338
   */
1339
0
  opaque = BTPageGetOpaque(page);
1340
1341
  /*
1342
   * Clear the BTP_HAS_GARBAGE page flag.
1343
   *
1344
   * This flag indicates the presence of LP_DEAD items on the page (though
1345
   * not reliably).  Note that we only rely on it with pg_upgrade'd
1346
   * !heapkeyspace indexes.
1347
   */
1348
0
  opaque->btpo_flags &= ~BTP_HAS_GARBAGE;
1349
1350
0
  MarkBufferDirty(buf);
1351
1352
  /* XLOG stuff */
1353
0
  if (needswal)
1354
0
  {
1355
0
    xl_btree_delete xlrec_delete;
1356
1357
0
    xlrec_delete.snapshotConflictHorizon = snapshotConflictHorizon;
1358
0
    xlrec_delete.ndeleted = ndeletable;
1359
0
    xlrec_delete.nupdated = nupdatable;
1360
0
    xlrec_delete.isCatalogRel = isCatalogRel;
1361
1362
0
    XLogBeginInsert();
1363
0
    XLogRegisterBuffer(0, buf, REGBUF_STANDARD);
1364
0
    XLogRegisterData(&xlrec_delete, SizeOfBtreeDelete);
1365
1366
0
    if (ndeletable > 0)
1367
0
      XLogRegisterBufData(0, deletable,
1368
0
                ndeletable * sizeof(OffsetNumber));
1369
1370
0
    if (nupdatable > 0)
1371
0
    {
1372
0
      XLogRegisterBufData(0, updatedoffsets,
1373
0
                nupdatable * sizeof(OffsetNumber));
1374
0
      XLogRegisterBufData(0, updatedbuf, updatedbuflen);
1375
0
    }
1376
1377
0
    recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_DELETE);
1378
0
  }
1379
0
  else
1380
0
    recptr = XLogGetFakeLSN(rel);
1381
1382
0
  PageSetLSN(page, recptr);
1383
1384
0
  END_CRIT_SECTION();
1385
1386
  /* can't leak memory here */
1387
0
  if (updatedbuf != NULL)
1388
0
    pfree(updatedbuf);
1389
  /* free tuples allocated within _bt_delitems_update() */
1390
0
  for (int i = 0; i < nupdatable; i++)
1391
0
    pfree(updatable[i]->itup);
1392
0
}
1393
1394
/*
1395
 * Set up state needed to delete TIDs from posting list tuples via "updating"
1396
 * the tuple.  Performs steps common to both _bt_delitems_vacuum and
1397
 * _bt_delitems_delete.  These steps must take place before each function's
1398
 * critical section begins.
1399
 *
1400
 * updatable and nupdatable are inputs, though note that we will use
1401
 * _bt_update_posting() to replace the original itup with a pointer to a final
1402
 * version in palloc()'d memory.  Caller should free the tuples when its done.
1403
 *
1404
 * The first nupdatable entries from updatedoffsets are set to the page offset
1405
 * number for posting list tuples that caller updates.  This is mostly useful
1406
 * because caller may need to WAL-log the page offsets (though we always do
1407
 * this for caller out of convenience).
1408
 *
1409
 * Returns buffer consisting of an array of xl_btree_update structs that
1410
 * describe the steps we perform here for caller (though only when needswal is
1411
 * true).  Also sets *updatedbuflen to the final size of the buffer.  This
1412
 * buffer is used by caller when WAL logging is required.
1413
 */
1414
static char *
1415
_bt_delitems_update(BTVacuumPosting *updatable, int nupdatable,
1416
          OffsetNumber *updatedoffsets, Size *updatedbuflen,
1417
          bool needswal)
1418
0
{
1419
0
  char     *updatedbuf = NULL;
1420
0
  Size    buflen = 0;
1421
1422
  /* Shouldn't be called unless there's something to do */
1423
0
  Assert(nupdatable > 0);
1424
1425
0
  for (int i = 0; i < nupdatable; i++)
1426
0
  {
1427
0
    BTVacuumPosting vacposting = updatable[i];
1428
0
    Size    itemsz;
1429
1430
    /* Replace work area IndexTuple with updated version */
1431
0
    _bt_update_posting(vacposting);
1432
1433
    /* Keep track of size of xl_btree_update for updatedbuf in passing */
1434
0
    itemsz = SizeOfBtreeUpdate + vacposting->ndeletedtids * sizeof(uint16);
1435
0
    buflen += itemsz;
1436
1437
    /* Build updatedoffsets buffer in passing */
1438
0
    updatedoffsets[i] = vacposting->updatedoffset;
1439
0
  }
1440
1441
  /* XLOG stuff */
1442
0
  if (needswal)
1443
0
  {
1444
0
    Size    offset = 0;
1445
1446
    /* Allocate, set final size for caller */
1447
0
    updatedbuf = palloc(buflen);
1448
0
    *updatedbuflen = buflen;
1449
0
    for (int i = 0; i < nupdatable; i++)
1450
0
    {
1451
0
      BTVacuumPosting vacposting = updatable[i];
1452
0
      Size    itemsz;
1453
0
      xl_btree_update update;
1454
1455
0
      update.ndeletedtids = vacposting->ndeletedtids;
1456
0
      memcpy(updatedbuf + offset, &update.ndeletedtids,
1457
0
           SizeOfBtreeUpdate);
1458
0
      offset += SizeOfBtreeUpdate;
1459
1460
0
      itemsz = update.ndeletedtids * sizeof(uint16);
1461
0
      memcpy(updatedbuf + offset, vacposting->deletetids, itemsz);
1462
0
      offset += itemsz;
1463
0
    }
1464
0
  }
1465
1466
0
  return updatedbuf;
1467
0
}
1468
1469
/*
1470
 * Comparator used by _bt_delitems_delete_check() to restore deltids array
1471
 * back to its original leaf-page-wise sort order
1472
 */
1473
static int
1474
_bt_delitems_cmp(const void *a, const void *b)
1475
0
{
1476
0
  const TM_IndexDelete *indexdelete1 = a;
1477
0
  const TM_IndexDelete *indexdelete2 = b;
1478
1479
0
  Assert(indexdelete1->id != indexdelete2->id);
1480
1481
0
  return pg_cmp_s16(indexdelete1->id, indexdelete2->id);
1482
0
}
1483
1484
/*
1485
 * Try to delete item(s) from a btree leaf page during single-page cleanup.
1486
 *
1487
 * nbtree interface to table_index_delete_tuples().  Deletes a subset of index
1488
 * tuples from caller's deltids array: those whose TIDs are found safe to
1489
 * delete by the tableam (or already marked LP_DEAD in index, and so already
1490
 * known to be deletable by our simple index deletion caller).  We physically
1491
 * delete index tuples from buf leaf page last of all (for index tuples where
1492
 * that is known to be safe following our table_index_delete_tuples() call).
1493
 *
1494
 * Simple index deletion caller only includes TIDs from index tuples marked
1495
 * LP_DEAD, as well as extra TIDs it found on the same leaf page that can be
1496
 * included without increasing the total number of distinct table blocks for
1497
 * the deletion operation as a whole.  This approach often allows us to delete
1498
 * some extra index tuples that were practically free for tableam to check in
1499
 * passing (when they actually turn out to be safe to delete).  It probably
1500
 * only makes sense for the tableam to go ahead with these extra checks when
1501
 * it is block-oriented (otherwise the checks probably won't be practically
1502
 * free, which we rely on).  The tableam interface requires the tableam side
1503
 * to handle the problem, though, so this is okay (we as an index AM are free
1504
 * to make the simplifying assumption that all tableams must be block-based).
1505
 *
1506
 * Bottom-up index deletion caller provides all the TIDs from the leaf page,
1507
 * without expecting that tableam will check most of them.  The tableam has
1508
 * considerable discretion around which entries/blocks it checks.  Our role in
1509
 * costing the bottom-up deletion operation is strictly advisory.
1510
 *
1511
 * Note: Caller must have added deltids entries (i.e. entries that go in
1512
 * delstate's main array) in leaf-page-wise order: page offset number order,
1513
 * TID order among entries taken from the same posting list tuple (tiebreak on
1514
 * TID).  This order is convenient to work with here.
1515
 *
1516
 * Note: We also rely on the id field of each deltids element "capturing" this
1517
 * original leaf-page-wise order.  That is, we expect to be able to get back
1518
 * to the original leaf-page-wise order just by sorting deltids on the id
1519
 * field (tableam will sort deltids for its own reasons, so we'll need to put
1520
 * it back in leaf-page-wise order afterwards).
1521
 */
1522
void
1523
_bt_delitems_delete_check(Relation rel, Buffer buf, Relation heapRel,
1524
              TM_IndexDeleteOp *delstate)
1525
0
{
1526
0
  Page    page = BufferGetPage(buf);
1527
0
  TransactionId snapshotConflictHorizon;
1528
0
  bool    isCatalogRel;
1529
0
  OffsetNumber postingidxoffnum = InvalidOffsetNumber;
1530
0
  int     ndeletable = 0,
1531
0
        nupdatable = 0;
1532
0
  OffsetNumber deletable[MaxIndexTuplesPerPage];
1533
0
  BTVacuumPosting updatable[MaxIndexTuplesPerPage];
1534
1535
  /* Use tableam interface to determine which tuples to delete first */
1536
0
  snapshotConflictHorizon = table_index_delete_tuples(heapRel, delstate);
1537
0
  isCatalogRel = RelationIsAccessibleInLogicalDecoding(heapRel);
1538
1539
  /* Should not WAL-log snapshotConflictHorizon unless it's required */
1540
0
  if (!XLogStandbyInfoActive())
1541
0
    snapshotConflictHorizon = InvalidTransactionId;
1542
1543
  /*
1544
   * Construct a leaf-page-wise description of what _bt_delitems_delete()
1545
   * needs to do to physically delete index tuples from the page.
1546
   *
1547
   * Must sort deltids array to restore leaf-page-wise order (original order
1548
   * before call to tableam).  This is the order that the loop expects.
1549
   *
1550
   * Note that deltids array might be a lot smaller now.  It might even have
1551
   * no entries at all (with bottom-up deletion caller), in which case there
1552
   * is nothing left to do.
1553
   */
1554
0
  qsort(delstate->deltids, delstate->ndeltids, sizeof(TM_IndexDelete),
1555
0
      _bt_delitems_cmp);
1556
0
  if (delstate->ndeltids == 0)
1557
0
  {
1558
0
    Assert(delstate->bottomup);
1559
0
    return;
1560
0
  }
1561
1562
  /* We definitely have to delete at least one index tuple (or one TID) */
1563
0
  for (int i = 0; i < delstate->ndeltids; i++)
1564
0
  {
1565
0
    TM_IndexStatus *dstatus = delstate->status + delstate->deltids[i].id;
1566
0
    OffsetNumber idxoffnum = dstatus->idxoffnum;
1567
0
    ItemId    itemid = PageGetItemId(page, idxoffnum);
1568
0
    IndexTuple  itup = (IndexTuple) PageGetItem(page, itemid);
1569
0
    int     nestedi,
1570
0
          nitem;
1571
0
    BTVacuumPosting vacposting;
1572
1573
0
    Assert(OffsetNumberIsValid(idxoffnum));
1574
1575
0
    if (idxoffnum == postingidxoffnum)
1576
0
    {
1577
      /*
1578
       * This deltid entry is a TID from a posting list tuple that has
1579
       * already been completely processed
1580
       */
1581
0
      Assert(BTreeTupleIsPosting(itup));
1582
0
      Assert(ItemPointerCompare(BTreeTupleGetHeapTID(itup),
1583
0
                    &delstate->deltids[i].tid) < 0);
1584
0
      Assert(ItemPointerCompare(BTreeTupleGetMaxHeapTID(itup),
1585
0
                    &delstate->deltids[i].tid) >= 0);
1586
0
      continue;
1587
0
    }
1588
1589
0
    if (!BTreeTupleIsPosting(itup))
1590
0
    {
1591
      /* Plain non-pivot tuple */
1592
0
      Assert(ItemPointerEquals(&itup->t_tid, &delstate->deltids[i].tid));
1593
0
      if (dstatus->knowndeletable)
1594
0
        deletable[ndeletable++] = idxoffnum;
1595
0
      continue;
1596
0
    }
1597
1598
    /*
1599
     * itup is a posting list tuple whose lowest deltids entry (which may
1600
     * or may not be for the first TID from itup) is considered here now.
1601
     * We should process all of the deltids entries for the posting list
1602
     * together now, though (not just the lowest).  Remember to skip over
1603
     * later itup-related entries during later iterations of outermost
1604
     * loop.
1605
     */
1606
0
    postingidxoffnum = idxoffnum; /* Remember work in outermost loop */
1607
0
    nestedi = i;      /* Initialize for first itup deltids entry */
1608
0
    vacposting = NULL;   /* Describes final action for itup */
1609
0
    nitem = BTreeTupleGetNPosting(itup);
1610
0
    for (int p = 0; p < nitem; p++)
1611
0
    {
1612
0
      ItemPointer ptid = BTreeTupleGetPostingN(itup, p);
1613
0
      int     ptidcmp = -1;
1614
1615
      /*
1616
       * This nested loop reuses work across ptid TIDs taken from itup.
1617
       * We take advantage of the fact that both itup's TIDs and deltids
1618
       * entries (within a single itup/posting list grouping) must both
1619
       * be in ascending TID order.
1620
       */
1621
0
      for (; nestedi < delstate->ndeltids; nestedi++)
1622
0
      {
1623
0
        TM_IndexDelete *tcdeltid = &delstate->deltids[nestedi];
1624
0
        TM_IndexStatus *tdstatus = (delstate->status + tcdeltid->id);
1625
1626
        /* Stop once we get past all itup related deltids entries */
1627
0
        Assert(tdstatus->idxoffnum >= idxoffnum);
1628
0
        if (tdstatus->idxoffnum != idxoffnum)
1629
0
          break;
1630
1631
        /* Skip past non-deletable itup related entries up front */
1632
0
        if (!tdstatus->knowndeletable)
1633
0
          continue;
1634
1635
        /* Entry is first partial ptid match (or an exact match)? */
1636
0
        ptidcmp = ItemPointerCompare(&tcdeltid->tid, ptid);
1637
0
        if (ptidcmp >= 0)
1638
0
        {
1639
          /* Greater than or equal (partial or exact) match... */
1640
0
          break;
1641
0
        }
1642
0
      }
1643
1644
      /* ...exact ptid match to a deletable deltids entry? */
1645
0
      if (ptidcmp != 0)
1646
0
        continue;
1647
1648
      /* Exact match for deletable deltids entry -- ptid gets deleted */
1649
0
      if (vacposting == NULL)
1650
0
      {
1651
0
        vacposting = palloc(offsetof(BTVacuumPostingData, deletetids) +
1652
0
                  nitem * sizeof(uint16));
1653
0
        vacposting->itup = itup;
1654
0
        vacposting->updatedoffset = idxoffnum;
1655
0
        vacposting->ndeletedtids = 0;
1656
0
      }
1657
0
      vacposting->deletetids[vacposting->ndeletedtids++] = p;
1658
0
    }
1659
1660
    /* Final decision on itup, a posting list tuple */
1661
1662
0
    if (vacposting == NULL)
1663
0
    {
1664
      /* No TIDs to delete from itup -- do nothing */
1665
0
    }
1666
0
    else if (vacposting->ndeletedtids == nitem)
1667
0
    {
1668
      /* Straight delete of itup (to delete all TIDs) */
1669
0
      deletable[ndeletable++] = idxoffnum;
1670
      /* Turns out we won't need granular information */
1671
0
      pfree(vacposting);
1672
0
    }
1673
0
    else
1674
0
    {
1675
      /* Delete some (but not all) TIDs from itup */
1676
0
      Assert(vacposting->ndeletedtids > 0 &&
1677
0
           vacposting->ndeletedtids < nitem);
1678
0
      updatable[nupdatable++] = vacposting;
1679
0
    }
1680
0
  }
1681
1682
  /* Physically delete tuples (or TIDs) using deletable (or updatable) */
1683
0
  _bt_delitems_delete(rel, buf, snapshotConflictHorizon, isCatalogRel,
1684
0
            deletable, ndeletable, updatable, nupdatable);
1685
1686
  /* be tidy */
1687
0
  for (int i = 0; i < nupdatable; i++)
1688
0
    pfree(updatable[i]);
1689
0
}
1690
1691
/*
1692
 * Check that leftsib page (the btpo_prev of target page) is not marked with
1693
 * INCOMPLETE_SPLIT flag.  Used during page deletion.
1694
 *
1695
 * Returning true indicates that page flag is set in leftsib (which is
1696
 * definitely still the left sibling of target).  When that happens, the
1697
 * target doesn't have a downlink in parent, and the page deletion algorithm
1698
 * isn't prepared to handle that.  Deletion of the target page (or the whole
1699
 * subtree that contains the target page) cannot take place.
1700
 *
1701
 * Caller should not have a lock on the target page itself, since pages on the
1702
 * same level must always be locked left to right to avoid deadlocks.
1703
 */
1704
static bool
1705
_bt_leftsib_splitflag(Relation rel, BlockNumber leftsib, BlockNumber target)
1706
0
{
1707
0
  Buffer    buf;
1708
0
  Page    page;
1709
0
  BTPageOpaque opaque;
1710
0
  bool    result;
1711
1712
  /* Easy case: No left sibling */
1713
0
  if (leftsib == P_NONE)
1714
0
    return false;
1715
1716
0
  buf = _bt_getbuf(rel, leftsib, BT_READ);
1717
0
  page = BufferGetPage(buf);
1718
0
  opaque = BTPageGetOpaque(page);
1719
1720
  /*
1721
   * If the left sibling was concurrently split, so that its next-pointer
1722
   * doesn't point to the current page anymore, the split that created
1723
   * target must be completed.  Caller can reasonably expect that there will
1724
   * be a downlink to the target page that it can relocate using its stack.
1725
   * (We don't allow splitting an incompletely split page again until the
1726
   * previous split has been completed.)
1727
   */
1728
0
  result = (opaque->btpo_next == target && P_INCOMPLETE_SPLIT(opaque));
1729
0
  _bt_relbuf(rel, buf);
1730
1731
0
  return result;
1732
0
}
1733
1734
/*
1735
 * Check that leafrightsib page (the btpo_next of target leaf page) is not
1736
 * marked with ISHALFDEAD flag.  Used during page deletion.
1737
 *
1738
 * Returning true indicates that page flag is set in leafrightsib, so page
1739
 * deletion cannot go ahead.  Our caller is not prepared to deal with the case
1740
 * where the parent page does not have a pivot tuples whose downlink points to
1741
 * leafrightsib (due to an earlier interrupted VACUUM operation).  It doesn't
1742
 * seem worth going to the trouble of teaching our caller to deal with it.
1743
 * The situation will be resolved after VACUUM finishes the deletion of the
1744
 * half-dead page (when a future VACUUM operation reaches the target page
1745
 * again).
1746
 *
1747
 * _bt_leftsib_splitflag() is called for both leaf pages and internal pages.
1748
 * _bt_rightsib_halfdeadflag() is only called for leaf pages, though.  This is
1749
 * okay because of the restriction on deleting pages that are the rightmost
1750
 * page of their parent (i.e. that such deletions can only take place when the
1751
 * entire subtree must be deleted).  The leaf level check made here will apply
1752
 * to a right "cousin" leaf page rather than a simple right sibling leaf page
1753
 * in cases where caller actually goes on to attempt deleting pages that are
1754
 * above the leaf page.  The right cousin leaf page is representative of the
1755
 * left edge of the subtree to the right of the to-be-deleted subtree as a
1756
 * whole, which is exactly the condition that our caller cares about.
1757
 * (Besides, internal pages are never marked half-dead, so it isn't even
1758
 * possible to _directly_ assess if an internal page is part of some other
1759
 * to-be-deleted subtree.)
1760
 */
1761
static bool
1762
_bt_rightsib_halfdeadflag(Relation rel, BlockNumber leafrightsib)
1763
0
{
1764
0
  Buffer    buf;
1765
0
  Page    page;
1766
0
  BTPageOpaque opaque;
1767
0
  bool    result;
1768
1769
0
  Assert(leafrightsib != P_NONE);
1770
1771
0
  buf = _bt_getbuf(rel, leafrightsib, BT_READ);
1772
0
  page = BufferGetPage(buf);
1773
0
  opaque = BTPageGetOpaque(page);
1774
1775
0
  Assert(P_ISLEAF(opaque) && !P_ISDELETED(opaque));
1776
0
  result = P_ISHALFDEAD(opaque);
1777
0
  _bt_relbuf(rel, buf);
1778
1779
0
  return result;
1780
0
}
1781
1782
/*
1783
 * _bt_pagedel() -- Delete a leaf page from the b-tree, if legal to do so.
1784
 *
1785
 * This action unlinks the leaf page from the b-tree structure, removing all
1786
 * pointers leading to it --- but not touching its own left and right links.
1787
 * The page cannot be physically reclaimed right away, since other processes
1788
 * may currently be trying to follow links leading to the page; they have to
1789
 * be allowed to use its right-link to recover.  See nbtree/README.
1790
 *
1791
 * On entry, the target buffer must be pinned and locked (either read or write
1792
 * lock is OK).  The page must be an empty leaf page, which may be half-dead
1793
 * already (a half-dead page should only be passed to us when an earlier
1794
 * VACUUM operation was interrupted, though).  Note in particular that caller
1795
 * should never pass a buffer containing an existing deleted page here.  The
1796
 * lock and pin on caller's buffer will be dropped before we return.
1797
 *
1798
 * Maintains bulk delete stats for caller, which are taken from vstate.  We
1799
 * need to cooperate closely with caller here so that whole VACUUM operation
1800
 * reliably avoids any double counting of subsidiary-to-leafbuf pages that we
1801
 * delete in passing.  If such pages happen to be from a block number that is
1802
 * ahead of the current scanblkno position, then caller is expected to count
1803
 * them directly later on.  It's simpler for us to understand caller's
1804
 * requirements than it would be for caller to understand when or how a
1805
 * deleted page became deleted after the fact.
1806
 *
1807
 * NOTE: this leaks memory.  Rather than trying to clean up everything
1808
 * carefully, it's better to run it in a temp context that can be reset
1809
 * frequently.
1810
 */
1811
void
1812
_bt_pagedel(Relation rel, Buffer leafbuf, BTVacState *vstate)
1813
0
{
1814
0
  BlockNumber rightsib;
1815
0
  bool    rightsib_empty;
1816
0
  Page    page;
1817
0
  BTPageOpaque opaque;
1818
1819
  /*
1820
   * Save original leafbuf block number from caller.  Only deleted blocks
1821
   * that are <= scanblkno are added to bulk delete stat's pages_deleted
1822
   * count.
1823
   */
1824
0
  BlockNumber scanblkno = BufferGetBlockNumber(leafbuf);
1825
1826
  /*
1827
   * "stack" is a search stack leading (approximately) to the target page.
1828
   * It is initially NULL, but when iterating, we keep it to avoid
1829
   * duplicated search effort.
1830
   *
1831
   * Also, when "stack" is not NULL, we have already checked that the
1832
   * current page is not the right half of an incomplete split, i.e. the
1833
   * left sibling does not have its INCOMPLETE_SPLIT flag set, including
1834
   * when the current target page is to the right of caller's initial page
1835
   * (the scanblkno page).
1836
   */
1837
0
  BTStack   stack = NULL;
1838
1839
0
  for (;;)
1840
0
  {
1841
0
    page = BufferGetPage(leafbuf);
1842
0
    opaque = BTPageGetOpaque(page);
1843
1844
    /*
1845
     * Internal pages are never deleted directly, only as part of deleting
1846
     * the whole subtree all the way down to leaf level.
1847
     *
1848
     * Also check for deleted pages here.  Caller never passes us a fully
1849
     * deleted page.  Only VACUUM can delete pages, so there can't have
1850
     * been a concurrent deletion.  Assume that we reached any deleted
1851
     * page encountered here by following a sibling link, and that the
1852
     * index is corrupt.
1853
     */
1854
0
    Assert(!P_ISDELETED(opaque));
1855
0
    if (!P_ISLEAF(opaque) || P_ISDELETED(opaque))
1856
0
    {
1857
      /*
1858
       * Pre-9.4 page deletion only marked internal pages as half-dead,
1859
       * but now we only use that flag on leaf pages. The old algorithm
1860
       * was never supposed to leave half-dead pages in the tree, it was
1861
       * just a transient state, but it was nevertheless possible in
1862
       * error scenarios. We don't know how to deal with them here. They
1863
       * are harmless as far as searches are considered, but inserts
1864
       * into the deleted keyspace could add out-of-order downlinks in
1865
       * the upper levels. Log a notice, hopefully the admin will notice
1866
       * and reindex.
1867
       */
1868
0
      if (P_ISHALFDEAD(opaque))
1869
0
        ereport(LOG,
1870
0
            (errcode(ERRCODE_INDEX_CORRUPTED),
1871
0
             errmsg("index \"%s\" contains a half-dead internal page",
1872
0
                RelationGetRelationName(rel)),
1873
0
             errhint("This can be caused by an interrupted VACUUM in version 9.3 or older, before upgrade. Please REINDEX it.")));
1874
1875
0
      if (P_ISDELETED(opaque))
1876
0
        ereport(LOG,
1877
0
            (errcode(ERRCODE_INDEX_CORRUPTED),
1878
0
             errmsg_internal("found deleted block %u while following right link from block %u in index \"%s\"",
1879
0
                     BufferGetBlockNumber(leafbuf),
1880
0
                     scanblkno,
1881
0
                     RelationGetRelationName(rel))));
1882
1883
0
      _bt_relbuf(rel, leafbuf);
1884
0
      return;
1885
0
    }
1886
1887
    /*
1888
     * We can never delete rightmost pages nor root pages.  While at it,
1889
     * check that page is empty, since it's possible that the leafbuf page
1890
     * was empty a moment ago, but has since had some inserts.
1891
     *
1892
     * To keep the algorithm simple, we also never delete an incompletely
1893
     * split page (they should be rare enough that this doesn't make any
1894
     * meaningful difference to disk usage):
1895
     *
1896
     * The INCOMPLETE_SPLIT flag on the page tells us if the page is the
1897
     * left half of an incomplete split, but ensuring that it's not the
1898
     * right half is more complicated.  For that, we have to check that
1899
     * the left sibling doesn't have its INCOMPLETE_SPLIT flag set using
1900
     * _bt_leftsib_splitflag().  On the first iteration, we temporarily
1901
     * release the lock on scanblkno/leafbuf, check the left sibling, and
1902
     * construct a search stack to scanblkno.  On subsequent iterations,
1903
     * we know we stepped right from a page that passed these tests, so
1904
     * it's OK.
1905
     */
1906
0
    if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) ||
1907
0
      P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page) ||
1908
0
      P_INCOMPLETE_SPLIT(opaque))
1909
0
    {
1910
      /* Should never fail to delete a half-dead page */
1911
0
      Assert(!P_ISHALFDEAD(opaque));
1912
1913
0
      _bt_relbuf(rel, leafbuf);
1914
0
      return;
1915
0
    }
1916
1917
    /*
1918
     * First, remove downlink pointing to the page (or a parent of the
1919
     * page, if we are going to delete a taller subtree), and mark the
1920
     * leafbuf page half-dead
1921
     */
1922
0
    if (!P_ISHALFDEAD(opaque))
1923
0
    {
1924
      /*
1925
       * We need an approximate pointer to the page's parent page.  We
1926
       * use a variant of the standard search mechanism to search for
1927
       * the page's high key; this will give us a link to either the
1928
       * current parent or someplace to its left (if there are multiple
1929
       * equal high keys, which is possible with !heapkeyspace indexes).
1930
       *
1931
       * Also check if this is the right-half of an incomplete split
1932
       * (see comment above).
1933
       */
1934
0
      if (!stack)
1935
0
      {
1936
0
        BTScanInsert itup_key;
1937
0
        ItemId    itemid;
1938
0
        IndexTuple  targetkey;
1939
0
        BlockNumber leftsib,
1940
0
              leafblkno;
1941
0
        Buffer    sleafbuf;
1942
1943
0
        itemid = PageGetItemId(page, P_HIKEY);
1944
0
        targetkey = CopyIndexTuple((IndexTuple) PageGetItem(page, itemid));
1945
1946
0
        leftsib = opaque->btpo_prev;
1947
0
        leafblkno = BufferGetBlockNumber(leafbuf);
1948
1949
        /*
1950
         * To avoid deadlocks, we'd better drop the leaf page lock
1951
         * before going further.
1952
         */
1953
0
        _bt_unlockbuf(rel, leafbuf);
1954
1955
        /*
1956
         * Check that the left sibling of leafbuf (if any) is not
1957
         * marked with INCOMPLETE_SPLIT flag before proceeding
1958
         */
1959
0
        Assert(leafblkno == scanblkno);
1960
0
        if (_bt_leftsib_splitflag(rel, leftsib, leafblkno))
1961
0
        {
1962
0
          ReleaseBuffer(leafbuf);
1963
0
          return;
1964
0
        }
1965
1966
        /*
1967
         * We need an insertion scan key, so build one.
1968
         *
1969
         * _bt_search searches for the leaf page that contains any
1970
         * matching non-pivot tuples, but we need it to "search" for
1971
         * the high key pivot from the page that we're set to delete.
1972
         * Compensate for the mismatch by having _bt_search locate the
1973
         * last position < equal-to-untruncated-prefix non-pivots.
1974
         */
1975
0
        itup_key = _bt_mkscankey(rel, targetkey);
1976
1977
        /* Set up a BTLessStrategyNumber-like insertion scan key */
1978
0
        itup_key->nextkey = false;
1979
0
        itup_key->backward = true;
1980
0
        stack = _bt_search(rel, NULL, itup_key, &sleafbuf, BT_READ, true);
1981
        /* won't need a second lock or pin on leafbuf */
1982
0
        _bt_relbuf(rel, sleafbuf);
1983
1984
        /*
1985
         * Re-lock the leaf page, and start over to use our stack
1986
         * within _bt_mark_page_halfdead.  We must do it that way
1987
         * because it's possible that leafbuf can no longer be
1988
         * deleted.  We need to recheck.
1989
         *
1990
         * Note: We can't simply hold on to the sleafbuf lock instead,
1991
         * because it's barely possible that sleafbuf is not the same
1992
         * page as leafbuf.  This happens when leafbuf split after our
1993
         * original lock was dropped, but before _bt_search finished
1994
         * its descent.  We rely on the assumption that we'll find
1995
         * leafbuf isn't safe to delete anymore in this scenario.
1996
         * (Page deletion can cope with the stack being to the left of
1997
         * leafbuf, but not to the right of leafbuf.)
1998
         */
1999
0
        _bt_lockbuf(rel, leafbuf, BT_WRITE);
2000
0
        continue;
2001
0
      }
2002
2003
      /*
2004
       * See if it's safe to delete the leaf page, and determine how
2005
       * many parent/internal pages above the leaf level will be
2006
       * deleted.  If it's safe then _bt_mark_page_halfdead will also
2007
       * perform the first phase of deletion, which includes marking the
2008
       * leafbuf page half-dead.
2009
       */
2010
0
      Assert(P_ISLEAF(opaque) && !P_IGNORE(opaque));
2011
0
      if (!_bt_mark_page_halfdead(rel, vstate->info->heaprel, leafbuf,
2012
0
                    stack))
2013
0
      {
2014
0
        _bt_relbuf(rel, leafbuf);
2015
0
        return;
2016
0
      }
2017
0
    }
2018
0
    else
2019
0
    {
2020
0
      INJECTION_POINT("nbtree-finish-half-dead-page-vacuum", NULL);
2021
0
    }
2022
2023
    /*
2024
     * Then unlink it from its siblings.  Each call to
2025
     * _bt_unlink_halfdead_page unlinks the topmost page from the subtree,
2026
     * making it shallower.  Iterate until the leafbuf page is deleted.
2027
     */
2028
0
    rightsib_empty = false;
2029
0
    Assert(P_ISLEAF(opaque) && P_ISHALFDEAD(opaque));
2030
0
    while (P_ISHALFDEAD(opaque))
2031
0
    {
2032
      /* Check for interrupts in _bt_unlink_halfdead_page */
2033
0
      if (!_bt_unlink_halfdead_page(rel, leafbuf, scanblkno,
2034
0
                      &rightsib_empty, vstate))
2035
0
      {
2036
        /*
2037
         * _bt_unlink_halfdead_page should never fail, since we
2038
         * established that deletion is generally safe in
2039
         * _bt_mark_page_halfdead -- index must be corrupt.
2040
         *
2041
         * Note that _bt_unlink_halfdead_page already released the
2042
         * lock and pin on leafbuf for us.
2043
         */
2044
0
        Assert(false);
2045
0
        return;
2046
0
      }
2047
0
    }
2048
2049
0
    Assert(P_ISLEAF(opaque) && P_ISDELETED(opaque));
2050
2051
0
    rightsib = opaque->btpo_next;
2052
2053
0
    _bt_relbuf(rel, leafbuf);
2054
2055
    /*
2056
     * Check here, as calling loops will have locks held, preventing
2057
     * interrupts from being processed.
2058
     */
2059
0
    CHECK_FOR_INTERRUPTS();
2060
2061
    /*
2062
     * The page has now been deleted. If its right sibling is completely
2063
     * empty, it's possible that the reason we haven't deleted it earlier
2064
     * is that it was the rightmost child of the parent. Now that we
2065
     * removed the downlink for this page, the right sibling might now be
2066
     * the only child of the parent, and could be removed. It would be
2067
     * picked up by the next vacuum anyway, but might as well try to
2068
     * remove it now, so loop back to process the right sibling.
2069
     *
2070
     * Note: This relies on the assumption that _bt_getstackbuf() will be
2071
     * able to reuse our original descent stack with a different child
2072
     * block (provided that the child block is to the right of the
2073
     * original leaf page reached by _bt_search()). It will even update
2074
     * the descent stack each time we loop around, avoiding repeated work.
2075
     */
2076
0
    if (!rightsib_empty)
2077
0
      break;
2078
2079
0
    leafbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
2080
0
  }
2081
0
}
2082
2083
/*
2084
 * First stage of page deletion.
2085
 *
2086
 * Establish the height of the to-be-deleted subtree with leafbuf at its
2087
 * lowest level, remove the downlink to the subtree, and mark leafbuf
2088
 * half-dead.  The final to-be-deleted subtree is usually just leafbuf itself,
2089
 * but may include additional internal pages (at most one per level of the
2090
 * tree below the root).
2091
 *
2092
 * Caller must pass a valid heaprel, since it's just about possible that our
2093
 * call to _bt_lock_subtree_parent will need to allocate a new index page to
2094
 * complete a page split.  Every call to _bt_allocbuf needs to pass a heaprel.
2095
 *
2096
 * Returns 'false' if leafbuf is unsafe to delete, usually because leafbuf is
2097
 * the rightmost child of its parent (and parent has more than one downlink).
2098
 * Returns 'true' when the first stage of page deletion completed
2099
 * successfully.
2100
 */
2101
static bool
2102
_bt_mark_page_halfdead(Relation rel, Relation heaprel, Buffer leafbuf,
2103
             BTStack stack)
2104
0
{
2105
0
  BlockNumber leafblkno;
2106
0
  BlockNumber leafrightsib;
2107
0
  BlockNumber topparent;
2108
0
  BlockNumber topparentrightsib;
2109
0
  ItemId    itemid;
2110
0
  Page    page;
2111
0
  BTPageOpaque opaque;
2112
0
  Buffer    subtreeparent;
2113
0
  OffsetNumber poffset;
2114
0
  OffsetNumber nextoffset;
2115
0
  IndexTuple  itup;
2116
0
  IndexTupleData trunctuple;
2117
0
  XLogRecPtr  recptr;
2118
2119
0
  page = BufferGetPage(leafbuf);
2120
0
  opaque = BTPageGetOpaque(page);
2121
2122
0
  Assert(!P_RIGHTMOST(opaque) && !P_ISROOT(opaque) &&
2123
0
       P_ISLEAF(opaque) && !P_IGNORE(opaque) &&
2124
0
       P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page));
2125
0
  Assert(heaprel != NULL);
2126
2127
  /*
2128
   * Save info about the leaf page.
2129
   */
2130
0
  leafblkno = BufferGetBlockNumber(leafbuf);
2131
0
  leafrightsib = opaque->btpo_next;
2132
2133
  /*
2134
   * Before attempting to lock the parent page, check that the right sibling
2135
   * is not in half-dead state.  A half-dead right sibling would have no
2136
   * downlink in the parent, which would be highly confusing later when we
2137
   * delete the downlink.  It would fail the "right sibling of target page
2138
   * is also the next child in parent page" cross-check below.
2139
   */
2140
0
  if (_bt_rightsib_halfdeadflag(rel, leafrightsib))
2141
0
  {
2142
0
    elog(DEBUG1, "could not delete page %u because its right sibling %u is half-dead",
2143
0
       leafblkno, leafrightsib);
2144
0
    return false;
2145
0
  }
2146
2147
  /*
2148
   * We cannot delete a page that is the rightmost child of its immediate
2149
   * parent, unless it is the only child --- in which case the parent has to
2150
   * be deleted too, and the same condition applies recursively to it. We
2151
   * have to check this condition all the way up before trying to delete,
2152
   * and lock the parent of the root of the to-be-deleted subtree (the
2153
   * "subtree parent").  _bt_lock_subtree_parent() locks the subtree parent
2154
   * for us.  We remove the downlink to the "top parent" page (subtree root
2155
   * page) from the subtree parent page below.
2156
   *
2157
   * Initialize topparent to be leafbuf page now.  The final to-be-deleted
2158
   * subtree is often a degenerate one page subtree consisting only of the
2159
   * leafbuf page.  When that happens, the leafbuf page is the final subtree
2160
   * root page/top parent page.
2161
   */
2162
0
  topparent = leafblkno;
2163
0
  topparentrightsib = leafrightsib;
2164
0
  if (!_bt_lock_subtree_parent(rel, heaprel, leafblkno, stack,
2165
0
                 &subtreeparent, &poffset,
2166
0
                 &topparent, &topparentrightsib))
2167
0
    return false;
2168
2169
0
  page = BufferGetPage(subtreeparent);
2170
0
  opaque = BTPageGetOpaque(page);
2171
2172
#ifdef USE_ASSERT_CHECKING
2173
2174
  /*
2175
   * This is just an assertion because _bt_lock_subtree_parent should have
2176
   * guaranteed tuple has the expected contents
2177
   */
2178
  itemid = PageGetItemId(page, poffset);
2179
  itup = (IndexTuple) PageGetItem(page, itemid);
2180
  Assert(BTreeTupleGetDownLink(itup) == topparent);
2181
#endif
2182
2183
0
  nextoffset = OffsetNumberNext(poffset);
2184
0
  itemid = PageGetItemId(page, nextoffset);
2185
0
  itup = (IndexTuple) PageGetItem(page, itemid);
2186
2187
  /*
2188
   * Check that the parent-page index items we're about to delete/overwrite
2189
   * in subtree parent page contain what we expect.  This can fail if the
2190
   * index has become corrupt for some reason.  When that happens we back
2191
   * out of deletion of the leafbuf subtree.  (This is just like the case
2192
   * where _bt_lock_subtree_parent() cannot "re-find" leafbuf's downlink.)
2193
   */
2194
0
  if (BTreeTupleGetDownLink(itup) != topparentrightsib)
2195
0
  {
2196
0
    ereport(LOG,
2197
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
2198
0
         errmsg_internal("right sibling %u of block %u is not next child %u of block %u in index \"%s\"",
2199
0
                 topparentrightsib, topparent,
2200
0
                 BTreeTupleGetDownLink(itup),
2201
0
                 BufferGetBlockNumber(subtreeparent),
2202
0
                 RelationGetRelationName(rel))));
2203
2204
0
    _bt_relbuf(rel, subtreeparent);
2205
0
    Assert(false);
2206
0
    return false;
2207
0
  }
2208
2209
  /*
2210
   * Any insert which would have gone on the leaf block will now go to its
2211
   * right sibling.  In other words, the key space moves right.
2212
   */
2213
0
  PredicateLockPageCombine(rel, leafblkno, leafrightsib);
2214
2215
  /* No ereport(ERROR) until changes are logged */
2216
0
  START_CRIT_SECTION();
2217
2218
  /*
2219
   * Update parent of subtree.  We want to delete the downlink to the top
2220
   * parent page/root of the subtree, and the *following* key.  Easiest way
2221
   * is to copy the right sibling's downlink over the downlink that points
2222
   * to top parent page, and then delete the right sibling's original pivot
2223
   * tuple.
2224
   *
2225
   * Lanin and Shasha make the key space move left when deleting a page,
2226
   * whereas the key space moves right here.  That's why we cannot simply
2227
   * delete the pivot tuple with the downlink to the top parent page.  See
2228
   * nbtree/README.
2229
   */
2230
0
  page = BufferGetPage(subtreeparent);
2231
0
  opaque = BTPageGetOpaque(page);
2232
2233
0
  itemid = PageGetItemId(page, poffset);
2234
0
  itup = (IndexTuple) PageGetItem(page, itemid);
2235
0
  BTreeTupleSetDownLink(itup, topparentrightsib);
2236
2237
0
  nextoffset = OffsetNumberNext(poffset);
2238
0
  PageIndexTupleDelete(page, nextoffset);
2239
2240
  /*
2241
   * Mark the leaf page as half-dead, and stamp it with a link to the top
2242
   * parent page.  When the leaf page is also the top parent page, the link
2243
   * is set to InvalidBlockNumber.
2244
   */
2245
0
  page = BufferGetPage(leafbuf);
2246
0
  opaque = BTPageGetOpaque(page);
2247
0
  opaque->btpo_flags |= BTP_HALF_DEAD;
2248
2249
0
  Assert(PageGetMaxOffsetNumber(page) == P_HIKEY);
2250
0
  MemSet(&trunctuple, 0, sizeof(IndexTupleData));
2251
0
  trunctuple.t_info = sizeof(IndexTupleData);
2252
0
  if (topparent != leafblkno)
2253
0
    BTreeTupleSetTopParent(&trunctuple, topparent);
2254
0
  else
2255
0
    BTreeTupleSetTopParent(&trunctuple, InvalidBlockNumber);
2256
2257
0
  if (!PageIndexTupleOverwrite(page, P_HIKEY, &trunctuple, IndexTupleSize(&trunctuple)))
2258
0
    elog(ERROR, "could not overwrite high key in half-dead page");
2259
2260
  /* Must mark buffers dirty before XLogInsert */
2261
0
  MarkBufferDirty(subtreeparent);
2262
0
  MarkBufferDirty(leafbuf);
2263
2264
  /* XLOG stuff */
2265
0
  if (RelationNeedsWAL(rel))
2266
0
  {
2267
0
    xl_btree_mark_page_halfdead xlrec;
2268
2269
0
    xlrec.poffset = poffset;
2270
0
    xlrec.leafblk = leafblkno;
2271
0
    if (topparent != leafblkno)
2272
0
      xlrec.topparent = topparent;
2273
0
    else
2274
0
      xlrec.topparent = InvalidBlockNumber;
2275
2276
0
    XLogBeginInsert();
2277
0
    XLogRegisterBuffer(0, leafbuf, REGBUF_WILL_INIT);
2278
0
    XLogRegisterBuffer(1, subtreeparent, REGBUF_STANDARD);
2279
2280
0
    page = BufferGetPage(leafbuf);
2281
0
    opaque = BTPageGetOpaque(page);
2282
0
    xlrec.leftblk = opaque->btpo_prev;
2283
0
    xlrec.rightblk = opaque->btpo_next;
2284
2285
0
    XLogRegisterData(&xlrec, SizeOfBtreeMarkPageHalfDead);
2286
2287
0
    recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_MARK_PAGE_HALFDEAD);
2288
0
  }
2289
0
  else
2290
0
    recptr = XLogGetFakeLSN(rel);
2291
2292
0
  page = BufferGetPage(subtreeparent);
2293
0
  PageSetLSN(page, recptr);
2294
0
  page = BufferGetPage(leafbuf);
2295
0
  PageSetLSN(page, recptr);
2296
2297
0
  END_CRIT_SECTION();
2298
2299
0
  _bt_relbuf(rel, subtreeparent);
2300
0
  return true;
2301
0
}
2302
2303
/*
2304
 * Second stage of page deletion.
2305
 *
2306
 * Unlinks a single page (in the subtree undergoing deletion) from its
2307
 * siblings.  Also marks the page deleted.
2308
 *
2309
 * To get rid of the whole subtree, including the leaf page itself, call here
2310
 * until the leaf page is deleted.  The original "top parent" established in
2311
 * the first stage of deletion is deleted in the first call here, while the
2312
 * leaf page is deleted in the last call here.  Note that the leaf page itself
2313
 * is often the initial top parent page.
2314
 *
2315
 * Returns 'false' if the page could not be unlinked (shouldn't happen).  If
2316
 * the right sibling of the current target page is empty, *rightsib_empty is
2317
 * set to true, allowing caller to delete the target's right sibling page in
2318
 * passing.  Note that *rightsib_empty is only actually used by caller when
2319
 * target page is leafbuf, following last call here for leafbuf/the subtree
2320
 * containing leafbuf.  (We always set *rightsib_empty for caller, just to be
2321
 * consistent.)
2322
 *
2323
 * Must hold pin and lock on leafbuf at entry (read or write doesn't matter).
2324
 * On success exit, we'll be holding pin and write lock.  On failure exit,
2325
 * we'll release both pin and lock before returning (we define it that way
2326
 * to avoid having to reacquire a lock we already released).
2327
 */
2328
static bool
2329
_bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
2330
             bool *rightsib_empty, BTVacState *vstate)
2331
0
{
2332
0
  BlockNumber leafblkno = BufferGetBlockNumber(leafbuf);
2333
0
  IndexBulkDeleteResult *stats = vstate->stats;
2334
0
  BlockNumber leafleftsib;
2335
0
  BlockNumber leafrightsib;
2336
0
  BlockNumber target;
2337
0
  BlockNumber leftsib;
2338
0
  BlockNumber rightsib;
2339
0
  Buffer    lbuf = InvalidBuffer;
2340
0
  Buffer    buf;
2341
0
  Buffer    rbuf;
2342
0
  Buffer    metabuf = InvalidBuffer;
2343
0
  Page    metapg = NULL;
2344
0
  BTMetaPageData *metad = NULL;
2345
0
  ItemId    itemid;
2346
0
  Page    page;
2347
0
  BTPageOpaque opaque;
2348
0
  FullTransactionId safexid;
2349
0
  bool    rightsib_is_rightmost;
2350
0
  uint32    targetlevel;
2351
0
  IndexTuple  leafhikey;
2352
0
  BlockNumber leaftopparent;
2353
0
  XLogRecPtr  recptr;
2354
2355
0
  page = BufferGetPage(leafbuf);
2356
0
  opaque = BTPageGetOpaque(page);
2357
2358
0
  Assert(P_ISLEAF(opaque) && !P_ISDELETED(opaque) && P_ISHALFDEAD(opaque));
2359
2360
  /*
2361
   * Remember some information about the leaf page.
2362
   */
2363
0
  itemid = PageGetItemId(page, P_HIKEY);
2364
0
  leafhikey = (IndexTuple) PageGetItem(page, itemid);
2365
0
  target = BTreeTupleGetTopParent(leafhikey);
2366
0
  leafleftsib = opaque->btpo_prev;
2367
0
  leafrightsib = opaque->btpo_next;
2368
2369
0
  _bt_unlockbuf(rel, leafbuf);
2370
2371
0
  INJECTION_POINT("nbtree-leave-page-half-dead", NULL);
2372
2373
  /*
2374
   * Check here, as calling loops will have locks held, preventing
2375
   * interrupts from being processed.
2376
   */
2377
0
  CHECK_FOR_INTERRUPTS();
2378
2379
  /* Unlink the current top parent of the subtree */
2380
0
  if (!BlockNumberIsValid(target))
2381
0
  {
2382
    /* Target is leaf page (or leaf page is top parent, if you prefer) */
2383
0
    target = leafblkno;
2384
2385
0
    buf = leafbuf;
2386
0
    leftsib = leafleftsib;
2387
0
    targetlevel = 0;
2388
0
  }
2389
0
  else
2390
0
  {
2391
    /* Target is the internal page taken from leaf's top parent link */
2392
0
    Assert(target != leafblkno);
2393
2394
    /* Fetch the block number of the target's left sibling */
2395
0
    buf = _bt_getbuf(rel, target, BT_READ);
2396
0
    page = BufferGetPage(buf);
2397
0
    opaque = BTPageGetOpaque(page);
2398
0
    leftsib = opaque->btpo_prev;
2399
0
    targetlevel = opaque->btpo_level;
2400
0
    Assert(targetlevel > 0);
2401
2402
    /*
2403
     * To avoid deadlocks, we'd better drop the target page lock before
2404
     * going further.
2405
     */
2406
0
    _bt_unlockbuf(rel, buf);
2407
0
  }
2408
2409
  /*
2410
   * We have to lock the pages we need to modify in the standard order:
2411
   * moving right, then up.  Else we will deadlock against other writers.
2412
   *
2413
   * So, first lock the leaf page, if it's not the target.  Then find and
2414
   * write-lock the current left sibling of the target page.  The sibling
2415
   * that was current a moment ago could have split, so we may have to move
2416
   * right.
2417
   */
2418
0
  if (target != leafblkno)
2419
0
    _bt_lockbuf(rel, leafbuf, BT_WRITE);
2420
0
  if (leftsib != P_NONE)
2421
0
  {
2422
0
    lbuf = _bt_getbuf(rel, leftsib, BT_WRITE);
2423
0
    page = BufferGetPage(lbuf);
2424
0
    opaque = BTPageGetOpaque(page);
2425
0
    while (P_ISDELETED(opaque) || opaque->btpo_next != target)
2426
0
    {
2427
0
      bool    leftsibvalid = true;
2428
2429
      /*
2430
       * Before we follow the link from the page that was the left
2431
       * sibling mere moments ago, validate its right link.  This
2432
       * reduces the opportunities for loop to fail to ever make any
2433
       * progress in the presence of index corruption.
2434
       *
2435
       * Note: we rely on the assumption that there can only be one
2436
       * vacuum process running at a time (against the same index).
2437
       */
2438
0
      if (P_RIGHTMOST(opaque) || P_ISDELETED(opaque) ||
2439
0
        leftsib == opaque->btpo_next)
2440
0
        leftsibvalid = false;
2441
2442
0
      leftsib = opaque->btpo_next;
2443
0
      _bt_relbuf(rel, lbuf);
2444
2445
0
      if (!leftsibvalid)
2446
0
      {
2447
        /*
2448
         * This is known to fail in the field; sibling link corruption
2449
         * is relatively common.  Press on with vacuuming rather than
2450
         * just throwing an ERROR.
2451
         */
2452
0
        ereport(LOG,
2453
0
            (errcode(ERRCODE_INDEX_CORRUPTED),
2454
0
             errmsg_internal("valid left sibling for deletion target could not be located: "
2455
0
                     "left sibling %u of target %u with leafblkno %u and scanblkno %u on level %u of index \"%s\"",
2456
0
                     leftsib, target, leafblkno, scanblkno,
2457
0
                     targetlevel, RelationGetRelationName(rel))));
2458
2459
        /* Must release all pins and locks on failure exit */
2460
0
        ReleaseBuffer(buf);
2461
0
        if (target != leafblkno)
2462
0
          _bt_relbuf(rel, leafbuf);
2463
2464
0
        return false;
2465
0
      }
2466
2467
0
      CHECK_FOR_INTERRUPTS();
2468
2469
      /* step right one page */
2470
0
      lbuf = _bt_getbuf(rel, leftsib, BT_WRITE);
2471
0
      page = BufferGetPage(lbuf);
2472
0
      opaque = BTPageGetOpaque(page);
2473
0
    }
2474
0
  }
2475
0
  else
2476
0
    lbuf = InvalidBuffer;
2477
2478
  /* Next write-lock the target page itself */
2479
0
  _bt_lockbuf(rel, buf, BT_WRITE);
2480
0
  page = BufferGetPage(buf);
2481
0
  opaque = BTPageGetOpaque(page);
2482
2483
  /*
2484
   * Check page is still empty etc, else abandon deletion.  This is just for
2485
   * paranoia's sake; a half-dead page cannot resurrect because there can be
2486
   * only one vacuum process running at a time.
2487
   */
2488
0
  if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque))
2489
0
    elog(ERROR, "target page changed status unexpectedly in block %u of index \"%s\"",
2490
0
       target, RelationGetRelationName(rel));
2491
2492
0
  if (opaque->btpo_prev != leftsib)
2493
0
    ereport(ERROR,
2494
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
2495
0
         errmsg_internal("target page left link unexpectedly changed from %u to %u in block %u of index \"%s\"",
2496
0
                 leftsib, opaque->btpo_prev, target,
2497
0
                 RelationGetRelationName(rel))));
2498
2499
0
  if (target == leafblkno)
2500
0
  {
2501
0
    if (P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page) ||
2502
0
      !P_ISLEAF(opaque) || !P_ISHALFDEAD(opaque))
2503
0
      elog(ERROR, "target leaf page changed status unexpectedly in block %u of index \"%s\"",
2504
0
         target, RelationGetRelationName(rel));
2505
2506
    /* Leaf page is also target page: don't set leaftopparent */
2507
0
    leaftopparent = InvalidBlockNumber;
2508
0
  }
2509
0
  else
2510
0
  {
2511
0
    IndexTuple  finaldataitem;
2512
2513
0
    if (P_FIRSTDATAKEY(opaque) != PageGetMaxOffsetNumber(page) ||
2514
0
      P_ISLEAF(opaque))
2515
0
      elog(ERROR, "target internal page on level %u changed status unexpectedly in block %u of index \"%s\"",
2516
0
         targetlevel, target, RelationGetRelationName(rel));
2517
2518
    /* Target is internal: set leaftopparent for next call here...  */
2519
0
    itemid = PageGetItemId(page, P_FIRSTDATAKEY(opaque));
2520
0
    finaldataitem = (IndexTuple) PageGetItem(page, itemid);
2521
0
    leaftopparent = BTreeTupleGetDownLink(finaldataitem);
2522
    /* ...except when it would be a redundant pointer-to-self */
2523
0
    if (leaftopparent == leafblkno)
2524
0
      leaftopparent = InvalidBlockNumber;
2525
0
  }
2526
2527
  /* No leaftopparent for level 0 (leaf page) or level 1 target */
2528
0
  Assert(!BlockNumberIsValid(leaftopparent) || targetlevel > 1);
2529
2530
  /*
2531
   * And next write-lock the (current) right sibling.
2532
   */
2533
0
  rightsib = opaque->btpo_next;
2534
0
  rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
2535
0
  page = BufferGetPage(rbuf);
2536
0
  opaque = BTPageGetOpaque(page);
2537
2538
  /*
2539
   * Validate target's right sibling page.  Its left link must point back to
2540
   * the target page.
2541
   */
2542
0
  if (opaque->btpo_prev != target)
2543
0
  {
2544
    /*
2545
     * This is known to fail in the field; sibling link corruption is
2546
     * relatively common.  Press on with vacuuming rather than just
2547
     * throwing an ERROR (same approach used for left-sibling's-right-link
2548
     * validation check a moment ago).
2549
     */
2550
0
    ereport(LOG,
2551
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
2552
0
         errmsg_internal("right sibling's left-link doesn't match: "
2553
0
                 "right sibling %u of target %u with leafblkno %u "
2554
0
                 "and scanblkno %u spuriously links to non-target %u "
2555
0
                 "on level %u of index \"%s\"",
2556
0
                 rightsib, target, leafblkno,
2557
0
                 scanblkno, opaque->btpo_prev,
2558
0
                 targetlevel, RelationGetRelationName(rel))));
2559
2560
    /* Must release all pins and locks on failure exit */
2561
0
    if (BufferIsValid(lbuf))
2562
0
      _bt_relbuf(rel, lbuf);
2563
0
    _bt_relbuf(rel, rbuf);
2564
0
    _bt_relbuf(rel, buf);
2565
0
    if (target != leafblkno)
2566
0
      _bt_relbuf(rel, leafbuf);
2567
2568
0
    return false;
2569
0
  }
2570
2571
0
  rightsib_is_rightmost = P_RIGHTMOST(opaque);
2572
0
  *rightsib_empty = (P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page));
2573
2574
  /*
2575
   * If we are deleting the next-to-last page on the target's level, then
2576
   * the rightsib is a candidate to become the new fast root. (In theory, it
2577
   * might be possible to push the fast root even further down, but the odds
2578
   * of doing so are slim, and the locking considerations daunting.)
2579
   *
2580
   * We can safely acquire a lock on the metapage here --- see comments for
2581
   * _bt_newlevel().
2582
   */
2583
0
  if (leftsib == P_NONE && rightsib_is_rightmost)
2584
0
  {
2585
0
    page = BufferGetPage(rbuf);
2586
0
    opaque = BTPageGetOpaque(page);
2587
0
    if (P_RIGHTMOST(opaque))
2588
0
    {
2589
      /* rightsib will be the only one left on the level */
2590
0
      metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
2591
0
      metapg = BufferGetPage(metabuf);
2592
0
      metad = BTPageGetMeta(metapg);
2593
2594
      /*
2595
       * The expected case here is btm_fastlevel == targetlevel+1; if
2596
       * the fastlevel is <= targetlevel, something is wrong, and we
2597
       * choose to overwrite it to fix it.
2598
       */
2599
0
      if (metad->btm_fastlevel > targetlevel + 1)
2600
0
      {
2601
        /* no update wanted */
2602
0
        _bt_relbuf(rel, metabuf);
2603
0
        metabuf = InvalidBuffer;
2604
0
      }
2605
0
    }
2606
0
  }
2607
2608
  /*
2609
   * Here we begin doing the deletion.
2610
   */
2611
2612
  /* No ereport(ERROR) until changes are logged */
2613
0
  START_CRIT_SECTION();
2614
2615
  /*
2616
   * Update siblings' side-links.  Note the target page's side-links will
2617
   * continue to point to the siblings.  Asserts here are just rechecking
2618
   * things we already verified above.
2619
   */
2620
0
  if (BufferIsValid(lbuf))
2621
0
  {
2622
0
    page = BufferGetPage(lbuf);
2623
0
    opaque = BTPageGetOpaque(page);
2624
0
    Assert(opaque->btpo_next == target);
2625
0
    opaque->btpo_next = rightsib;
2626
0
  }
2627
0
  page = BufferGetPage(rbuf);
2628
0
  opaque = BTPageGetOpaque(page);
2629
0
  Assert(opaque->btpo_prev == target);
2630
0
  opaque->btpo_prev = leftsib;
2631
2632
  /*
2633
   * If we deleted a parent of the targeted leaf page, instead of the leaf
2634
   * itself, update the leaf to point to the next remaining child in the
2635
   * subtree.
2636
   *
2637
   * Note: We rely on the fact that a buffer pin on the leaf page has been
2638
   * held since leafhikey was initialized.  This is safe, though only
2639
   * because the page was already half-dead at that point.  The leaf page
2640
   * cannot have been modified by any other backend during the period when
2641
   * no lock was held.
2642
   */
2643
0
  if (target != leafblkno)
2644
0
    BTreeTupleSetTopParent(leafhikey, leaftopparent);
2645
2646
  /*
2647
   * Mark the page itself deleted.  It can be recycled when all current
2648
   * transactions are gone.  Storing GetTopTransactionId() would work, but
2649
   * we're in VACUUM and would not otherwise have an XID.  Having already
2650
   * updated links to the target, ReadNextFullTransactionId() suffices as an
2651
   * upper bound.  Any scan having retained a now-stale link is advertising
2652
   * in its PGPROC an xmin less than or equal to the value we read here.  It
2653
   * will continue to do so, holding back the xmin horizon, for the duration
2654
   * of that scan.
2655
   */
2656
0
  page = BufferGetPage(buf);
2657
0
  opaque = BTPageGetOpaque(page);
2658
0
  Assert(P_ISHALFDEAD(opaque) || !P_ISLEAF(opaque));
2659
2660
  /*
2661
   * Store upper bound XID that's used to determine when deleted page is no
2662
   * longer needed as a tombstone
2663
   */
2664
0
  safexid = ReadNextFullTransactionId();
2665
0
  BTPageSetDeleted(page, safexid);
2666
0
  opaque->btpo_cycleid = 0;
2667
2668
  /* And update the metapage, if needed */
2669
0
  if (BufferIsValid(metabuf))
2670
0
  {
2671
    /* upgrade metapage if needed */
2672
0
    if (metad->btm_version < BTREE_NOVAC_VERSION)
2673
0
      _bt_upgrademetapage(metapg);
2674
0
    metad->btm_fastroot = rightsib;
2675
0
    metad->btm_fastlevel = targetlevel;
2676
0
    MarkBufferDirty(metabuf);
2677
0
  }
2678
2679
  /* Must mark buffers dirty before XLogInsert */
2680
0
  MarkBufferDirty(rbuf);
2681
0
  MarkBufferDirty(buf);
2682
0
  if (BufferIsValid(lbuf))
2683
0
    MarkBufferDirty(lbuf);
2684
0
  if (target != leafblkno)
2685
0
    MarkBufferDirty(leafbuf);
2686
2687
  /* XLOG stuff */
2688
0
  if (RelationNeedsWAL(rel))
2689
0
  {
2690
0
    xl_btree_unlink_page xlrec;
2691
0
    xl_btree_metadata xlmeta;
2692
0
    uint8   xlinfo;
2693
2694
0
    XLogBeginInsert();
2695
2696
0
    XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
2697
0
    if (BufferIsValid(lbuf))
2698
0
      XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD);
2699
0
    XLogRegisterBuffer(2, rbuf, REGBUF_STANDARD);
2700
0
    if (target != leafblkno)
2701
0
      XLogRegisterBuffer(3, leafbuf, REGBUF_WILL_INIT);
2702
2703
    /* information stored on the target/to-be-unlinked block */
2704
0
    xlrec.leftsib = leftsib;
2705
0
    xlrec.rightsib = rightsib;
2706
0
    xlrec.level = targetlevel;
2707
0
    xlrec.safexid = safexid;
2708
2709
    /* information needed to recreate the leaf block (if not the target) */
2710
0
    xlrec.leafleftsib = leafleftsib;
2711
0
    xlrec.leafrightsib = leafrightsib;
2712
0
    xlrec.leaftopparent = leaftopparent;
2713
2714
0
    XLogRegisterData(&xlrec, SizeOfBtreeUnlinkPage);
2715
2716
0
    if (BufferIsValid(metabuf))
2717
0
    {
2718
0
      XLogRegisterBuffer(4, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD);
2719
2720
0
      Assert(metad->btm_version >= BTREE_NOVAC_VERSION);
2721
0
      xlmeta.version = metad->btm_version;
2722
0
      xlmeta.root = metad->btm_root;
2723
0
      xlmeta.level = metad->btm_level;
2724
0
      xlmeta.fastroot = metad->btm_fastroot;
2725
0
      xlmeta.fastlevel = metad->btm_fastlevel;
2726
0
      xlmeta.last_cleanup_num_delpages = metad->btm_last_cleanup_num_delpages;
2727
0
      xlmeta.allequalimage = metad->btm_allequalimage;
2728
2729
0
      XLogRegisterBufData(4, &xlmeta, sizeof(xl_btree_metadata));
2730
0
      xlinfo = XLOG_BTREE_UNLINK_PAGE_META;
2731
0
    }
2732
0
    else
2733
0
      xlinfo = XLOG_BTREE_UNLINK_PAGE;
2734
2735
0
    recptr = XLogInsert(RM_BTREE_ID, xlinfo);
2736
0
  }
2737
0
  else
2738
0
    recptr = XLogGetFakeLSN(rel);
2739
2740
0
  if (BufferIsValid(metabuf))
2741
0
    PageSetLSN(metapg, recptr);
2742
0
  page = BufferGetPage(rbuf);
2743
0
  PageSetLSN(page, recptr);
2744
0
  page = BufferGetPage(buf);
2745
0
  PageSetLSN(page, recptr);
2746
0
  if (BufferIsValid(lbuf))
2747
0
  {
2748
0
    page = BufferGetPage(lbuf);
2749
0
    PageSetLSN(page, recptr);
2750
0
  }
2751
0
  if (target != leafblkno)
2752
0
  {
2753
0
    page = BufferGetPage(leafbuf);
2754
0
    PageSetLSN(page, recptr);
2755
0
  }
2756
2757
0
  END_CRIT_SECTION();
2758
2759
  /* release metapage */
2760
0
  if (BufferIsValid(metabuf))
2761
0
    _bt_relbuf(rel, metabuf);
2762
2763
  /* release siblings */
2764
0
  if (BufferIsValid(lbuf))
2765
0
    _bt_relbuf(rel, lbuf);
2766
0
  _bt_relbuf(rel, rbuf);
2767
2768
  /* If the target is not leafbuf, we're done with it now -- release it */
2769
0
  if (target != leafblkno)
2770
0
    _bt_relbuf(rel, buf);
2771
2772
  /*
2773
   * Maintain pages_newly_deleted, which is simply the number of pages
2774
   * deleted by the ongoing VACUUM operation.
2775
   *
2776
   * Maintain pages_deleted in a way that takes into account how
2777
   * btvacuumpage() will count deleted pages that have yet to become
2778
   * scanblkno -- only count page when it's not going to get that treatment
2779
   * later on.
2780
   */
2781
0
  stats->pages_newly_deleted++;
2782
0
  if (target <= scanblkno)
2783
0
    stats->pages_deleted++;
2784
2785
  /*
2786
   * Remember information about the target page (now a newly deleted page)
2787
   * in dedicated vstate space for later.  The page will be considered as a
2788
   * candidate to place in the FSM at the end of the current btvacuumscan()
2789
   * call.
2790
   */
2791
0
  _bt_pendingfsm_add(vstate, target, safexid);
2792
2793
  /* Success - hold on to lock on leafbuf (might also have been target) */
2794
0
  return true;
2795
0
}
2796
2797
/*
2798
 * Establish how tall the to-be-deleted subtree will be during the first stage
2799
 * of page deletion.
2800
 *
2801
 * Caller's child argument is the block number of the page caller wants to
2802
 * delete (this is leafbuf's block number, except when we're called
2803
 * recursively).  stack is a search stack leading to it.  Note that we will
2804
 * update the stack entry(s) to reflect current downlink positions --- this is
2805
 * similar to the corresponding point in page split handling.
2806
 *
2807
 * If "first stage" caller cannot go ahead with deleting _any_ pages, returns
2808
 * false.  Returns true on success, in which case caller can use certain
2809
 * details established here to perform the first stage of deletion.  This
2810
 * function is the last point at which page deletion may be deemed unsafe
2811
 * (barring index corruption, or unexpected concurrent page deletions).
2812
 *
2813
 * We write lock the parent of the root of the to-be-deleted subtree for
2814
 * caller on success (i.e. we leave our lock on the *subtreeparent buffer for
2815
 * caller).  Caller will have to remove a downlink from *subtreeparent.  We
2816
 * also set a *subtreeparent offset number in *poffset, to indicate the
2817
 * location of the pivot tuple that contains the relevant downlink.
2818
 *
2819
 * The root of the to-be-deleted subtree is called the "top parent".  Note
2820
 * that the leafbuf page is often the final "top parent" page (you can think
2821
 * of the leafbuf page as a degenerate single page subtree when that happens).
2822
 * Caller should initialize *topparent to the target leafbuf page block number
2823
 * (while *topparentrightsib should be set to leafbuf's right sibling block
2824
 * number).  We will update *topparent (and *topparentrightsib) for caller
2825
 * here, though only when it turns out that caller will delete at least one
2826
 * internal page (i.e. only when caller needs to store a valid link to the top
2827
 * parent block in the leafbuf page using BTreeTupleSetTopParent()).
2828
 */
2829
static bool
2830
_bt_lock_subtree_parent(Relation rel, Relation heaprel, BlockNumber child,
2831
            BTStack stack, Buffer *subtreeparent,
2832
            OffsetNumber *poffset, BlockNumber *topparent,
2833
            BlockNumber *topparentrightsib)
2834
0
{
2835
0
  BlockNumber parent,
2836
0
        leftsibparent;
2837
0
  OffsetNumber parentoffset,
2838
0
        maxoff;
2839
0
  Buffer    pbuf;
2840
0
  Page    page;
2841
0
  BTPageOpaque opaque;
2842
2843
  /*
2844
   * Locate the pivot tuple whose downlink points to "child".  Write lock
2845
   * the parent page itself.
2846
   */
2847
0
  pbuf = _bt_getstackbuf(rel, heaprel, stack, child);
2848
0
  if (pbuf == InvalidBuffer)
2849
0
  {
2850
    /*
2851
     * Failed to "re-find" a pivot tuple whose downlink matched our child
2852
     * block number on the parent level -- the index must be corrupt.
2853
     * Don't even try to delete the leafbuf subtree.  Just report the
2854
     * issue and press on with vacuuming the index.
2855
     *
2856
     * Note: _bt_getstackbuf() recovers from concurrent page splits that
2857
     * take place on the parent level.  Its approach is a near-exhaustive
2858
     * linear search.  This also gives it a surprisingly good chance of
2859
     * recovering in the event of a buggy or inconsistent opclass.  But we
2860
     * don't rely on that here.
2861
     */
2862
0
    ereport(LOG,
2863
0
        (errcode(ERRCODE_INDEX_CORRUPTED),
2864
0
         errmsg_internal("failed to re-find parent key in index \"%s\" for deletion target page %u",
2865
0
                 RelationGetRelationName(rel), child)));
2866
0
    Assert(false);
2867
0
    return false;
2868
0
  }
2869
2870
0
  parent = stack->bts_blkno;
2871
0
  parentoffset = stack->bts_offset;
2872
2873
0
  page = BufferGetPage(pbuf);
2874
0
  opaque = BTPageGetOpaque(page);
2875
0
  maxoff = PageGetMaxOffsetNumber(page);
2876
0
  leftsibparent = opaque->btpo_prev;
2877
2878
  /*
2879
   * _bt_getstackbuf() completes page splits on returned parent buffer when
2880
   * required.
2881
   *
2882
   * In general it's a bad idea for VACUUM to use up more disk space, which
2883
   * is why page deletion does not finish incomplete page splits most of the
2884
   * time.  We allow this limited exception because the risk is much lower,
2885
   * and the potential downside of not proceeding is much higher:  A single
2886
   * internal page with the INCOMPLETE_SPLIT flag set might otherwise
2887
   * prevent us from deleting hundreds of empty leaf pages from one level
2888
   * down.
2889
   */
2890
0
  Assert(!P_INCOMPLETE_SPLIT(opaque));
2891
2892
0
  if (parentoffset < maxoff)
2893
0
  {
2894
    /*
2895
     * Child is not the rightmost child in parent, so it's safe to delete
2896
     * the subtree whose root/topparent is child page
2897
     */
2898
0
    *subtreeparent = pbuf;
2899
0
    *poffset = parentoffset;
2900
0
    return true;
2901
0
  }
2902
2903
  /*
2904
   * Child is the rightmost child of parent.
2905
   *
2906
   * Since it's the rightmost child of parent, deleting the child (or
2907
   * deleting the subtree whose root/topparent is the child page) is only
2908
   * safe when it's also possible to delete the parent.
2909
   */
2910
0
  Assert(parentoffset == maxoff);
2911
0
  if (parentoffset != P_FIRSTDATAKEY(opaque) || P_RIGHTMOST(opaque))
2912
0
  {
2913
    /*
2914
     * Child isn't parent's only child, or parent is rightmost on its
2915
     * entire level.  Definitely cannot delete any pages.
2916
     */
2917
0
    _bt_relbuf(rel, pbuf);
2918
0
    return false;
2919
0
  }
2920
2921
  /*
2922
   * Now make sure that the parent deletion is itself safe by examining the
2923
   * child's grandparent page.  Recurse, passing the parent page as the
2924
   * child page (child's grandparent is the parent on the next level up). If
2925
   * parent deletion is unsafe, then child deletion must also be unsafe (in
2926
   * which case caller cannot delete any pages at all).
2927
   */
2928
0
  *topparent = parent;
2929
0
  *topparentrightsib = opaque->btpo_next;
2930
2931
  /*
2932
   * Release lock on parent before recursing.
2933
   *
2934
   * It's OK to release page locks on parent before recursive call locks
2935
   * grandparent.  An internal page can only acquire an entry if the child
2936
   * is split, but that cannot happen as long as we still hold a lock on the
2937
   * leafbuf page.
2938
   */
2939
0
  _bt_relbuf(rel, pbuf);
2940
2941
  /*
2942
   * Before recursing, check that the left sibling of parent (if any) is not
2943
   * marked with INCOMPLETE_SPLIT flag first (must do so after we drop the
2944
   * parent lock).
2945
   *
2946
   * Note: We deliberately avoid completing incomplete splits here.
2947
   */
2948
0
  if (_bt_leftsib_splitflag(rel, leftsibparent, parent))
2949
0
    return false;
2950
2951
  /* Recurse to examine child page's grandparent page */
2952
0
  return _bt_lock_subtree_parent(rel, heaprel, parent, stack->bts_parent,
2953
0
                   subtreeparent, poffset,
2954
0
                   topparent, topparentrightsib);
2955
0
}
2956
2957
/*
2958
 * Initialize local memory state used by VACUUM for _bt_pendingfsm_finalize
2959
 * optimization.
2960
 *
2961
 * Called at the start of a btvacuumscan().  Caller's cleanuponly argument
2962
 * indicates if ongoing VACUUM has not (and will not) call btbulkdelete().
2963
 *
2964
 * We expect to allocate memory inside VACUUM's top-level memory context here.
2965
 * The working buffer is subject to a limit based on work_mem.  Our strategy
2966
 * when the array can no longer grow within the bounds of that limit is to
2967
 * stop saving additional newly deleted pages, while proceeding as usual with
2968
 * the pages that we can fit.
2969
 */
2970
void
2971
_bt_pendingfsm_init(Relation rel, BTVacState *vstate, bool cleanuponly)
2972
0
{
2973
0
  Size    maxbufsize;
2974
2975
  /*
2976
   * Don't bother with optimization in cleanup-only case -- we don't expect
2977
   * any newly deleted pages.  Besides, cleanup-only calls to btvacuumscan()
2978
   * can only take place because this optimization didn't work out during
2979
   * the last VACUUM.
2980
   */
2981
0
  if (cleanuponly)
2982
0
    return;
2983
2984
  /*
2985
   * Cap maximum size of array so that we always respect work_mem.  Avoid
2986
   * int overflow here.
2987
   */
2988
0
  vstate->bufsize = 256;
2989
0
  maxbufsize = (work_mem * (Size) 1024) / sizeof(BTPendingFSM);
2990
0
  maxbufsize = Min(maxbufsize, MaxAllocSize / sizeof(BTPendingFSM));
2991
  /* BTVacState.maxbufsize has type int */
2992
0
  maxbufsize = Min(maxbufsize, INT_MAX);
2993
  /* Stay sane with small work_mem */
2994
0
  maxbufsize = Max(maxbufsize, vstate->bufsize);
2995
0
  vstate->maxbufsize = (int) maxbufsize;
2996
2997
  /* Allocate buffer, indicate that there are currently 0 pending pages */
2998
0
  vstate->pendingpages = palloc_array(BTPendingFSM, vstate->bufsize);
2999
0
  vstate->npendingpages = 0;
3000
0
}
3001
3002
/*
3003
 * Place any newly deleted pages (i.e. pages that _bt_pagedel() deleted during
3004
 * the ongoing VACUUM operation) into the free space map -- though only when
3005
 * it is actually safe to do so by now.
3006
 *
3007
 * Called at the end of a btvacuumscan(), just before free space map vacuuming
3008
 * takes place.
3009
 *
3010
 * Frees memory allocated by _bt_pendingfsm_init(), if any.
3011
 */
3012
void
3013
_bt_pendingfsm_finalize(Relation rel, BTVacState *vstate)
3014
0
{
3015
0
  IndexBulkDeleteResult *stats = vstate->stats;
3016
0
  Relation  heaprel = vstate->info->heaprel;
3017
3018
0
  Assert(stats->pages_newly_deleted >= vstate->npendingpages);
3019
0
  Assert(heaprel != NULL);
3020
3021
0
  if (vstate->npendingpages == 0)
3022
0
  {
3023
    /* Just free memory when nothing to do */
3024
0
    if (vstate->pendingpages)
3025
0
      pfree(vstate->pendingpages);
3026
3027
0
    return;
3028
0
  }
3029
3030
#ifdef DEBUG_BTREE_PENDING_FSM
3031
3032
  /*
3033
   * Debugging aid: Sleep for 5 seconds to greatly increase the chances of
3034
   * placing pending pages in the FSM.  Note that the optimization will
3035
   * never be effective without some other backend concurrently consuming an
3036
   * XID.
3037
   */
3038
  pg_usleep(5000000L);
3039
#endif
3040
3041
  /*
3042
   * Recompute VACUUM XID boundaries.
3043
   *
3044
   * We don't actually care about the oldest non-removable XID.  Computing
3045
   * the oldest such XID has a useful side-effect that we rely on: it
3046
   * forcibly updates the XID horizon state for this backend.  This step is
3047
   * essential; GlobalVisCheckRemovableFullXid() will not reliably recognize
3048
   * that it is now safe to recycle newly deleted pages without this step.
3049
   */
3050
0
  GetOldestNonRemovableTransactionId(heaprel);
3051
3052
0
  for (unsigned int i = 0; i < vstate->npendingpages; i++)
3053
0
  {
3054
0
    BlockNumber target = vstate->pendingpages[i].target;
3055
0
    FullTransactionId safexid = vstate->pendingpages[i].safexid;
3056
3057
    /*
3058
     * Do the equivalent of checking BTPageIsRecyclable(), but without
3059
     * accessing the page again a second time.
3060
     *
3061
     * Give up on finding the first non-recyclable page -- all later pages
3062
     * must be non-recyclable too, since _bt_pendingfsm_add() adds pages
3063
     * to the array in safexid order.
3064
     */
3065
0
    if (!GlobalVisCheckRemovableFullXid(heaprel, safexid))
3066
0
      break;
3067
3068
0
    RecordFreeIndexPage(rel, target);
3069
0
    stats->pages_free++;
3070
0
  }
3071
3072
0
  pfree(vstate->pendingpages);
3073
0
}
3074
3075
/*
3076
 * Maintain array of pages that were deleted during current btvacuumscan()
3077
 * call, for use in _bt_pendingfsm_finalize()
3078
 */
3079
static void
3080
_bt_pendingfsm_add(BTVacState *vstate,
3081
           BlockNumber target,
3082
           FullTransactionId safexid)
3083
0
{
3084
0
  Assert(vstate->npendingpages <= vstate->bufsize);
3085
0
  Assert(vstate->bufsize <= vstate->maxbufsize);
3086
3087
#ifdef USE_ASSERT_CHECKING
3088
3089
  /*
3090
   * Verify an assumption made by _bt_pendingfsm_finalize(): pages from the
3091
   * array will always be in safexid order (since that is the order that we
3092
   * save them in here)
3093
   */
3094
  if (vstate->npendingpages > 0)
3095
  {
3096
    FullTransactionId lastsafexid =
3097
      vstate->pendingpages[vstate->npendingpages - 1].safexid;
3098
3099
    Assert(FullTransactionIdFollowsOrEquals(safexid, lastsafexid));
3100
  }
3101
#endif
3102
3103
  /*
3104
   * If temp buffer reaches maxbufsize/work_mem capacity then we discard
3105
   * information about this page.
3106
   *
3107
   * Note that this also covers the case where we opted to not use the
3108
   * optimization in _bt_pendingfsm_init().
3109
   */
3110
0
  if (vstate->npendingpages == vstate->maxbufsize)
3111
0
    return;
3112
3113
  /* Consider enlarging buffer */
3114
0
  if (vstate->npendingpages == vstate->bufsize)
3115
0
  {
3116
0
    int     newbufsize = vstate->bufsize * 2;
3117
3118
    /* Respect work_mem */
3119
0
    if (newbufsize > vstate->maxbufsize)
3120
0
      newbufsize = vstate->maxbufsize;
3121
3122
0
    vstate->bufsize = newbufsize;
3123
0
    vstate->pendingpages =
3124
0
      repalloc(vstate->pendingpages,
3125
0
           sizeof(BTPendingFSM) * vstate->bufsize);
3126
0
  }
3127
3128
  /* Save metadata for newly deleted page */
3129
0
  vstate->pendingpages[vstate->npendingpages].target = target;
3130
0
  vstate->pendingpages[vstate->npendingpages].safexid = safexid;
3131
0
  vstate->npendingpages++;
3132
0
}