Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5f08acc

Browse files
committed
Fix past pd_upper write in ginRedoRecompress()
ginRedoRecompress() replays actions over compressed segments of posting listin-place. However, it might lead to write past pg_upper, because intermediatestate during playing the changes can take more space than both original stateand final state. This commit fixes that by refuse from in-place modification.Instead page tail is copied once modification is started, and then it's usedas the source of original segments. Backpatch to 9.4 where posting listcompression was introduced.Reported-by: Sivasubramanian RamasubramanianDiscussion:https://postgr.es/m/1536091151804.6588%40amazon.comAuthor: Alexander Korotkov based on patch from and ideas by Sivasubramanian RamasubramanianReview: Sivasubramanian RamasubramanianBackpatch-through: 9.4
1 parentff47d4b commit5f08acc

File tree

1 file changed

+59
-21
lines changed

1 file changed

+59
-21
lines changed

‎src/backend/access/gin/ginxlog.c

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ ginRedoInsertEntry(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rda
135135
}
136136
}
137137

138+
/*
139+
* Redo recompression of posting list. Doing all the changes in-place is not
140+
* always possible, because it might require more space than we've on the page.
141+
* Instead, once modification is required we copy unprocessed tail of the page
142+
* into separately allocated chunk of memory for further reading original
143+
* versions of segments. Thanks to that we don't bother about moving page data
144+
* in-place.
145+
*/
138146
staticvoid
139147
ginRedoRecompress(Pagepage,ginxlogRecompressDataLeaf*data)
140148
{
@@ -144,6 +152,9 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
144152
Pointersegmentend;
145153
char*walbuf;
146154
inttotalsize;
155+
PointertailCopy=NULL;
156+
PointerwritePtr;
157+
Pointersegptr;
147158

148159
/*
149160
* If the page is in pre-9.4 format, convert to new format first.
@@ -183,6 +194,7 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
183194
}
184195

185196
oldseg=GinDataLeafPageGetPostingList(page);
197+
writePtr= (Pointer)oldseg;
186198
segmentend= (Pointer)oldseg+GinDataLeafPageGetPostingListSize(page);
187199
segno=0;
188200

@@ -200,8 +212,6 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
200212
ItemPointerData*newitems;
201213
intnnewitems;
202214
intsegsize;
203-
Pointersegptr;
204-
intszleft;
205215

206216
/* Extract all the information we need from the WAL record */
207217
if (a_action==GIN_SEGMENT_INSERT||
@@ -224,6 +234,17 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
224234
Assert(segno <=a_segno);
225235
while (segno<a_segno)
226236
{
237+
/*
238+
* Once modification is started and page tail is copied, we've
239+
* to copy unmodified segments.
240+
*/
241+
segsize=SizeOfGinPostingList(oldseg);
242+
if (tailCopy)
243+
{
244+
Assert(writePtr+segsize<PageGetSpecialPointer(page));
245+
memcpy(writePtr, (Pointer)oldseg,segsize);
246+
}
247+
writePtr+=segsize;
227248
oldseg=GinNextPostingListSegment(oldseg);
228249
segno++;
229250
}
@@ -264,36 +285,42 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
264285
Assert(a_action==GIN_SEGMENT_INSERT);
265286
segsize=0;
266287
}
267-
szleft=segmentend-segptr;
288+
289+
/*
290+
* We're about to start modification of the page. So, copy tail of the
291+
* page if it's not done already.
292+
*/
293+
if (!tailCopy&&segptr!=segmentend)
294+
{
295+
inttailSize=segmentend-segptr;
296+
297+
tailCopy= (Pointer)palloc(tailSize);
298+
memcpy(tailCopy,segptr,tailSize);
299+
segptr=tailCopy;
300+
oldseg= (GinPostingList*)segptr;
301+
segmentend=segptr+tailSize;
302+
}
268303

269304
switch (a_action)
270305
{
271306
caseGIN_SEGMENT_DELETE:
272-
memmove(segptr,segptr+segsize,szleft-segsize);
273-
segmentend-=segsize;
274-
307+
segptr+=segsize;
275308
segno++;
276309
break;
277310

278311
caseGIN_SEGMENT_INSERT:
279-
/* make room for the new segment */
280-
memmove(segptr+newsegsize,segptr,szleft);
281312
/* copy the new segment in place */
282-
memcpy(segptr,newseg,newsegsize);
283-
segmentend+=newsegsize;
284-
segptr+=newsegsize;
313+
Assert(writePtr+newsegsize <=PageGetSpecialPointer(page));
314+
memcpy(writePtr,newseg,newsegsize);
315+
writePtr+=newsegsize;
285316
break;
286317

287318
caseGIN_SEGMENT_REPLACE:
288-
/* shift the segments that follow */
289-
memmove(segptr+newsegsize,
290-
segptr+segsize,
291-
szleft-segsize);
292-
/* copy the replacement segment in place */
293-
memcpy(segptr,newseg,newsegsize);
294-
segmentend-=segsize;
295-
segmentend+=newsegsize;
296-
segptr+=newsegsize;
319+
/* copy the new version of segment in place */
320+
Assert(writePtr+newsegsize <=PageGetSpecialPointer(page));
321+
memcpy(writePtr,newseg,newsegsize);
322+
writePtr+=newsegsize;
323+
segptr+=segsize;
297324
segno++;
298325
break;
299326

@@ -303,7 +330,18 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
303330
oldseg= (GinPostingList*)segptr;
304331
}
305332

306-
totalsize=segmentend- (Pointer)GinDataLeafPageGetPostingList(page);
333+
/* Copy the rest of unmodified segments if any. */
334+
segptr= (Pointer)oldseg;
335+
if (segptr!=segmentend&&tailCopy)
336+
{
337+
intrestSize=segmentend-segptr;
338+
339+
Assert(writePtr+restSize <=PageGetSpecialPointer(page));
340+
memcpy(writePtr,segptr,restSize);
341+
writePtr+=restSize;
342+
}
343+
344+
totalsize=writePtr- (Pointer)GinDataLeafPageGetPostingList(page);
307345
GinDataPageSetDataSize(page,totalsize);
308346
}
309347

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp