/* Struct of generic xlog data for single page */ typedefstruct
{
Buffer buffer; /* registered buffer */ int flags; /* flags for this buffer */ int deltaLen; /* space consumed in delta field */ char *image; /* copy of page image for modification, do not
* do it in-place to have aligned memory chunk */ char delta[MAX_DELTA_SIZE]; /* delta between page images */
} GenericXLogPageData;
/* *Stateofgenericxlogrecordconstruction.MustbeallocatedatanI/O *alignedaddress.
*/ struct GenericXLogState
{ /* Page images (properly aligned, must be first) */
PGIOAlignedBlock images[MAX_GENERIC_XLOG_PAGES]; /* Info about each page, see above */
GenericXLogPageData pages[MAX_GENERIC_XLOG_PAGES]; bool isLogged;
};
staticvoid writeFragment(GenericXLogPageData *pageData, OffsetNumber offset,
OffsetNumber length, constchar *data); staticvoid computeRegionDelta(GenericXLogPageData *pageData, constchar *curpage, constchar *targetpage, int targetStart, int targetEnd, int validStart, int validEnd); staticvoid computeDelta(GenericXLogPageData *pageData, Page curpage, Page targetpage); staticvoid applyPageRedo(Page page, constchar *delta, Size deltaSize);
/* *ComputetheXLOGfragmentsneededtotransformaregionofcurpageintothe *correspondingregionoftargetpage,andappendthemtopageData'sdelta *field.TheregiontotransformrunsfromtargetStarttotargetEnd-1. *BytesincurpageoutsidetherangevalidStarttovalidEnd-1shouldbe *consideredinvalid,andalwaysoverwrittenwithtargetdata. * *Thisfunctionisahotspot,soit'sworthbeingastenseaspossible *aboutthedata-matchingloops.
*/ staticvoid
computeRegionDelta(GenericXLogPageData *pageData, constchar *curpage, constchar *targetpage, int targetStart, int targetEnd, int validStart, int validEnd)
{ int i,
loopEnd,
fragmentBegin = -1,
fragmentEnd = -1;
/* Deal with any invalid start region by including it in first fragment */ if (validStart > targetStart)
{
fragmentBegin = targetStart;
targetStart = validStart;
}
/* We'll deal with any invalid end region after the main loop */
loopEnd = Min(targetEnd, validEnd);
/* Examine all the potentially matchable bytes */
i = targetStart; while (i < loopEnd)
{ if (curpage[i] != targetpage[i])
{ /* On unmatched byte, start new fragment if not already in one */ if (fragmentBegin < 0)
fragmentBegin = i; /* Mark unmatched-data endpoint as uncertain */
fragmentEnd = -1; /* Extend the fragment as far as possible in a tight loop */
i++; while (i < loopEnd && curpage[i] != targetpage[i])
i++; if (i >= loopEnd) break;
}
/* Found a matched byte, so remember end of unmatched fragment */
fragmentEnd = i;
/* *Extendthematchasfaraspossibleinatightloop.(Ontypical *workloads,thisinnerloopisthebulkofthisfunction'sruntime.)
*/
i++; while (i < loopEnd && curpage[i] == targetpage[i])
i++;
/* Deal with any invalid end region by including it in final fragment */ if (loopEnd < targetEnd)
{ if (fragmentBegin < 0)
fragmentBegin = loopEnd;
fragmentEnd = targetEnd;
}
/* Write final fragment if any */ if (fragmentBegin >= 0)
{ if (fragmentEnd < 0)
fragmentEnd = targetEnd;
writeFragment(pageData, fragmentBegin,
fragmentEnd - fragmentBegin,
targetpage + fragmentBegin);
}
}
/* Compute delta records for lower part of page ... */
computeRegionDelta(pageData, curpage, targetpage, 0, targetLower, 0, curLower); /* ... and for upper part, ignoring what's between */
computeRegionDelta(pageData, curpage, targetpage,
targetUpper, BLCKSZ,
curUpper, BLCKSZ);
/* Insert xlog record */
lsn = XLogInsert(RM_GENERIC_ID, 0);
/* Set LSN */ for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
{
GenericXLogPageData *pageData = &state->pages[i];
if (BufferIsInvalid(pageData->buffer)) continue;
PageSetLSN(BufferGetPage(pageData->buffer), lsn);
}
END_CRIT_SECTION();
} else
{ /* Unlogged relation: skip xlog-related stuff */
START_CRIT_SECTION(); for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
{
GenericXLogPageData *pageData = &state->pages[i];
if (BufferIsInvalid(pageData->buffer)) continue;
memcpy(BufferGetPage(pageData->buffer),
pageData->image,
BLCKSZ); /* We don't worry about zeroing the "hole" in this case */
MarkBufferDirty(pageData->buffer);
}
END_CRIT_SECTION(); /* We don't have a LSN to return, in this case */
lsn = InvalidXLogRecPtr;
}
/* Changes are done: unlock and release all buffers */ for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
{ if (BufferIsValid(buffers[block_id]))
UnlockReleaseBuffer(buffers[block_id]);
}
}