+ /* XLOG stuff */
+ if (RelationNeedsWAL(rel))
+ {
+ xl_btree_delete_page xlrec;
+ xl_btree_metadata xlmeta;
+ uint8 xlinfo;
+ XLogRecPtr recptr;
+ XLogRecData rdata[5];
+ XLogRecData *nextrdata;
+
+ xlrec.target.node = rel->rd_node;
+ ItemPointerSet(&(xlrec.target.tid), parent, poffset);
+ xlrec.deadblk = target;
+ xlrec.leftblk = leftsib;
+ xlrec.rightblk = rightsib;
+ xlrec.btpo_xact = opaque->btpo.xact;
+
+ rdata[0].data = (char *) &xlrec;
+ rdata[0].len = SizeOfBtreeDeletePage;
+ rdata[0].buffer = InvalidBuffer;
+ rdata[0].next = nextrdata = &(rdata[1]);
+
+ if (BufferIsValid(metabuf))
+ {
+ xlmeta.root = metad->btm_root;
+ xlmeta.level = metad->btm_level;
+ xlmeta.fastroot = metad->btm_fastroot;
+ xlmeta.fastlevel = metad->btm_fastlevel;
+
+ nextrdata->data = (char *) &xlmeta;
+ nextrdata->len = sizeof(xl_btree_metadata);
+ nextrdata->buffer = InvalidBuffer;
+ nextrdata->next = nextrdata + 1;
+ nextrdata++;
+ xlinfo = XLOG_BTREE_DELETE_PAGE_META;
+ }
+ else if (parent_half_dead)
+ xlinfo = XLOG_BTREE_DELETE_PAGE_HALF;
+ else
+ xlinfo = XLOG_BTREE_DELETE_PAGE;
+
+ nextrdata->data = NULL;
+ nextrdata->len = 0;
+ nextrdata->next = nextrdata + 1;
+ nextrdata->buffer = pbuf;
+ nextrdata->buffer_std = true;
+ nextrdata++;
+
+ nextrdata->data = NULL;
+ nextrdata->len = 0;
+ nextrdata->buffer = rbuf;
+ nextrdata->buffer_std = true;
+ nextrdata->next = NULL;
+
+ if (BufferIsValid(lbuf))
+ {
+ nextrdata->next = nextrdata + 1;
+ nextrdata++;
+ nextrdata->data = NULL;
+ nextrdata->len = 0;
+ nextrdata->buffer = lbuf;
+ nextrdata->buffer_std = true;
+ nextrdata->next = NULL;
+ }
+
+ recptr = XLogInsert(RM_BTREE_ID, xlinfo, rdata);
+
+ if (BufferIsValid(metabuf))
+ {
+ PageSetLSN(metapg, recptr);
+ PageSetTLI(metapg, ThisTimeLineID);
+ }
+ page = BufferGetPage(pbuf);
+ PageSetLSN(page, recptr);
+ PageSetTLI(page, ThisTimeLineID);
+ page = BufferGetPage(rbuf);
+ PageSetLSN(page, recptr);
+ PageSetTLI(page, ThisTimeLineID);
+ page = BufferGetPage(buf);
+ PageSetLSN(page, recptr);
+ PageSetTLI(page, ThisTimeLineID);
+ if (BufferIsValid(lbuf))
+ {
+ page = BufferGetPage(lbuf);
+ PageSetLSN(page, recptr);
+ PageSetTLI(page, ThisTimeLineID);
+ }
+ }
+
+ END_CRIT_SECTION();
+
+ /* release metapage; send out relcache inval if metapage changed */
+ if (BufferIsValid(metabuf))
+ {
+ CacheInvalidateRelcache(rel);
+ _bt_relbuf(rel, metabuf);
+ }
+ /* can always release leftsib immediately */
+ if (BufferIsValid(lbuf))
+ _bt_relbuf(rel, lbuf);
+
+ /*
+ * If parent became half dead, recurse to delete it. Otherwise, if right
+ * sibling is empty and is now the last child of the parent, recurse to
+ * try to delete it. (These cases cannot apply at the same time, though
+ * the second case might itself recurse to the first.)
+ *
+ * When recursing to parent, we hold the lock on the target page until
+ * done. This delays any insertions into the keyspace that was just
+ * effectively reassigned to the parent's right sibling. If we allowed
+ * that, and there were enough such insertions before we finish deleting
+ * the parent, page splits within that keyspace could lead to inserting
+ * out-of-order keys into the grandparent level. It is thought that that
+ * wouldn't have any serious consequences, but it still seems like a
+ * pretty bad idea.
+ */
+ if (parent_half_dead)
+ {
+ /* recursive call will release pbuf */
+ _bt_relbuf(rel, rbuf);
+ result = _bt_pagedel(rel, pbuf, stack->bts_parent) + 1;
+ _bt_relbuf(rel, buf);
+ }
+ else if (parent_one_child && rightsib_empty)
+ {
+ _bt_relbuf(rel, pbuf);
+ _bt_relbuf(rel, buf);
+ /* recursive call will release rbuf */
+ result = _bt_pagedel(rel, rbuf, stack) + 1;
+ }
+ else
+ {
+ _bt_relbuf(rel, pbuf);
+ _bt_relbuf(rel, buf);
+ _bt_relbuf(rel, rbuf);
+ result = 1;
+ }