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

Lines changed: 92 additions & 67 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy