Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit db03cf3

Browse files
committed
Code review/prettification for generic_xlog.c.
Improve commentary, use more specific names for the delta fields, const-ify pointer arguments where possible, avoid assuming that initializing only the first element of a local array will guarantee that the remaining elements end up as we need them. (I think that code in generic_redo actually worked, but only because InvalidBuffer is zero; this is a particularly ugly way of depending on that ...)
1 parent 2dd318d commit db03cf3

File tree

1 file changed

+92
-67
lines changed

1 file changed

+92
-67
lines changed

src/backend/access/transam/generic_xlog.c

+92-67
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@
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 region in 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, we break fragments only if
35-
* the unchanged region is bigger 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 region between 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, we merge adjacent fragments if 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
@@ -41,16 +41,16 @@
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 */
4747
typedef struct
4848
{
4949
Buffer 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 */
5350
bool 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

6363
static 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
*/
7175
static void
7276
writeFragment(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 */
8286
memcpy(ptr, &offset, sizeof(offset));
@@ -86,14 +90,14 @@ writeFragment(PageData *pageData, OffsetNumber offset, OffsetNumber length,
8690
memcpy(ptr, data, length);
8791
ptr += 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
*/
9599
static void
96-
writeDelta(PageData *pageData)
100+
computeDelta(PageData *pageData)
97101
{
98102
Page page = BufferGetPage(pageData->buffer, NULL, NULL,
99103
BGP_NO_SNAPSHOT_TEST),
@@ -106,6 +110,8 @@ writeDelta(PageData *pageData)
106110
imageLower = ((PageHeader) image)->pd_lower,
107111
imageUpper = ((PageHeader) image)->pd_upper;
108112

113+
pageData->deltaLen = 0;
114+
109115
for (i = 0; i < BLCKSZ; i++)
110116
{
111117
bool match;
@@ -181,22 +187,22 @@ writeDelta(PageData *pageData)
181187
char tmp[BLCKSZ];
182188

183189
memcpy(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)
187193
elog(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
*/
195201
GenericXLogState *
196202
GenericXLogStart(Relation relation)
197203
{
198-
int i;
199204
GenericXLogState *state;
205+
int i;
200206

201207
state = (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
*/
213224
Page
214225
GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
215226
{
216227
int block_id;
217228

218-
/* Place new buffer to unused slot in array */
229+
/* Search array for existing entry or first unused slot */
219230
for (block_id = 0; block_id < MAX_GENERIC_XLOG_PAGES; block_id++)
220231
{
221232
PageData *page = &state->pages[block_id];
222233

223234
if (BufferIsInvalid(page->buffer))
224235
{
236+
/* Empty slot, so use it (there cannot be a match later) */
225237
page->buffer = buffer;
226-
memcpy(page->image, BufferGetPage(buffer, NULL, NULL,
227-
BGP_NO_SNAPSHOT_TEST), BLCKSZ);
228-
page->dataLen = 0;
229238
page->fullImage = isNew;
239+
memcpy(page->image,
240+
BufferGetPage(buffer, NULL, NULL, BGP_NO_SNAPSHOT_TEST),
241+
BLCKSZ);
230242
return (Page) page->image;
231243
}
232244
else if (page->buffer == buffer)
@@ -239,15 +251,16 @@ GenericXLogRegister(GenericXLogState *state, Buffer buffer, bool isNew)
239251
}
240252
}
241253

242-
elog(ERROR, "maximum number of %d generic xlog buffers is exceeded",
254+
elog(ERROR, "maximum number %d of generic xlog buffers is exceeded",
243255
MAX_GENERIC_XLOG_PAGES);
244-
245256
/* keep compiler quiet */
246257
return NULL;
247258
}
248259

249260
/*
250261
* Unregister particular buffer for generic xlog record.
262+
*
263+
* XXX this is dangerous and should go away.
251264
*/
252265
void
253266
GenericXLogUnregister(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
*/
279293
XLogRecPtr
280294
GenericXLogFinish(GenericXLogState *state)
@@ -291,33 +305,35 @@ GenericXLogFinish(GenericXLogState *state)
291305

292306
for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
293307
{
308+
PageData *pageData = &state->pages[i];
309+
Page page;
294310
char tmp[BLCKSZ];
295-
PageData *page = &state->pages[i];
296311

297-
if (BufferIsInvalid(page->buffer))
312+
if (BufferIsInvalid(pageData->buffer))
298313
continue;
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
}
312328
else
313329
{
314330
/*
315-
* In normal mode, calculate delta and write it as data
331+
* In normal mode, calculate delta and write it as xlog 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 */
328344
for (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))
333349
continue;
334-
PageSetLSN(BufferGetPage(page->buffer, NULL, NULL,
350+
PageSetLSN(BufferGetPage(pageData->buffer, NULL, NULL,
335351
BGP_NO_SNAPSHOT_TEST), lsn);
336-
MarkBufferDirty(page->buffer);
352+
MarkBufferDirty(pageData->buffer);
337353
}
338354
END_CRIT_SECTION();
339355
}
@@ -343,13 +359,15 @@ GenericXLogFinish(GenericXLogState *state)
343359
START_CRIT_SECTION();
344360
for (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))
349365
continue;
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
}
354372
END_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
*/
365385
void
366386
GenericXLogAbort(GenericXLogState *state)
@@ -372,10 +392,10 @@ GenericXLogAbort(GenericXLogState *state)
372392
* Apply delta to given page image.
373393
*/
374394
static 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

380400
while (ptr < end)
381401
{
@@ -399,10 +419,11 @@ applyPageRedo(Page page, Pointer data, Size dataSize)
399419
void
400420
generic_redo(XLogReaderState *record)
401421
{
402-
uint8 block_id;
403-
Buffer buffers[MAX_GENERIC_XLOG_PAGES] = {InvalidBuffer};
404422
XLogRecPtr lsn = record->EndRecPtr;
423+
Buffer buffers[MAX_GENERIC_XLOG_PAGES];
424+
uint8 block_id;
405425

426+
/* Protect limited size of buffers[] array */
406427
Assert(record->max_block_id < MAX_GENERIC_XLOG_PAGES);
407428

408429
/* Iterate over blocks */
@@ -411,20 +432,24 @@ generic_redo(XLogReaderState *record)
411432
XLogRedoAction action;
412433

413434
if (!XLogRecHasBlockRef(record, block_id))
435+
{
436+
buffers[block_id] = InvalidBuffer;
414437
continue;
438+
}
415439

416440
action = XLogReadBufferForRedo(record, block_id, &buffers[block_id]);
417441

418442
/* Apply redo to given block if needed */
419443
if (action == BLK_NEEDS_REDO)
420444
{
421-
Pointer blockData;
422-
Size blockDataSize;
423445
Page 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

429454
PageSetLSN(page, lsn);
430455
MarkBufferDirty(buffers[block_id]);

0 commit comments

Comments
 (0)