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

Commitfcb7c14

Browse files
committed
Repair subtle VACUUM bug that led to 'HEAP_MOVED_IN was not expected'
errors. VACUUM normally compacts the table back-to-front, and stopsas soon as it gets to a page that it has moved some tuples onto.(This logic doesn't make for a complete packing of the table, but itshould be pretty close.) But the way it was checking whether it hadgot to a page with some moved-in tuples was to look at whether thecurrent page was the same as the last page of the list of pages thathave enough free space to be move-in targets. And there was othercode that would remove pages from that list once they got full.There was a kluge that prevented the last list entry from beingremoved, but it didn't get the job done. Fixed by keeping a separatevariable that contains the largest block number into which a tuplehas been moved. There's no longer any need to protect the last elementof the fraged_pages list.Also, fix NOTICE messages to describe elapsed user/system CPU timecorrectly.
1 parentb86ca72 commitfcb7c14

File tree

1 file changed

+110
-76
lines changed

1 file changed

+110
-76
lines changed

‎src/backend/commands/vacuum.c

Lines changed: 110 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.133 1999/12/29 10:13:20 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.134 2000/01/10 04:09:50 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -95,6 +95,8 @@ static intvc_cmp_blk(const void *left, const void *right);
9595
staticintvc_cmp_offno(constvoid*left,constvoid*right);
9696
staticintvc_cmp_vtlinks(constvoid*left,constvoid*right);
9797
staticboolvc_enough_space(VPageDescrvpd,Sizelen);
98+
staticchar*vc_show_rusage(structrusage*ru0);
99+
98100

99101
void
100102
vacuum(char*vacrel,boolverbose,boolanalyze,List*va_spec)
@@ -637,12 +639,11 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
637639
Sizemin_tlen=MaxTupleSize;
638640
Sizemax_tlen=0;
639641
int32i;
640-
structrusageru0,
641-
ru1;
642642
booldo_shrinking= true;
643643
VTupleLinkvtlinks= (VTupleLink)palloc(100*sizeof(VTupleLinkData));
644644
intnum_vtlinks=0;
645645
intfree_vtlinks=100;
646+
structrusageru0;
646647

647648
getrusage(RUSAGE_SELF,&ru0);
648649

@@ -987,25 +988,21 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
987988
pfree(vtlinks);
988989
}
989990

990-
getrusage(RUSAGE_SELF,&ru1);
991-
992991
elog(MESSAGE_LEVEL,"Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
993992
Tup %u: Vac %u, Keep/VTL %u/%u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; \
994-
Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. \
995-
Elapsed %u/%u sec.",
993+
Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. %s",
996994
nblocks,changed_pages,vacuum_pages->vpl_num_pages,empty_pages,
997995
new_pages,num_tuples,tups_vacuumed,
998996
nkeep,vacrelstats->num_vtlinks,ncrash,
999997
nunused,min_tlen,max_tlen,free_size,usable_free_size,
1000998
empty_end_pages,fraged_pages->vpl_num_pages,
1001-
ru1.ru_stime.tv_sec-ru0.ru_stime.tv_sec,
1002-
ru1.ru_utime.tv_sec-ru0.ru_utime.tv_sec);
999+
vc_show_rusage(&ru0));
10031000

10041001
}/* vc_scanheap */
10051002

10061003

10071004
/*
1008-
*vc_rpfheap() -- try torepaire relation' fragmentation
1005+
*vc_rpfheap() -- try torepair relation's fragmentation
10091006
*
10101007
*This routine marks dead tuples as unused and tries re-use dead space
10111008
*by moving tuples (and inserting indices if needed). It constructs
@@ -1016,7 +1013,8 @@ Elapsed %u/%u sec.",
10161013
*/
10171014
staticvoid
10181015
vc_rpfheap(VRelStats*vacrelstats,Relationonerel,
1019-
VPageListvacuum_pages,VPageListfraged_pages,intnindices,Relation*Irel)
1016+
VPageListvacuum_pages,VPageListfraged_pages,
1017+
intnindices,Relation*Irel)
10201018
{
10211019
TransactionIdmyXID;
10221020
CommandIdmyCID;
@@ -1040,14 +1038,13 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
10401038
InsertIndexResultiresult;
10411039
VPageListDataNvpl;
10421040
VPageDescrcur_page=NULL,
1043-
last_fraged_page,
10441041
last_vacuum_page,
10451042
vpc,
10461043
*vpp;
10471044
intcur_item=0;
10481045
IndDesc*Idesc,
10491046
*idcur;
1050-
intlast_fraged_block,
1047+
intlast_move_dest_block=-1,
10511048
last_vacuum_block,
10521049
i=0;
10531050
Sizetuple_len;
@@ -1060,8 +1057,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
10601057
boolisempty,
10611058
dowrite,
10621059
chain_tuple_moved;
1063-
structrusageru0,
1064-
ru1;
1060+
structrusageru0;
10651061

10661062
getrusage(RUSAGE_SELF,&ru0);
10671063

@@ -1078,26 +1074,32 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
10781074

10791075
Nvpl.vpl_num_pages=0;
10801076
num_fraged_pages=fraged_pages->vpl_num_pages;
1081-
last_fraged_page=fraged_pages->vpl_pagedesc[num_fraged_pages-1];
1082-
last_fraged_block=last_fraged_page->vpd_blkno;
10831077
Assert(vacuum_pages->vpl_num_pages>vacuum_pages->vpl_empty_end_pages);
10841078
vacuumed_pages=vacuum_pages->vpl_num_pages-vacuum_pages->vpl_empty_end_pages;
10851079
last_vacuum_page=vacuum_pages->vpl_pagedesc[vacuumed_pages-1];
10861080
last_vacuum_block=last_vacuum_page->vpd_blkno;
1087-
Assert(last_vacuum_block >=last_fraged_block);
10881081
cur_buffer=InvalidBuffer;
10891082
num_moved=0;
10901083

10911084
vpc= (VPageDescr)palloc(sizeof(VPageDescrData)+MaxOffsetNumber*sizeof(OffsetNumber));
10921085
vpc->vpd_offsets_used=vpc->vpd_offsets_free=0;
10931086

1087+
/*
1088+
* Scan pages backwards from the last nonempty page, trying to move
1089+
* tuples down to lower pages. Quit when we reach a page that we
1090+
* have moved any tuples onto. Note that if a page is still in the
1091+
* fraged_pages list (list of candidate move-target pages) when we
1092+
* reach it, we will remove it from the list. This ensures we never
1093+
* move a tuple up to a higher page number.
1094+
*
1095+
* NB: this code depends on the vacuum_pages and fraged_pages lists
1096+
* being in order, and on fraged_pages being a subset of vacuum_pages.
1097+
*/
10941098
nblocks=vacrelstats->num_pages;
1095-
for (blkno=nblocks-vacuum_pages->vpl_empty_end_pages-1;;blkno--)
1099+
for (blkno=nblocks-vacuum_pages->vpl_empty_end_pages-1;
1100+
blkno>last_move_dest_block;
1101+
blkno--)
10961102
{
1097-
/* if it's reapped page and it was used by me - quit */
1098-
if (blkno==last_fraged_block&&last_fraged_page->vpd_offsets_used>0)
1099-
break;
1100-
11011103
buf=ReadBuffer(onerel,blkno);
11021104
page=BufferGetPage(buf);
11031105

@@ -1117,21 +1119,24 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
11171119
else
11181120
Assert(isempty);
11191121
--vacuumed_pages;
1120-
Assert(vacuumed_pages>0);
1121-
/* get prev reapped page from vacuum_pages */
1122-
last_vacuum_page=vacuum_pages->vpl_pagedesc[vacuumed_pages-1];
1123-
last_vacuum_block=last_vacuum_page->vpd_blkno;
1124-
if (blkno==last_fraged_block)/* this page in
1125-
* fraged_pages too */
1122+
if (vacuumed_pages>0)
1123+
{
1124+
/* get prev reapped page from vacuum_pages */
1125+
last_vacuum_page=vacuum_pages->vpl_pagedesc[vacuumed_pages-1];
1126+
last_vacuum_block=last_vacuum_page->vpd_blkno;
1127+
}
1128+
else
11261129
{
1130+
last_vacuum_page=NULL;
1131+
last_vacuum_block=-1;
1132+
}
1133+
if (num_fraged_pages>0&&
1134+
blkno==
1135+
fraged_pages->vpl_pagedesc[num_fraged_pages-1]->vpd_blkno)
1136+
{
1137+
/* page is in fraged_pages too; remove it */
11271138
--num_fraged_pages;
1128-
Assert(num_fraged_pages>0);
1129-
Assert(last_fraged_page->vpd_offsets_used==0);
1130-
/* get prev reapped page from fraged_pages */
1131-
last_fraged_page=fraged_pages->vpl_pagedesc[num_fraged_pages-1];
1132-
last_fraged_block=last_fraged_page->vpd_blkno;
11331139
}
1134-
Assert(last_fraged_block <=last_vacuum_block);
11351140
if (isempty)
11361141
{
11371142
ReleaseBuffer(buf);
@@ -1217,10 +1222,10 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
12171222
HeapTupleDatatp=tuple;
12181223
Sizetlen=tuple_len;
12191224
VTupleMovevtmove= (VTupleMove)
1220-
palloc(100*sizeof(VTupleMoveData));
1225+
palloc(100*sizeof(VTupleMoveData));
12211226
intnum_vtmove=0;
12221227
intfree_vtmove=100;
1223-
VPageDescrto_vpd=fraged_pages->vpl_pagedesc[0];
1228+
VPageDescrto_vpd=NULL;
12241229
intto_item=0;
12251230
boolfreeCbuf= false;
12261231
intti;
@@ -1276,17 +1281,20 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
12761281
/* first, can chain be moved ? */
12771282
for (;;)
12781283
{
1279-
if (!vc_enough_space(to_vpd,tlen))
1284+
if (to_vpd==NULL||
1285+
!vc_enough_space(to_vpd,tlen))
12801286
{
1281-
if (to_vpd!=last_fraged_page&&
1282-
!vc_enough_space(to_vpd,vacrelstats->min_tlen))
1287+
/* if to_vpd no longer has enough free space to be
1288+
* useful, remove it from fraged_pages list
1289+
*/
1290+
if (to_vpd!=NULL&&
1291+
!vc_enough_space(to_vpd,vacrelstats->min_tlen))
12831292
{
1284-
Assert(num_fraged_pages>to_item+1);
1293+
Assert(num_fraged_pages>to_item);
12851294
memmove(fraged_pages->vpl_pagedesc+to_item,
1286-
fraged_pages->vpl_pagedesc+to_item+1,
1287-
sizeof(VPageDescr*)* (num_fraged_pages-to_item-1));
1295+
fraged_pages->vpl_pagedesc+to_item+1,
1296+
sizeof(VPageDescr)* (num_fraged_pages-to_item-1));
12881297
num_fraged_pages--;
1289-
Assert(last_fraged_page==fraged_pages->vpl_pagedesc[num_fraged_pages-1]);
12901298
}
12911299
for (i=0;i<num_fraged_pages;i++)
12921300
{
@@ -1477,6 +1485,8 @@ moving chain: failed to add item with len = %u to page %u",
14771485
newtup.t_datamcxt=NULL;
14781486
newtup.t_data= (HeapTupleHeader)PageGetItem(ToPage,newitemid);
14791487
ItemPointerSet(&(newtup.t_self),vtmove[ti].vpd->vpd_blkno,newoff);
1488+
if (((int)vtmove[ti].vpd->vpd_blkno)>last_move_dest_block)
1489+
last_move_dest_block=vtmove[ti].vpd->vpd_blkno;
14801490

14811491
/*
14821492
* Set t_ctid pointing to itself for last tuple in
@@ -1545,23 +1555,17 @@ moving chain: failed to add item with len = %u to page %u",
15451555
{
15461556
WriteBuffer(cur_buffer);
15471557
cur_buffer=InvalidBuffer;
1548-
15491558
/*
1550-
* If no one tuple can't be added to this page -
1551-
* remove page from fraged_pages. - vadim 11/27/96
1552-
*
1553-
* But we can't remove last page - this is our
1554-
* "show-stopper" !!!- vadim 02/25/98
1559+
* If previous target page is now too full to add
1560+
* *any* tuple to it, remove it from fraged_pages.
15551561
*/
1556-
if (cur_page!=last_fraged_page&&
1557-
!vc_enough_space(cur_page,vacrelstats->min_tlen))
1562+
if (!vc_enough_space(cur_page,vacrelstats->min_tlen))
15581563
{
1559-
Assert(num_fraged_pages>cur_item+1);
1564+
Assert(num_fraged_pages>cur_item);
15601565
memmove(fraged_pages->vpl_pagedesc+cur_item,
15611566
fraged_pages->vpl_pagedesc+cur_item+1,
1562-
sizeof(VPageDescr*)* (num_fraged_pages-cur_item-1));
1567+
sizeof(VPageDescr)* (num_fraged_pages-cur_item-1));
15631568
num_fraged_pages--;
1564-
Assert(last_fraged_page==fraged_pages->vpl_pagedesc[num_fraged_pages-1]);
15651569
}
15661570
}
15671571
for (i=0;i<num_fraged_pages;i++)
@@ -1623,6 +1627,9 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
16231627
cur_page->vpd_offsets_used++;
16241628
num_moved++;
16251629
cur_page->vpd_free= ((PageHeader)ToPage)->pd_upper- ((PageHeader)ToPage)->pd_lower;
1630+
if (((int)cur_page->vpd_blkno)>last_move_dest_block)
1631+
last_move_dest_block=cur_page->vpd_blkno;
1632+
16261633
vpc->vpd_offsets[vpc->vpd_offsets_free++]=offnum;
16271634

16281635
/* insert index' tuples if needed */
@@ -1789,14 +1796,10 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
17891796
}
17901797
Assert(num_moved==checked_moved);
17911798

1792-
getrusage(RUSAGE_SELF,&ru1);
1793-
1794-
elog(MESSAGE_LEVEL,"Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. \
1795-
Elapsed %u/%u sec.",
1799+
elog(MESSAGE_LEVEL,"Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. %s",
17961800
RelationGetRelationName(onerel),
17971801
nblocks,blkno,num_moved,
1798-
ru1.ru_stime.tv_sec-ru0.ru_stime.tv_sec,
1799-
ru1.ru_utime.tv_sec-ru0.ru_utime.tv_sec);
1802+
vc_show_rusage(&ru0));
18001803

18011804
if (Nvpl.vpl_num_pages>0)
18021805
{
@@ -1950,14 +1953,17 @@ vc_vacheap(VRelStats *vacrelstats, Relation onerel, VPageList vacuum_pages)
19501953

19511954
/*
19521955
*vc_vacpage() -- free dead tuples on a page
1953-
* andrepaire its fragmentation.
1956+
* andrepair its fragmentation.
19541957
*/
19551958
staticvoid
19561959
vc_vacpage(Pagepage,VPageDescrvpd)
19571960
{
19581961
ItemIditemid;
19591962
inti;
19601963

1964+
/* There shouldn't be any tuples moved onto the page yet! */
1965+
Assert(vpd->vpd_offsets_used==0);
1966+
19611967
for (i=0;i<vpd->vpd_offsets_free;i++)
19621968
{
19631969
itemid=&(((PageHeader)page)->pd_linp[vpd->vpd_offsets[i]-1]);
@@ -1978,8 +1984,7 @@ vc_scanoneind(Relation indrel, int num_tuples)
19781984
IndexScanDesciscan;
19791985
intnitups;
19801986
intnipages;
1981-
structrusageru0,
1982-
ru1;
1987+
structrusageru0;
19831988

19841989
getrusage(RUSAGE_SELF,&ru0);
19851990

@@ -2000,12 +2005,9 @@ vc_scanoneind(Relation indrel, int num_tuples)
20002005
nipages=RelationGetNumberOfBlocks(indrel);
20012006
vc_updstats(RelationGetRelid(indrel),nipages,nitups, false,NULL);
20022007

2003-
getrusage(RUSAGE_SELF,&ru1);
2004-
2005-
elog(MESSAGE_LEVEL,"Index %s: Pages %u; Tuples %u. Elapsed %u/%u sec.",
2008+
elog(MESSAGE_LEVEL,"Index %s: Pages %u; Tuples %u. %s",
20062009
RelationGetRelationName(indrel),nipages,nitups,
2007-
ru1.ru_stime.tv_sec-ru0.ru_stime.tv_sec,
2008-
ru1.ru_utime.tv_sec-ru0.ru_utime.tv_sec);
2010+
vc_show_rusage(&ru0));
20092011

20102012
if (nitups!=num_tuples)
20112013
elog(NOTICE,"Index %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u).\
@@ -2036,8 +2038,7 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
20362038
intnum_index_tuples;
20372039
intnum_pages;
20382040
VPageDescrvp;
2039-
structrusageru0,
2040-
ru1;
2041+
structrusageru0;
20412042

20422043
getrusage(RUSAGE_SELF,&ru0);
20432044

@@ -2081,13 +2082,10 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
20812082
num_pages=RelationGetNumberOfBlocks(indrel);
20822083
vc_updstats(RelationGetRelid(indrel),num_pages,num_index_tuples, false,NULL);
20832084

2084-
getrusage(RUSAGE_SELF,&ru1);
2085-
2086-
elog(MESSAGE_LEVEL,"Index %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
2085+
elog(MESSAGE_LEVEL,"Index %s: Pages %u; Tuples %u: Deleted %u. %s",
20872086
RelationGetRelationName(indrel),num_pages,
20882087
num_index_tuples-keep_tuples,tups_vacuumed,
2089-
ru1.ru_stime.tv_sec-ru0.ru_stime.tv_sec,
2090-
ru1.ru_utime.tv_sec-ru0.ru_utime.tv_sec);
2088+
vc_show_rusage(&ru0));
20912089

20922090
if (num_index_tuples!=num_tuples+keep_tuples)
20932091
elog(NOTICE,"Index %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u).\
@@ -2905,3 +2903,39 @@ vc_enough_space(VPageDescr vpd, Size len)
29052903
return false;
29062904

29072905
}/* vc_enough_space */
2906+
2907+
2908+
/*
2909+
* Compute elapsed time since ru0 usage snapshot, and format into
2910+
* a displayable string. Result is in a static string, which is
2911+
* tacky, but no one ever claimed that the Postgres backend is
2912+
* threadable...
2913+
*/
2914+
staticchar*
2915+
vc_show_rusage(structrusage*ru0)
2916+
{
2917+
staticcharresult[64];
2918+
structrusageru1;
2919+
2920+
getrusage(RUSAGE_SELF,&ru1);
2921+
2922+
if (ru1.ru_stime.tv_usec<ru0->ru_stime.tv_usec)
2923+
{
2924+
ru1.ru_stime.tv_sec--;
2925+
ru1.ru_stime.tv_usec+=1000000;
2926+
}
2927+
if (ru1.ru_utime.tv_usec<ru0->ru_utime.tv_usec)
2928+
{
2929+
ru1.ru_utime.tv_sec--;
2930+
ru1.ru_utime.tv_usec+=1000000;
2931+
}
2932+
2933+
snprintf(result,sizeof(result),
2934+
"CPU %d.%02ds/%d.%02du sec.",
2935+
(int) (ru1.ru_stime.tv_sec-ru0->ru_stime.tv_sec),
2936+
(int) (ru1.ru_stime.tv_usec-ru0->ru_stime.tv_usec) /10000,
2937+
(int) (ru1.ru_utime.tv_sec-ru0->ru_utime.tv_sec),
2938+
(int) (ru1.ru_utime.tv_usec-ru0->ru_utime.tv_usec) /10000);
2939+
2940+
returnresult;
2941+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp