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

Commite16954f

Browse files
committed
Try again to make the visibility map crash safe.
My previous attempt was quite a bit less than half-baked with respect toheap_update().
1 parent66a36ef commite16954f

File tree

3 files changed

+100
-44
lines changed

3 files changed

+100
-44
lines changed

‎src/backend/access/heap/heapam.c

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1941,7 +1941,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
19411941
*/
19421942
buffer=RelationGetBufferForTuple(relation,heaptup->t_len,
19431943
InvalidBuffer,options,bistate,
1944-
&vmbuffer);
1944+
&vmbuffer,NULL);
19451945

19461946
/*
19471947
* We're about to do the actual insert -- check for conflict at the
@@ -2519,19 +2519,6 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
25192519

25202520
LockBuffer(buffer,BUFFER_LOCK_EXCLUSIVE);
25212521

2522-
/*
2523-
* If we didn't pin the visibility map page and the page has become all
2524-
* visible while we were busy locking the buffer, we'll have to unlock and
2525-
* re-lock, to avoid holding the buffer lock across an I/O. That's a bit
2526-
* unfortunate, but hopefully shouldn't happen often.
2527-
*/
2528-
if (vmbuffer==InvalidBuffer&&PageIsAllVisible(page))
2529-
{
2530-
LockBuffer(buffer,BUFFER_LOCK_UNLOCK);
2531-
visibilitymap_pin(relation,block,&vmbuffer);
2532-
LockBuffer(buffer,BUFFER_LOCK_EXCLUSIVE);
2533-
}
2534-
25352522
lp=PageGetItemId(page,ItemPointerGetOffsetNumber(otid));
25362523
Assert(ItemIdIsNormal(lp));
25372524

@@ -2667,6 +2654,20 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
26672654
returnresult;
26682655
}
26692656

2657+
/*
2658+
* If we didn't pin the visibility map page and the page has become all
2659+
* visible while we were busy locking the buffer, or during some subsequent
2660+
* window during which we had it unlocked, we'll have to unlock and
2661+
* re-lock, to avoid holding the buffer lock across an I/O. That's a bit
2662+
* unfortunate, but hopefully shouldn't happen often.
2663+
*/
2664+
if (vmbuffer==InvalidBuffer&&PageIsAllVisible(page))
2665+
{
2666+
LockBuffer(buffer,BUFFER_LOCK_UNLOCK);
2667+
visibilitymap_pin(relation,block,&vmbuffer);
2668+
LockBuffer(buffer,BUFFER_LOCK_EXCLUSIVE);
2669+
}
2670+
26702671
/*
26712672
* We're about to do the actual update -- check for conflict first, to
26722673
* avoid possibly having to roll back work we've just done.
@@ -2784,7 +2785,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
27842785
/* Assume there's no chance to put heaptup on same page. */
27852786
newbuf=RelationGetBufferForTuple(relation,heaptup->t_len,
27862787
buffer,0,NULL,
2787-
&vmbuffer_new);
2788+
&vmbuffer_new,&vmbuffer);
27882789
}
27892790
else
27902791
{
@@ -2802,7 +2803,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
28022803
LockBuffer(buffer,BUFFER_LOCK_UNLOCK);
28032804
newbuf=RelationGetBufferForTuple(relation,heaptup->t_len,
28042805
buffer,0,NULL,
2805-
&vmbuffer_new);
2806+
&vmbuffer_new,&vmbuffer);
28062807
}
28072808
else
28082809
{
@@ -2908,11 +2909,15 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
29082909
{
29092910
all_visible_cleared= true;
29102911
PageClearAllVisible(BufferGetPage(buffer));
2912+
visibilitymap_clear(relation,BufferGetBlockNumber(buffer),
2913+
vmbuffer);
29112914
}
29122915
if (newbuf!=buffer&&PageIsAllVisible(BufferGetPage(newbuf)))
29132916
{
29142917
all_visible_cleared_new= true;
29152918
PageClearAllVisible(BufferGetPage(newbuf));
2919+
visibilitymap_clear(relation,BufferGetBlockNumber(newbuf),
2920+
vmbuffer_new);
29162921
}
29172922

29182923
if (newbuf!=buffer)
@@ -2949,14 +2954,6 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
29492954
*/
29502955
CacheInvalidateHeapTuple(relation,&oldtup);
29512956

2952-
/* Clear bits in visibility map */
2953-
if (all_visible_cleared)
2954-
visibilitymap_clear(relation,BufferGetBlockNumber(buffer),
2955-
vmbuffer);
2956-
if (all_visible_cleared_new)
2957-
visibilitymap_clear(relation,BufferGetBlockNumber(newbuf),
2958-
vmbuffer_new);
2959-
29602957
/* Now we can release the buffer(s) */
29612958
if (newbuf!=buffer)
29622959
ReleaseBuffer(newbuf);

‎src/backend/access/heap/hio.c

Lines changed: 78 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,64 @@ ReadBufferBI(Relation relation, BlockNumber targetBlock,
9696
returnbuffer;
9797
}
9898

99+
/*
100+
* For each heap page which is all-visible, acquire a pin on the appropriate
101+
* visibility map page, if we haven't already got one.
102+
*
103+
* buffer2 may be InvalidBuffer, if only one buffer is involved. buffer1
104+
* must not be InvalidBuffer. If both buffers are specified, buffer1 must
105+
* be less than buffer2.
106+
*/
107+
staticvoid
108+
GetVisibilityMapPins(Relationrelation,Bufferbuffer1,Bufferbuffer2,
109+
BlockNumberblock1,BlockNumberblock2,
110+
Buffer*vmbuffer1,Buffer*vmbuffer2)
111+
{
112+
boolneed_to_pin_buffer1;
113+
boolneed_to_pin_buffer2;
114+
115+
Assert(BufferIsValid(buffer1));
116+
Assert(buffer2==InvalidBuffer||buffer1 <=buffer2);
117+
118+
while (1)
119+
{
120+
/* Figure out which pins we need but don't have. */
121+
need_to_pin_buffer1=PageIsAllVisible(BufferGetPage(buffer1))
122+
&& !visibilitymap_pin_ok(block1,*vmbuffer1);
123+
need_to_pin_buffer2=buffer2!=InvalidBuffer
124+
&&PageIsAllVisible(BufferGetPage(buffer2))
125+
&& !visibilitymap_pin_ok(block2,*vmbuffer2);
126+
if (!need_to_pin_buffer1&& !need_to_pin_buffer2)
127+
return;
128+
129+
/* We must unlock both buffers before doing any I/O. */
130+
LockBuffer(buffer1,BUFFER_LOCK_UNLOCK);
131+
if (buffer2!=InvalidBuffer&&buffer2!=buffer1)
132+
LockBuffer(buffer2,BUFFER_LOCK_UNLOCK);
133+
134+
/* Get pins. */
135+
if (need_to_pin_buffer1)
136+
visibilitymap_pin(relation,block1,vmbuffer1);
137+
if (need_to_pin_buffer2)
138+
visibilitymap_pin(relation,block2,vmbuffer2);
139+
140+
/* Relock buffers. */
141+
LockBuffer(buffer1,BUFFER_LOCK_EXCLUSIVE);
142+
if (buffer2!=InvalidBuffer&&buffer2!=buffer1)
143+
LockBuffer(buffer2,BUFFER_LOCK_EXCLUSIVE);
144+
145+
/*
146+
* If there are two buffers involved and we pinned just one of them,
147+
* it's possible that the second one became all-visible while we were
148+
* busy pinning the first one. If it looks like that's a possible
149+
* scenario, we'll need to make a second pass through this loop.
150+
*/
151+
if (buffer2==InvalidBuffer||buffer1==buffer2
152+
|| (need_to_pin_buffer1&&need_to_pin_buffer2))
153+
break;
154+
}
155+
}
156+
99157
/*
100158
* RelationGetBufferForTuple
101159
*
@@ -152,7 +210,7 @@ Buffer
152210
RelationGetBufferForTuple(Relationrelation,Sizelen,
153211
BufferotherBuffer,intoptions,
154212
structBulkInsertStateData*bistate,
155-
Buffer*vmbuffer)
213+
Buffer*vmbuffer,Buffer*vmbuffer_other)
156214
{
157215
booluse_fsm= !(options&HEAP_INSERT_SKIP_FSM);
158216
Bufferbuffer=InvalidBuffer;
@@ -284,11 +342,17 @@ RelationGetBufferForTuple(Relation relation, Size len,
284342
}
285343

286344
/*
287-
* If the page is all visible but we don't have the right visibility
288-
* map page pinned, then give up our locks, go get the pin, and
289-
* re-lock. This is pretty painful, but hopefully shouldn't happen
290-
* often. Note that there's a small possibility that we didn't pin
291-
* the page above but still have the correct page pinned anyway, either
345+
* We now have the target page (and the other buffer, if any) pinned
346+
* and locked. However, since our initial PageIsAllVisible checks
347+
* were performed before acquiring the lock, the results might now
348+
* be out of date, either for the selected victim buffer, or for the
349+
* other buffer passed by the caller. In that case, we'll need to give
350+
* up our locks, go get the pin(s) we failed to get earlier, and
351+
* re-lock. That's pretty painful, but hopefully shouldn't happen
352+
* often.
353+
*
354+
* Note that there's a small possibility that we didn't pin the
355+
* page above but still have the correct page pinned anyway, either
292356
* because we've already made a previous pass through this loop, or
293357
* because caller passed us the right page anyway.
294358
*
@@ -297,19 +361,14 @@ RelationGetBufferForTuple(Relation relation, Size len,
297361
* cleared by some other backend anyway. In that case, we'll have done
298362
* a bit of extra work for no gain, but there's no real harm done.
299363
*/
300-
if (PageIsAllVisible(BufferGetPage(buffer))
301-
&& !visibilitymap_pin_ok(targetBlock,*vmbuffer))
302-
{
303-
LockBuffer(buffer,BUFFER_LOCK_UNLOCK);
304-
if (otherBlock!=targetBlock)
305-
LockBuffer(otherBuffer,BUFFER_LOCK_UNLOCK);
306-
visibilitymap_pin(relation,targetBlock,vmbuffer);
307-
if (otherBuffer!=InvalidBuffer&&otherBlock<targetBlock)
308-
LockBuffer(otherBuffer,BUFFER_LOCK_EXCLUSIVE);
309-
LockBuffer(buffer,BUFFER_LOCK_EXCLUSIVE);
310-
if (otherBuffer!=InvalidBuffer&&otherBlock>targetBlock)
311-
LockBuffer(otherBuffer,BUFFER_LOCK_EXCLUSIVE);
312-
}
364+
if (otherBuffer==InvalidBuffer||buffer <=otherBuffer)
365+
GetVisibilityMapPins(relation,buffer,otherBuffer,
366+
targetBlock,otherBlock,vmbuffer,
367+
vmbuffer_other);
368+
else
369+
GetVisibilityMapPins(relation,otherBuffer,buffer,
370+
otherBlock,targetBlock,vmbuffer_other,
371+
vmbuffer);
313372

314373
/*
315374
* Now we can check to see if there's enough free space here. If so,

‎src/include/access/hio.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@ extern void RelationPutHeapTuple(Relation relation, Buffer buffer,
3939
externBufferRelationGetBufferForTuple(Relationrelation,Sizelen,
4040
BufferotherBuffer,intoptions,
4141
structBulkInsertStateData*bistate,
42-
Buffer*vmbuffer);
42+
Buffer*vmbuffer,Buffer*vmbuffer_other);
4343

4444
#endif/* HIO_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp