2727 * - length of page region (OffsetNumber)
2828 * - data - the data to place into the region ('length' number of bytes)
2929 *
30- * Unchanged regions of a page are not represented in its delta. As a
31- *result, a delta can be more compact than the full page image. But having
32- *an unchanged regionin the middle of two fragments that is smaller than
33- *the fragment header (offset and length) does not pay off in terms of the
34- *overall size of the delta. For this reason, webreak fragmentsonly if
35- *the unchanged region isbigger than MATCH_THRESHOLD.
30+ * Unchanged regions of a page are not represented in its delta. As a result,
31+ * a delta can be more compact than the full page image. But having an
32+ * unchanged regionbetween two fragments that is smaller than the fragment
33+ * header (offset+ length) does not pay off in terms of the overall size of
34+ * the delta. For this reason, wemerge adjacent fragmentsif the unchanged
35+ *region between them is<= MATCH_THRESHOLD bytes .
3636 *
3737 * The worst case for delta sizes occurs when we did not find any unchanged
3838 * region in the page. The size of the delta will be the size of the page plus
4141 */
4242#define FRAGMENT_HEADER_SIZE (2 * sizeof(OffsetNumber))
4343#define MATCH_THRESHOLD FRAGMENT_HEADER_SIZE
44- #define MAX_DELTA_SIZE BLCKSZ + FRAGMENT_HEADER_SIZE
44+ #define MAX_DELTA_SIZE ( BLCKSZ + FRAGMENT_HEADER_SIZE)
4545
4646/* Struct of generic xlog data for single page */
4747typedef struct
4848{
4949Buffer buffer ;/* registered buffer */
50- char image [BLCKSZ ];/* copy of page image for modification */
51- char data [MAX_DELTA_SIZE ];/* delta between page images */
52- int dataLen ;/* space consumed in data field */
5350bool fullImage ;/* are we taking a full image of this page? */
51+ int deltaLen ;/* space consumed in delta field */
52+ char image [BLCKSZ ];/* copy of page image for modification */
53+ char delta [MAX_DELTA_SIZE ];/* delta between page images */
5454}PageData ;
5555
5656/* State of generic xlog record construction */
@@ -61,22 +61,26 @@ struct GenericXLogState
6161};
6262
6363static void writeFragment (PageData * pageData ,OffsetNumber offset ,
64- OffsetNumber len ,Pointer data );
65- static void writeDelta (PageData * pageData );
66- static void applyPageRedo (Page page ,Pointer data ,Size dataSize );
64+ OffsetNumber len ,const char * data );
65+ static void computeDelta (PageData * pageData );
66+ static void applyPageRedo (Page page ,const char * delta ,Size deltaSize );
67+
6768
6869/*
69- * Write next fragment into delta.
70+ * Write next fragment into pageData's delta.
71+ *
72+ * The fragment has the given offset and length, and data points to the
73+ * actual data (of length length).
7074 */
7175static void
7276writeFragment (PageData * pageData ,OffsetNumber offset ,OffsetNumber length ,
73- Pointer data )
77+ const char * data )
7478{
75- Pointer ptr = pageData -> data + pageData -> dataLen ;
79+ char * ptr = pageData -> delta + pageData -> deltaLen ;
7680
77- /*Check if we have enough space */
78- Assert (pageData -> dataLen + sizeof (offset )+
79- sizeof (length )+ length <=sizeof (pageData -> data ));
81+ /*Verify we have enough space */
82+ Assert (pageData -> deltaLen + sizeof (offset )+
83+ sizeof (length )+ length <=sizeof (pageData -> delta ));
8084
8185/* Write fragment data */
8286memcpy (ptr ,& offset ,sizeof (offset ));
@@ -86,14 +90,14 @@ writeFragment(PageData *pageData, OffsetNumber offset, OffsetNumber length,
8690memcpy (ptr ,data ,length );
8791ptr += length ;
8892
89- pageData -> dataLen = ptr - pageData -> data ;
93+ pageData -> deltaLen = ptr - pageData -> delta ;
9094}
9195
9296/*
93- *Make delta for given page.
97+ *Compute the delta record for given page.
9498 */
9599static void
96- writeDelta (PageData * pageData )
100+ computeDelta (PageData * pageData )
97101{
98102Page page = BufferGetPage (pageData -> buffer ,NULL ,NULL ,
99103BGP_NO_SNAPSHOT_TEST ),
@@ -106,6 +110,8 @@ writeDelta(PageData *pageData)
106110imageLower = ((PageHeader )image )-> pd_lower ,
107111imageUpper = ((PageHeader )image )-> pd_upper ;
108112
113+ pageData -> deltaLen = 0 ;
114+
109115for (i = 0 ;i < BLCKSZ ;i ++ )
110116{
111117bool match ;
@@ -181,22 +187,22 @@ writeDelta(PageData *pageData)
181187char tmp [BLCKSZ ];
182188
183189memcpy (tmp ,image ,BLCKSZ );
184- applyPageRedo (tmp ,pageData -> data ,pageData -> dataLen );
185- if (memcmp (tmp ,page ,pageLower )
186- || memcmp (tmp + pageUpper ,page + pageUpper ,BLCKSZ - pageUpper ))
190+ applyPageRedo (tmp ,pageData -> delta ,pageData -> deltaLen );
191+ if (memcmp (tmp ,page ,pageLower )!= 0 ||
192+ memcmp (tmp + pageUpper ,page + pageUpper ,BLCKSZ - pageUpper )!= 0 )
187193elog (ERROR ,"result of generic xlog apply does not match" );
188194}
189195#endif
190196}
191197
192198/*
193- * Start new generic xlog record.
199+ * Start new generic xlog record for modifications to specified relation .
194200 */
195201GenericXLogState *
196202GenericXLogStart (Relation relation )
197203{
198- int i ;
199204GenericXLogState * state ;
205+ int i ;
200206
201207state = (GenericXLogState * )palloc (sizeof (GenericXLogState ));
202208
@@ -209,24 +215,30 @@ GenericXLogStart(Relation relation)
209215
210216/*
211217 * Register new buffer for generic xlog record.
218+ *
219+ * Returns pointer to the page's image in the GenericXLogState, which
220+ * is what the caller should modify.
221+ *
222+ * If the buffer is already registered, just return its existing entry.
212223 */
213224Page
214225GenericXLogRegister (GenericXLogState * state ,Buffer buffer ,bool isNew )
215226{
216227int block_id ;
217228
218- /*Place new buffer to unused slot in array */
229+ /*Search array for existing entry or first unused slot */
219230for (block_id = 0 ;block_id < MAX_GENERIC_XLOG_PAGES ;block_id ++ )
220231{
221232PageData * page = & state -> pages [block_id ];
222233
223234if (BufferIsInvalid (page -> buffer ))
224235{
236+ /* Empty slot, so use it (there cannot be a match later) */
225237page -> buffer = buffer ;
226- memcpy (page -> image ,BufferGetPage (buffer ,NULL ,NULL ,
227- BGP_NO_SNAPSHOT_TEST ),BLCKSZ );
228- page -> dataLen = 0 ;
229238page -> fullImage = isNew ;
239+ memcpy (page -> image ,
240+ BufferGetPage (buffer ,NULL ,NULL ,BGP_NO_SNAPSHOT_TEST ),
241+ BLCKSZ );
230242return (Page )page -> image ;
231243}
232244else if (page -> buffer == buffer )
@@ -239,15 +251,16 @@ GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
239251}
240252}
241253
242- elog (ERROR ,"maximum numberof %d generic xlog buffers is exceeded" ,
254+ elog (ERROR ,"maximum number%d of generic xlog buffers is exceeded" ,
243255MAX_GENERIC_XLOG_PAGES );
244-
245256/* keep compiler quiet */
246257return NULL ;
247258}
248259
249260/*
250261 * Unregister particular buffer for generic xlog record.
262+ *
263+ * XXX this is dangerous and should go away.
251264 */
252265void
253266GenericXLogUnregister (GenericXLogState * state ,Buffer buffer )
@@ -274,7 +287,8 @@ GenericXLogUnregister(GenericXLogState *state, Buffer buffer)
274287}
275288
276289/*
277- * Put all changes in registered buffers to generic xlog record.
290+ * Apply changes represented by GenericXLogState to the actual buffers,
291+ * and emit a generic xlog record.
278292 */
279293XLogRecPtr
280294GenericXLogFinish (GenericXLogState * state )
@@ -291,33 +305,35 @@ GenericXLogFinish(GenericXLogState *state)
291305
292306for (i = 0 ;i < MAX_GENERIC_XLOG_PAGES ;i ++ )
293307{
308+ PageData * pageData = & state -> pages [i ];
309+ Page page ;
294310char tmp [BLCKSZ ];
295- PageData * page = & state -> pages [i ];
296311
297- if (BufferIsInvalid (page -> buffer ))
312+ if (BufferIsInvalid (pageData -> buffer ))
298313continue ;
299314
315+ page = BufferGetPage (pageData -> buffer ,NULL ,NULL ,
316+ BGP_NO_SNAPSHOT_TEST );
317+
300318/* Swap current and saved page image. */
301- memcpy (tmp ,page -> image ,BLCKSZ );
302- memcpy (page -> image ,BufferGetPage (page -> buffer ,NULL ,NULL ,
303- BGP_NO_SNAPSHOT_TEST ),BLCKSZ );
304- memcpy (BufferGetPage (page -> buffer ,NULL ,NULL ,
305- BGP_NO_SNAPSHOT_TEST ),tmp ,BLCKSZ );
319+ memcpy (tmp ,pageData -> image ,BLCKSZ );
320+ memcpy (pageData -> image ,page ,BLCKSZ );
321+ memcpy (page ,tmp ,BLCKSZ );
306322
307- if (page -> fullImage )
323+ if (pageData -> fullImage )
308324{
309325/* A full page image does not require anything special */
310- XLogRegisterBuffer (i ,page -> buffer ,REGBUF_FORCE_IMAGE );
326+ XLogRegisterBuffer (i ,pageData -> buffer ,REGBUF_FORCE_IMAGE );
311327}
312328else
313329{
314330/*
315- * In normal mode, calculate delta and write it as data
331+ * In normal mode, calculate delta and write it asxlog data
316332 * associated with this page.
317333 */
318- XLogRegisterBuffer (i ,page -> buffer ,REGBUF_STANDARD );
319- writeDelta ( page );
320- XLogRegisterBufData (i ,page -> data , page -> dataLen );
334+ XLogRegisterBuffer (i ,pageData -> buffer ,REGBUF_STANDARD );
335+ computeDelta ( pageData );
336+ XLogRegisterBufData (i ,pageData -> delta , pageData -> deltaLen );
321337}
322338}
323339
@@ -327,13 +343,13 @@ GenericXLogFinish(GenericXLogState *state)
327343/* Set LSN and mark buffers dirty */
328344for (i = 0 ;i < MAX_GENERIC_XLOG_PAGES ;i ++ )
329345{
330- PageData * page = & state -> pages [i ];
346+ PageData * pageData = & state -> pages [i ];
331347
332- if (BufferIsInvalid (page -> buffer ))
348+ if (BufferIsInvalid (pageData -> buffer ))
333349continue ;
334- PageSetLSN (BufferGetPage (page -> buffer ,NULL ,NULL ,
350+ PageSetLSN (BufferGetPage (pageData -> buffer ,NULL ,NULL ,
335351BGP_NO_SNAPSHOT_TEST ),lsn );
336- MarkBufferDirty (page -> buffer );
352+ MarkBufferDirty (pageData -> buffer );
337353}
338354END_CRIT_SECTION ();
339355}
@@ -343,13 +359,15 @@ GenericXLogFinish(GenericXLogState *state)
343359START_CRIT_SECTION ();
344360for (i = 0 ;i < MAX_GENERIC_XLOG_PAGES ;i ++ )
345361{
346- PageData * page = & state -> pages [i ];
362+ PageData * pageData = & state -> pages [i ];
347363
348- if (BufferIsInvalid (page -> buffer ))
364+ if (BufferIsInvalid (pageData -> buffer ))
349365continue ;
350- memcpy (BufferGetPage (page -> buffer ,NULL ,NULL ,
351- BGP_NO_SNAPSHOT_TEST ),page -> image ,BLCKSZ );
352- MarkBufferDirty (page -> buffer );
366+ memcpy (BufferGetPage (pageData -> buffer ,NULL ,NULL ,
367+ BGP_NO_SNAPSHOT_TEST ),
368+ pageData -> image ,
369+ BLCKSZ );
370+ MarkBufferDirty (pageData -> buffer );
353371}
354372END_CRIT_SECTION ();
355373}
@@ -360,7 +378,9 @@ GenericXLogFinish(GenericXLogState *state)
360378}
361379
362380/*
363- * Abort generic xlog record.
381+ * Abort generic xlog record construction. No changes are applied to buffers.
382+ *
383+ * Note: caller is responsible for releasing locks/pins on buffers, if needed.
364384 */
365385void
366386GenericXLogAbort (GenericXLogState * state )
@@ -372,10 +392,10 @@ GenericXLogAbort(GenericXLogState *state)
372392 * Apply delta to given page image.
373393 */
374394static void
375- applyPageRedo (Page page ,Pointer data ,Size dataSize )
395+ applyPageRedo (Page page ,const char * delta ,Size deltaSize )
376396{
377- Pointer ptr = data ,
378- end = data + dataSize ;
397+ const char * ptr = delta ;
398+ const char * end = delta + deltaSize ;
379399
380400while (ptr < end )
381401{
@@ -399,10 +419,11 @@ applyPageRedo(Page page, Pointer data, Size dataSize)
399419void
400420generic_redo (XLogReaderState * record )
401421{
402- uint8 block_id ;
403- Buffer buffers [MAX_GENERIC_XLOG_PAGES ]= {InvalidBuffer };
404422XLogRecPtr lsn = record -> EndRecPtr ;
423+ Buffer buffers [MAX_GENERIC_XLOG_PAGES ];
424+ uint8 block_id ;
405425
426+ /* Protect limited size of buffers[] array */
406427Assert (record -> max_block_id < MAX_GENERIC_XLOG_PAGES );
407428
408429/* Iterate over blocks */
@@ -411,20 +432,24 @@ generic_redo(XLogReaderState *record)
411432XLogRedoAction action ;
412433
413434if (!XLogRecHasBlockRef (record ,block_id ))
435+ {
436+ buffers [block_id ]= InvalidBuffer ;
414437continue ;
438+ }
415439
416440action = XLogReadBufferForRedo (record ,block_id ,& buffers [block_id ]);
417441
418442/* Apply redo to given block if needed */
419443if (action == BLK_NEEDS_REDO )
420444{
421- Pointer blockData ;
422- Size blockDataSize ;
423445Page page ;
446+ char * blockDelta ;
447+ Size blockDeltaSize ;
424448
425- page = BufferGetPage (buffers [block_id ],NULL ,NULL ,BGP_NO_SNAPSHOT_TEST );
426- blockData = XLogRecGetBlockData (record ,block_id ,& blockDataSize );
427- applyPageRedo (page ,blockData ,blockDataSize );
449+ page = BufferGetPage (buffers [block_id ],NULL ,NULL ,
450+ BGP_NO_SNAPSHOT_TEST );
451+ blockDelta = XLogRecGetBlockData (record ,block_id ,& blockDeltaSize );
452+ applyPageRedo (page ,blockDelta ,blockDeltaSize );
428453
429454PageSetLSN (page ,lsn );
430455MarkBufferDirty (buffers [block_id ]);