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

Commitf9e66f2

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 parent82ebf39 commitf9e66f2

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
@@ -133,6 +133,14 @@ ginRedoInsertEntry(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rda
133133
}
134134
}
135135

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

146157
/*
147158
* If the page is in pre-9.4 format, convert to new format first.
@@ -181,6 +192,7 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
181192
}
182193

183194
oldseg=GinDataLeafPageGetPostingList(page);
195+
writePtr= (Pointer)oldseg;
184196
segmentend= (Pointer)oldseg+GinDataLeafPageGetPostingListSize(page);
185197
segno=0;
186198

@@ -198,8 +210,6 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
198210
ItemPointerData*newitems;
199211
intnnewitems;
200212
intsegsize;
201-
Pointersegptr;
202-
intszleft;
203213

204214
/* Extract all the information we need from the WAL record */
205215
if (a_action==GIN_SEGMENT_INSERT||
@@ -222,6 +232,17 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
222232
Assert(segno <=a_segno);
223233
while (segno<a_segno)
224234
{
235+
/*
236+
* Once modification is started and page tail is copied, we've
237+
* to copy unmodified segments.
238+
*/
239+
segsize=SizeOfGinPostingList(oldseg);
240+
if (tailCopy)
241+
{
242+
Assert(writePtr+segsize<PageGetSpecialPointer(page));
243+
memcpy(writePtr, (Pointer)oldseg,segsize);
244+
}
245+
writePtr+=segsize;
225246
oldseg=GinNextPostingListSegment(oldseg);
226247
segno++;
227248
}
@@ -262,36 +283,42 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
262283
Assert(a_action==GIN_SEGMENT_INSERT);
263284
segsize=0;
264285
}
265-
szleft=segmentend-segptr;
286+
287+
/*
288+
* We're about to start modification of the page. So, copy tail of the
289+
* page if it's not done already.
290+
*/
291+
if (!tailCopy&&segptr!=segmentend)
292+
{
293+
inttailSize=segmentend-segptr;
294+
295+
tailCopy= (Pointer)palloc(tailSize);
296+
memcpy(tailCopy,segptr,tailSize);
297+
segptr=tailCopy;
298+
oldseg= (GinPostingList*)segptr;
299+
segmentend=segptr+tailSize;
300+
}
266301

267302
switch (a_action)
268303
{
269304
caseGIN_SEGMENT_DELETE:
270-
memmove(segptr,segptr+segsize,szleft-segsize);
271-
segmentend-=segsize;
272-
305+
segptr+=segsize;
273306
segno++;
274307
break;
275308

276309
caseGIN_SEGMENT_INSERT:
277-
/* make room for the new segment */
278-
memmove(segptr+newsegsize,segptr,szleft);
279310
/* copy the new segment in place */
280-
memcpy(segptr,newseg,newsegsize);
281-
segmentend+=newsegsize;
282-
segptr+=newsegsize;
311+
Assert(writePtr+newsegsize <=PageGetSpecialPointer(page));
312+
memcpy(writePtr,newseg,newsegsize);
313+
writePtr+=newsegsize;
283314
break;
284315

285316
caseGIN_SEGMENT_REPLACE:
286-
/* shift the segments that follow */
287-
memmove(segptr+newsegsize,
288-
segptr+segsize,
289-
szleft-segsize);
290-
/* copy the replacement segment in place */
291-
memcpy(segptr,newseg,newsegsize);
292-
segmentend-=segsize;
293-
segmentend+=newsegsize;
294-
segptr+=newsegsize;
317+
/* copy the new version of segment in place */
318+
Assert(writePtr+newsegsize <=PageGetSpecialPointer(page));
319+
memcpy(writePtr,newseg,newsegsize);
320+
writePtr+=newsegsize;
321+
segptr+=segsize;
295322
segno++;
296323
break;
297324

@@ -301,7 +328,18 @@ ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
301328
oldseg= (GinPostingList*)segptr;
302329
}
303330

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp