up have the standard layout with unused space between pd_lower and pd_upper.
When this is set, XLogInsert will omit the unused space without bothering
to scan it to see if it's zero. That saves time in XLogInsert, and also
allows reversion of my earlier patch to make PageRepairFragmentation et al
explicitly re-zero freed space. Per suggestion by Heikki Linnakangas.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.192 2005/06/06 17:01:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.193 2005/06/06 20:22:56 tgl Exp $
*
*
* INTERFACE ROUTINES
xlrec.target.node = relation->rd_node;
xlrec.target.tid = tup->t_self;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfHeapInsert;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
xlhdr.t_natts = tup->t_data->t_natts;
* decides to write the whole page to the xlog, we don't need to
* store xl_heap_header in the xlog.
*/
- rdata[1].buffer = buffer;
rdata[1].data = (char *) &xlhdr;
rdata[1].len = SizeOfHeapHeader;
+ rdata[1].buffer = buffer;
+ rdata[1].buffer_std = true;
rdata[1].next = &(rdata[2]);
- rdata[2].buffer = buffer;
/* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
rdata[2].data = (char *) tup->t_data + offsetof(HeapTupleHeaderData, t_bits);
rdata[2].len = tup->t_len - offsetof(HeapTupleHeaderData, t_bits);
+ rdata[2].buffer = buffer;
+ rdata[2].buffer_std = true;
rdata[2].next = NULL;
/*
xlrec.target.node = relation->rd_node;
xlrec.target.tid = tp.t_self;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfHeapDelete;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = buffer;
rdata[1].data = NULL;
rdata[1].len = 0;
+ rdata[1].buffer = buffer;
+ rdata[1].buffer_std = true;
rdata[1].next = NULL;
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE, rdata);
xlrec.target.node = relation->rd_node;
xlrec.target.tid = tuple->t_self;
xlrec.shared_lock = (mode == LockTupleShared);
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfHeapLock;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = *buffer;
rdata[1].data = NULL;
rdata[1].len = 0;
+ rdata[1].buffer = *buffer;
+ rdata[1].buffer_std = true;
rdata[1].next = NULL;
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK, rdata);
xlrec.node = reln->rd_node;
xlrec.block = BufferGetBlockNumber(buffer);
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfHeapClean;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
/*
* that it is. When XLogInsert stores the whole buffer, the offsets
* array need not be stored too.
*/
- rdata[1].buffer = buffer;
if (uncnt > 0)
{
rdata[1].data = (char *) unused;
rdata[1].data = NULL;
rdata[1].len = 0;
}
+ rdata[1].buffer = buffer;
+ rdata[1].buffer_std = true;
rdata[1].next = NULL;
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CLEAN, rdata);
xlrec.target.node = reln->rd_node;
xlrec.target.tid = from;
xlrec.newtid = newtup->t_self;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfHeapUpdate;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = oldbuf;
rdata[1].data = NULL;
rdata[1].len = 0;
+ rdata[1].buffer = oldbuf;
+ rdata[1].buffer_std = true;
rdata[1].next = &(rdata[2]);
xlhdr.hdr.t_natts = newtup->t_data->t_natts;
* As with insert records, we need not store the rdata[2] segment if
* we decide to store the whole buffer instead.
*/
- rdata[2].buffer = newbuf;
rdata[2].data = (char *) &xlhdr;
rdata[2].len = hsize;
+ rdata[2].buffer = newbuf;
+ rdata[2].buffer_std = true;
rdata[2].next = &(rdata[3]);
- rdata[3].buffer = newbuf;
/* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
rdata[3].data = (char *) newtup->t_data + offsetof(HeapTupleHeaderData, t_bits);
rdata[3].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits);
+ rdata[3].buffer = newbuf;
+ rdata[3].buffer_std = true;
rdata[3].next = NULL;
/* If new tuple is the single and first tuple on page... */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.120 2005/03/21 01:23:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.121 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
xlrec.target.node = rel->rd_node;
ItemPointerSet(&(xlrec.target.tid), itup_blkno, itup_off);
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfBtreeInsert;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = nextrdata = &(rdata[1]);
if (BufferIsValid(metabuf))
xlmeta.fastroot = metad->btm_fastroot;
xlmeta.fastlevel = metad->btm_fastlevel;
- nextrdata->buffer = InvalidBuffer;
nextrdata->data = (char *) &xlmeta;
nextrdata->len = sizeof(xl_btree_metadata);
+ nextrdata->buffer = InvalidBuffer;
nextrdata->next = nextrdata + 1;
nextrdata++;
xlinfo = XLOG_BTREE_INSERT_META;
(sizeof(BTItemData) - sizeof(IndexTupleData));
}
nextrdata->buffer = buf;
+ nextrdata->buffer_std = true;
nextrdata->next = NULL;
recptr = XLogInsert(RM_BTREE_ID, xlinfo, rdata);
xlrec.leftlen = ((PageHeader) leftpage)->pd_special -
((PageHeader) leftpage)->pd_upper;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfBtreeSplit;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) leftpage + ((PageHeader) leftpage)->pd_upper;
rdata[1].len = xlrec.leftlen;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = &(rdata[2]);
- rdata[2].buffer = InvalidBuffer;
rdata[2].data = (char *) rightpage + ((PageHeader) rightpage)->pd_upper;
rdata[2].len = ((PageHeader) rightpage)->pd_special -
((PageHeader) rightpage)->pd_upper;
+ rdata[2].buffer = InvalidBuffer;
rdata[2].next = NULL;
if (!P_RIGHTMOST(ropaque))
{
rdata[2].next = &(rdata[3]);
- rdata[3].buffer = sbuf;
rdata[3].data = NULL;
rdata[3].len = 0;
+ rdata[3].buffer = sbuf;
+ rdata[3].buffer_std = true;
rdata[3].next = NULL;
}
xlrec.rootblk = rootblknum;
xlrec.level = metad->btm_level;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfBtreeNewroot;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
/*
* Direct access to page is not good but faster - we should
* implement some new func in page API.
*/
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) rootpage + ((PageHeader) rootpage)->pd_upper;
rdata[1].len = ((PageHeader) rootpage)->pd_special -
((PageHeader) rootpage)->pd_upper;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT, rdata);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.85 2005/06/02 05:55:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.86 2005/06/06 20:22:57 tgl Exp $
*
* NOTES
* Postgres btree pages look like ordinary relation pages. The opaque
xlrec.meta.fastroot = metad->btm_fastroot;
xlrec.meta.fastlevel = metad->btm_fastlevel;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfBtreeNewmeta;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = NULL;
recptr = XLogInsert(RM_BTREE_ID,
xlrec.rootblk = rootblkno;
xlrec.level = 0;
- rdata.buffer = InvalidBuffer;
rdata.data = (char *) &xlrec;
rdata.len = SizeOfBtreeNewroot;
+ rdata.buffer = InvalidBuffer;
rdata.next = NULL;
recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT, &rdata);
xlrec.node = rel->rd_node;
xlrec.block = BufferGetBlockNumber(buf);
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfBtreeDelete;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
/*
* it is. When XLogInsert stores the whole buffer, the offsets
* array need not be stored too.
*/
- rdata[1].buffer = buf;
if (nitems > 0)
{
rdata[1].data = (char *) itemnos;
rdata[1].data = NULL;
rdata[1].len = 0;
}
+ rdata[1].buffer = buf;
+ rdata[1].buffer_std = true;
rdata[1].next = NULL;
recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_DELETE, rdata);
xlrec.leftblk = leftsib;
xlrec.rightblk = rightsib;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfBtreeDeletePage;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = nextrdata = &(rdata[1]);
if (BufferIsValid(metabuf))
xlmeta.fastroot = metad->btm_fastroot;
xlmeta.fastlevel = metad->btm_fastlevel;
- nextrdata->buffer = InvalidBuffer;
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
xlinfo = XLOG_BTREE_DELETE_PAGE;
- nextrdata->buffer = pbuf;
nextrdata->data = NULL;
nextrdata->len = 0;
nextrdata->next = nextrdata + 1;
+ nextrdata->buffer = pbuf;
+ nextrdata->buffer_std = true;
nextrdata++;
- nextrdata->buffer = rbuf;
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->buffer = lbuf;
nextrdata->data = NULL;
nextrdata->len = 0;
+ nextrdata->buffer = lbuf;
+ nextrdata->buffer_std = true;
nextrdata->next = NULL;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.90 2004/12/31 21:59:22 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.91 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
xlrec.node = wstate->index->rd_node;
xlrec.blkno = blkno;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfHeapNewpage;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) page;
rdata[1].len = BLCKSZ;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/clog.c,v 1.29 2005/06/06 17:01:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/clog.c,v 1.30 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
XLogRecData rdata;
- rdata.buffer = InvalidBuffer;
rdata.data = (char *) (&pageno);
rdata.len = sizeof(int);
+ rdata.buffer = InvalidBuffer;
rdata.next = NULL;
(void) XLogInsert(RM_CLOG_ID, CLOG_ZEROPAGE | XLOG_NO_TRAN, &rdata);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.203 2005/06/06 17:01:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.204 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
xlrec.xtime = time(NULL);
xlrec.nrels = nrels;
xlrec.nsubxacts = nchildren;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) (&xlrec);
rdata[0].len = MinSizeOfXactCommit;
+ rdata[0].buffer = InvalidBuffer;
/* dump rels to delete */
if (nrels > 0)
{
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) rptr;
rdata[1].len = nrels * sizeof(RelFileNode);
+ rdata[1].buffer = InvalidBuffer;
lastrdata = 1;
}
/* dump committed child Xids */
if (nchildren > 0)
{
rdata[lastrdata].next = &(rdata[2]);
- rdata[2].buffer = InvalidBuffer;
rdata[2].data = (char *) children;
rdata[2].len = nchildren * sizeof(TransactionId);
+ rdata[2].buffer = InvalidBuffer;
lastrdata = 2;
}
rdata[lastrdata].next = NULL;
xlrec.xtime = time(NULL);
xlrec.nrels = nrels;
xlrec.nsubxacts = nchildren;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) (&xlrec);
rdata[0].len = MinSizeOfXactAbort;
+ rdata[0].buffer = InvalidBuffer;
/* dump rels to delete */
if (nrels > 0)
{
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) rptr;
rdata[1].len = nrels * sizeof(RelFileNode);
+ rdata[1].buffer = InvalidBuffer;
lastrdata = 1;
}
/* dump committed child Xids */
if (nchildren > 0)
{
rdata[lastrdata].next = &(rdata[2]);
- rdata[2].buffer = InvalidBuffer;
rdata[2].data = (char *) children;
rdata[2].len = nchildren * sizeof(TransactionId);
+ rdata[2].buffer = InvalidBuffer;
lastrdata = 2;
}
rdata[lastrdata].next = NULL;
xlrec.xtime = time(NULL);
xlrec.nrels = nrels;
xlrec.nsubxacts = nchildren;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) (&xlrec);
rdata[0].len = MinSizeOfXactAbort;
+ rdata[0].buffer = InvalidBuffer;
/* dump rels to delete */
if (nrels > 0)
{
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) rptr;
rdata[1].len = nrels * sizeof(RelFileNode);
+ rdata[1].buffer = InvalidBuffer;
lastrdata = 1;
}
/* dump committed child Xids */
if (nchildren > 0)
{
rdata[lastrdata].next = &(rdata[2]);
- rdata[2].buffer = InvalidBuffer;
rdata[2].data = (char *) children;
rdata[2].len = nchildren * sizeof(TransactionId);
+ rdata[2].buffer = InvalidBuffer;
lastrdata = 2;
}
rdata[lastrdata].next = NULL;
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.196 2005/06/06 17:01:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.197 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
uint32 endLogId, uint32 endLogSeg);
static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
-static void SetBkpBlock(BkpBlock *bkpb, Buffer buffer);
+static bool XLogCheckBuffer(XLogRecData *rdata,
+ XLogRecPtr *lsn, BkpBlock *bkpb);
static bool AdvanceXLInsertBuffer(void);
static void XLogWrite(XLogwrtRqst WriteRqst);
static int XLogFileInit(uint32 log, uint32 seg,
/*
* Insert an XLOG record having the specified RMID and info bytes,
* with the body of the record being the data chunk(s) described by
- * the rdata list (see xlog.h for notes about rdata).
+ * the rdata chain (see xlog.h for notes about rdata).
*
* Returns XLOG pointer to end of record (beginning of next record).
* This can be used as LSN for data pages affected by the logged action.
}
/*
- * Here we scan the rdata list, determine which buffers must be backed
+ * Here we scan the rdata chain, determine which buffers must be backed
* up, and compute the CRC values for the data. Note that the record
* header isn't added into the CRC initially since we don't know the
* final length or info bits quite yet. Thus, the CRC will represent
* below. We could prevent the race by doing all this work while
* holding the insert lock, but it seems better to avoid doing CRC
* calculations while holding the lock. This means we have to be
- * careful about modifying the rdata list until we know we aren't
+ * careful about modifying the rdata chain until we know we aren't
* going to loop back again. The only change we allow ourselves to
- * make earlier is to set rdt->data = NULL in list items we have
+ * make earlier is to set rdt->data = NULL in chain items we have
* decided we will have to back up the whole buffer for. This is OK
* because we will certainly decide the same thing again for those
* items if we do it over; doing it here saves an extra pass over the
- * list later.
+ * chain later.
*/
begin:;
for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)
{
if (rdt->buffer == dtbuf[i])
{
- /* Buffer already referenced by earlier list item */
+ /* Buffer already referenced by earlier chain item */
if (dtbuf_bkp[i])
rdt->data = NULL;
else if (rdt->data)
{
/* OK, put it in this slot */
dtbuf[i] = rdt->buffer;
-
- /*
- * XXX We assume page LSN is first data on page
- */
- dtbuf_lsn[i] = *((XLogRecPtr *) BufferGetBlock(rdt->buffer));
- if (XLByteLE(dtbuf_lsn[i], RedoRecPtr))
+ if (XLogCheckBuffer(rdt, &(dtbuf_lsn[i]), &(dtbuf_xlg[i])))
{
dtbuf_bkp[i] = true;
- SetBkpBlock(&(dtbuf_xlg[i]), rdt->buffer);
rdt->data = NULL;
}
else if (rdt->data)
elog(PANIC, "can backup at most %d blocks per xlog record",
XLR_MAX_BKP_BLOCKS);
}
- /* Break out of loop when rdt points to last list item */
+ /* Break out of loop when rdt points to last chain item */
if (rdt->next == NULL)
break;
rdt = rdt->next;
}
/*
- * Make additional rdata list entries for the backup blocks, so that
+ * Make additional rdata chain entries for the backup blocks, so that
* we don't need to special-case them in the write loop. Note that we
- * have now irrevocably changed the input rdata list. At the exit of
+ * have now irrevocably changed the input rdata chain. At the exit of
* this loop, write_len includes the backup block data.
*
* Also set the appropriate info bits to show which buffers were backed
* up. The i'th XLR_SET_BKP_BLOCK bit corresponds to the i'th
* distinct buffer value (ignoring InvalidBuffer) appearing in the
- * rdata list.
+ * rdata chain.
*/
write_len = len;
for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)
BkpBlock *bkpb;
char *page;
- if (dtbuf[i] == InvalidBuffer || !(dtbuf_bkp[i]))
+ if (!dtbuf_bkp[i])
continue;
info |= XLR_SET_BKP_BLOCK(i);
}
/*
- * Fill a BkpBlock struct given a buffer containing the page to be saved
- *
- * This is nontrivial only because it has to decide whether to apply "hole
- * compression".
+ * Determine whether the buffer referenced by an XLogRecData item has to
+ * be backed up, and if so fill a BkpBlock struct for it. In any case
+ * save the buffer's LSN at *lsn.
*/
-static void
-SetBkpBlock(BkpBlock *bkpb, Buffer buffer)
+static bool
+XLogCheckBuffer(XLogRecData *rdata,
+ XLogRecPtr *lsn, BkpBlock *bkpb)
{
PageHeader page;
- uint16 offset;
- uint16 length;
- /* Save page identity info */
- bkpb->node = BufferGetFileNode(buffer);
- bkpb->block = BufferGetBlockNumber(buffer);
+ page = (PageHeader) BufferGetBlock(rdata->buffer);
+
+ /*
+ * XXX We assume page LSN is first data on *every* page that can be
+ * passed to XLogInsert, whether it otherwise has the standard page
+ * layout or not.
+ */
+ *lsn = page->pd_lsn;
- /* Test whether there is a "hole" containing zeroes in the page */
- page = (PageHeader) BufferGetBlock(buffer);
- offset = page->pd_lower;
- /* Check if pd_lower appears sane at all */
- if (offset >= SizeOfPageHeaderData && offset < BLCKSZ)
+ if (XLByteLE(page->pd_lsn, RedoRecPtr))
{
- char *spd = (char *) page + offset;
- char *epd = (char *) page + BLCKSZ;
- char *pd = spd;
+ /*
+ * The page needs to be backed up, so set up *bkpb
+ */
+ bkpb->node = BufferGetFileNode(rdata->buffer);
+ bkpb->block = BufferGetBlockNumber(rdata->buffer);
+
+ if (rdata->buffer_std)
+ {
+ /* Assume we can omit data between pd_lower and pd_upper */
+ uint16 lower = page->pd_lower;
+ uint16 upper = page->pd_upper;
- while (pd < epd && *pd == '\0')
- pd++;
+ if (lower >= SizeOfPageHeaderData &&
+ upper > lower &&
+ upper <= BLCKSZ)
+ {
+ bkpb->hole_offset = lower;
+ bkpb->hole_length = upper - lower;
+ }
+ else
+ {
+ /* No "hole" to compress out */
+ bkpb->hole_offset = 0;
+ bkpb->hole_length = 0;
+ }
+ }
+ else
+ {
+ /* Not a standard page header, don't try to eliminate "hole" */
+ bkpb->hole_offset = 0;
+ bkpb->hole_length = 0;
+ }
- length = pd - spd;
- if (length == 0)
- offset = 0;
+ return true; /* buffer requires backup */
}
- else
- offset = length = 0;
- bkpb->hole_offset = offset;
- bkpb->hole_length = length;
+
+ return false; /* buffer does not need to be backed up */
}
/*
/*
* Now insert the checkpoint record into XLOG.
*/
- rdata.buffer = InvalidBuffer;
rdata.data = (char *) (&checkPoint);
rdata.len = sizeof(checkPoint);
+ rdata.buffer = InvalidBuffer;
rdata.next = NULL;
recptr = XLogInsert(RM_XLOG_ID,
{
XLogRecData rdata;
- rdata.buffer = InvalidBuffer;
rdata.data = (char *) (&nextOid);
rdata.len = sizeof(Oid);
+ rdata.buffer = InvalidBuffer;
rdata.next = NULL;
(void) XLogInsert(RM_XLOG_ID, XLOG_NEXTOID, &rdata);
/*
{
XLogRecData rdata;
- rdata.buffer = InvalidBuffer;
rdata.data = (char *) (&nextMulti);
rdata.len = sizeof(MultiXactId);
+ rdata.buffer = InvalidBuffer;
rdata.next = NULL;
(void) XLogInsert(RM_XLOG_ID, XLOG_NEXTMULTI, &rdata);
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.158 2005/06/06 17:01:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.159 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
xlrec.src_db_id = src_dboid;
xlrec.src_tablespace_id = srctablespace;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = sizeof(xl_dbase_create_rec);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = NULL;
(void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_CREATE, rdata);
xlrec.db_id = db_id;
xlrec.tablespace_id = dsttablespace;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = sizeof(xl_dbase_drop_rec);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = NULL;
(void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_DROP, rdata);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.121 2005/06/06 17:01:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.122 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
newseq->log_cnt = 0;
xlrec.node = rel->rd_node;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = sizeof(xl_seq_rec);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) tuple->t_data;
rdata[1].len = tuple->t_len;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
XLogRecData rdata[2];
xlrec.node = seqrel->rd_node;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = sizeof(xl_seq_rec);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
rdata[1].len = ((PageHeader) page)->pd_special -
((PageHeader) page)->pd_upper;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
XLogRecData rdata[2];
xlrec.node = seqrel->rd_node;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = sizeof(xl_seq_rec);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
/* set values that will be saved in xlog */
seq->is_called = true;
seq->log_cnt = 0;
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
rdata[1].len = ((PageHeader) page)->pd_special -
((PageHeader) page)->pd_upper;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
Page page = BufferGetPage(buf);
xlrec.node = seqrel->rd_node;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = sizeof(xl_seq_rec);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
/* set values that will be saved in xlog */
seq->is_called = true;
seq->log_cnt = 0;
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) page + ((PageHeader) page)->pd_upper;
rdata[1].len = ((PageHeader) page)->pd_special -
((PageHeader) page)->pd_upper;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG | XLOG_NO_TRAN, rdata);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.160 2005/06/05 00:38:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.161 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
xlrec.node = dst->smgr_rnode;
xlrec.blkno = blkno;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = SizeOfHeapNewpage;
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) page;
rdata[1].len = BLCKSZ;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.20 2005/06/06 17:01:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.21 2005/06/06 20:22:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
XLogRecData rdata[2];
xlrec.ts_id = tablespaceoid;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = offsetof(xl_tblspc_create_rec, ts_path);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = &(rdata[1]);
- rdata[1].buffer = InvalidBuffer;
rdata[1].data = (char *) location;
rdata[1].len = strlen(location) + 1;
+ rdata[1].buffer = InvalidBuffer;
rdata[1].next = NULL;
(void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_CREATE, rdata);
XLogRecData rdata[1];
xlrec.ts_id = tablespaceoid;
- rdata[0].buffer = InvalidBuffer;
rdata[0].data = (char *) &xlrec;
rdata[0].len = sizeof(xl_tblspc_drop_rec);
+ rdata[0].buffer = InvalidBuffer;
rdata[0].next = NULL;
(void) XLogInsert(RM_TBLSPC_ID, XLOG_TBLSPC_DROP, rdata);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.64 2005/06/02 05:55:28 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/page/bufpage.c,v 1.65 2005/06/06 20:22:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
lp = PageGetItemId(page, i + 1);
lp->lp_len = 0; /* indicate unused & deallocated */
}
- ((PageHeader) page)->pd_upper = pd_upper = pd_special;
+ ((PageHeader) page)->pd_upper = pd_special;
}
else
{ /* nused != 0 */
lp->lp_off = upper;
}
- ((PageHeader) page)->pd_upper = pd_upper = upper;
+ ((PageHeader) page)->pd_upper = upper;
pfree(itemidbase);
}
- /*
- * Zero out the now-free space. This is not essential, but it allows
- * xlog.c to compress WAL data better.
- */
- MemSet((char *) page + pd_lower, 0, pd_upper - pd_lower);
-
return (nline - nused);
}
phdr->pd_upper += size;
phdr->pd_lower -= sizeof(ItemIdData);
- /*
- * Zero out the just-freed space. This is not essential, but it allows
- * xlog.c to compress WAL data better.
- */
- MemSet((char *) page + phdr->pd_lower, 0, sizeof(ItemIdData));
- MemSet(addr, 0, size);
-
/*
* Finally, we need to adjust the linp entries that remain.
*
lp->lp_off = upper;
}
- phdr->pd_lower = pd_lower = SizeOfPageHeaderData + nused * sizeof(ItemIdData);
- phdr->pd_upper = pd_upper = upper;
-
- /*
- * Zero out the now-free space. This is not essential, but it allows
- * xlog.c to compress WAL data better.
- */
- MemSet((char *) page + pd_lower, 0, pd_upper - pd_lower);
+ phdr->pd_lower = SizeOfPageHeaderData + nused * sizeof(ItemIdData);
+ phdr->pd_upper = upper;
pfree(itemidbase);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.88 2005/06/06 17:01:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.89 2005/06/06 20:22:58 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
xlrec.rnode = reln->smgr_rnode;
- rdata.buffer = InvalidBuffer;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
+ rdata.buffer = InvalidBuffer;
rdata.next = NULL;
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLOG_NO_TRAN, &rdata);
xlrec.blkno = newblks;
xlrec.rnode = reln->smgr_rnode;
- rdata.buffer = InvalidBuffer;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
+ rdata.buffer = InvalidBuffer;
rdata.next = NULL;
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_TRUNCATE | XLOG_NO_TRAN,
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.63 2005/06/06 17:01:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.64 2005/06/06 20:22:58 tgl Exp $
*/
#ifndef XLOG_H
#define XLOG_H
extern int sync_method;
/*
- * List of these structs is used to pass data to XLogInsert().
+ * The rmgr data to be written by XLogInsert() is defined by a chain of
+ * one or more XLogRecData structs. (Multiple structs would be used when
+ * parts of the source data aren't physically adjacent in memory, or when
+ * multiple associated buffers need to be specified.)
*
* If buffer is valid then XLOG will check if buffer must be backed up
* (ie, whether this is first change of that page since last checkpoint).
* If so, the whole page contents are attached to the XLOG record, and XLOG
* sets XLR_BKP_BLOCK_X bit in xl_info. Note that the buffer must be pinned
- * and locked while this is going on, so that it won't change under us.
- * NB: when this happens, we do not bother to insert the associated data into
- * the XLOG record, since we assume it's present in the buffer. Therefore,
- * rmgr redo routines MUST pay attention to XLR_BKP_BLOCK_X to know what
- * is actually stored in the XLOG record.
+ * and exclusive-locked by the caller, so that it won't change under us.
+ * NB: when the buffer is backed up, we DO NOT insert the data pointed to by
+ * this XLogRecData struct into the XLOG record, since we assume it's present
+ * in the buffer. Therefore, rmgr redo routines MUST pay attention to
+ * XLR_BKP_BLOCK_X to know what is actually stored in the XLOG record.
+ * The i'th XLR_BKP_BLOCK bit corresponds to the i'th distinct buffer
+ * value (ignoring InvalidBuffer) appearing in the rdata chain.
+ *
+ * When buffer is valid, caller must set buffer_std to indicate whether the
+ * page uses standard pd_lower/pd_upper header fields. If this is true, then
+ * XLOG is allowed to omit the free space between pd_lower and pd_upper from
+ * the backed-up page image. Note that even when buffer_std is false, the
+ * page MUST have an LSN field as its first eight bytes!
+ *
+ * Note: data can be NULL to indicate no rmgr data associated with this chain
+ * entry. This can be sensible (ie, not a wasted entry) if buffer is valid.
+ * The implication is that the buffer has been changed by the operation being
+ * logged, and so may need to be backed up, but the change can be redone using
+ * only information already present elsewhere in the XLOG entry.
*/
typedef struct XLogRecData
{
- Buffer buffer; /* buffer associated with this data */
- char *data;
- uint32 len;
- struct XLogRecData *next;
+ char *data; /* start of rmgr data to include */
+ uint32 len; /* length of rmgr data to include */
+ Buffer buffer; /* buffer associated with data, if any */
+ bool buffer_std; /* buffer has standard pd_lower/pd_upper */
+ struct XLogRecData *next; /* next struct in chain, or NULL */
} XLogRecData;
extern TimeLineID ThisTimeLineID; /* current TLI */