@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $ Header : / cvsroot / pgsql / src / backend / commands / vacuum . c , v 1.96 1999 / 02 / 21 03 : 48 : 33 scrappy Exp $
* $ Header : / cvsroot / pgsql / src / backend / commands / vacuum . c , v 1.97 1999 / 03 / 28 20 : 32 : 01 vadim Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -65,6 +65,9 @@ static Portal vc_portal;
static int MESSAGE_LEVEL ; /* message level */
static TransactionId XmaxRecent ;
extern void GetXmaxRecent ( TransactionId * xid ) ;
# define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
# define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
# define swapDatum(a,b) {Datum tmp; tmp=a; a=b; b=tmp;}
@ -98,9 +101,11 @@ static void vc_free(VRelList vrl);
static void vc_getindices ( Oid relid , int * nindices , Relation * * Irel ) ;
static void vc_clsindices ( int nindices , Relation * Irel ) ;
static void vc_mkindesc ( Relation onerel , int nindices , Relation * Irel , IndDesc * * Idesc ) ;
static char * vc_find_eq ( char * bot , int nelem , int size , char * elm , int ( * compar ) ( char * , char * ) ) ;
static int vc_cmp_blk ( char * left , char * right ) ;
static int vc_cmp_offno ( char * left , char * right ) ;
static void * vc_find_eq ( void * bot , int nelem , int size , void * elm ,
int ( * compar ) ( const void * , const void * ) ) ;
static int vc_cmp_blk ( const void * left , const void * right ) ;
static int vc_cmp_offno ( const void * left , const void * right ) ;
static int vc_cmp_vtlinks ( const void * left , const void * right ) ;
static bool vc_enough_space ( VPageDescr vpd , Size len ) ;
void
@ -502,6 +507,8 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
/* we require the relation to be locked until the indices are cleaned */
LockRelation ( onerel , AccessExclusiveLock ) ;
GetXmaxRecent ( & XmaxRecent ) ;
/* scan it */
vacuum_pages . vpl_num_pages = fraged_pages . vpl_num_pages = 0 ;
vc_scanheap ( vacrelstats , onerel , & vacuum_pages , & fraged_pages ) ;
@ -595,6 +602,7 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
vp ;
uint32 tups_vacuumed ,
num_tuples ,
nkeep ,
nunused ,
ncrash ,
empty_pages ,
@ -609,22 +617,24 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
struct rusage ru0 ,
ru1 ;
bool do_shrinking = true ;
VTupleLink vtlinks = ( VTupleLink ) palloc ( 100 * sizeof ( VTupleLinkData ) ) ;
int num_vtlinks = 0 ;
int free_vtlinks = 100 ;
getrusage ( RUSAGE_SELF , & ru0 ) ;
tups_vacuumed = num_tuples = nunused = ncrash = empty_pages =
relname = ( RelationGetRelationName ( onerel ) ) - > data ;
elog ( MESSAGE_LEVEL , " --Relation %s-- " , relname ) ;
tups_vacuumed = num_tuples = nkeep = nunused = ncrash = empty_pages =
new_pages = changed_pages = empty_end_pages = 0 ;
free_size = usable_free_size = 0 ;
relname = ( RelationGetRelationName ( onerel ) ) - > data ;
nblocks = RelationGetNumberOfBlocks ( onerel ) ;
vpc = ( VPageDescr ) palloc ( sizeof ( VPageDescrData ) + MaxOffsetNumber * sizeof ( OffsetNumber ) ) ;
vpc - > vpd_offsets_used = 0 ;
elog ( MESSAGE_LEVEL , " --Relation %s-- " , relname ) ;
for ( blkno = 0 ; blkno < nblocks ; blkno + + )
{
buf = ReadBuffer ( onerel , blkno ) ;
@ -686,6 +696,34 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
{
if ( tuple . t_data - > t_infomask & HEAP_XMIN_INVALID )
tupgone = true ;
else if ( tuple . t_data - > t_infomask & HEAP_MOVED_OFF )
{
if ( TransactionIdDidCommit ( ( TransactionId )
tuple . t_data - > t_cmin ) )
{
tuple . t_data - > t_infomask | = HEAP_XMIN_INVALID ;
tupgone = true ;
}
else
{
tuple . t_data - > t_infomask | = HEAP_XMIN_COMMITTED ;
pgchanged = true ;
}
}
else if ( tuple . t_data - > t_infomask & HEAP_MOVED_IN )
{
if ( ! TransactionIdDidCommit ( ( TransactionId )
tuple . t_data - > t_cmin ) )
{
tuple . t_data - > t_infomask | = HEAP_XMIN_INVALID ;
tupgone = true ;
}
else
{
tuple . t_data - > t_infomask | = HEAP_XMIN_COMMITTED ;
pgchanged = true ;
}
}
else
{
if ( TransactionIdDidAbort ( tuple . t_data - > t_xmin ) )
@ -722,22 +760,37 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
! ( tuple . t_data - > t_infomask & HEAP_XMAX_INVALID ) )
{
if ( tuple . t_data - > t_infomask & HEAP_XMAX_COMMITTED )
tupgone = true ;
{
if ( tuple . t_data - > t_infomask & HEAP_MARKED_FOR_UPDATE )
{
pgchanged = true ;
tuple . t_data - > t_infomask | = HEAP_XMAX_INVALID ;
}
else
tupgone = true ;
}
else if ( TransactionIdDidAbort ( tuple . t_data - > t_xmax ) )
{
tuple . t_data - > t_infomask | = HEAP_XMAX_INVALID ;
pgchanged = true ;
}
else if ( TransactionIdDidCommit ( tuple . t_data - > t_xmax ) )
tupgone = true ;
{
if ( tuple . t_data - > t_infomask & HEAP_MARKED_FOR_UPDATE )
{
tuple . t_data - > t_infomask | = HEAP_XMAX_INVALID ;
pgchanged = true ;
}
else
tupgone = true ;
}
else if ( ! TransactionIdIsInProgress ( tuple . t_data - > t_xmax ) )
{
/*
* Not Aborted , Not Committed , Not in Progress - so it
* from crashed process . - vadim 06 / 02 / 97
*/
tuple . t_data - > t_infomask | = HEAP_XMAX_INVALID ; ;
tuple . t_data - > t_infomask | = HEAP_XMAX_INVALID ;
pgchanged = true ;
}
else
@ -746,6 +799,41 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
relname , blkno , offnum , tuple . t_data - > t_xmax ) ;
do_shrinking = false ;
}
/*
* If tuple is recently deleted then
* we must not remove it from relation .
*/
if ( tupgone & & tuple . t_data - > t_xmax > = XmaxRecent & &
tuple . t_data - > t_infomask & HEAP_XMIN_COMMITTED )
{
tupgone = false ;
nkeep + + ;
if ( ! ( tuple . t_data - > t_infomask & HEAP_XMAX_COMMITTED ) )
{
tuple . t_data - > t_infomask | = HEAP_XMAX_COMMITTED ;
pgchanged = true ;
}
/*
* If we do shrinking and this tuple is updated one
* then remember it to construct updated tuple
* dependencies .
*/
if ( do_shrinking & & ! ( ItemPointerEquals ( & ( tuple . t_self ) ,
& ( tuple . t_data - > t_ctid ) ) ) )
{
if ( free_vtlinks = = 0 )
{
free_vtlinks = 1000 ;
vtlinks = ( VTupleLink ) repalloc ( vtlinks ,
( free_vtlinks + num_vtlinks ) *
sizeof ( VTupleLinkData ) ) ;
}
vtlinks [ num_vtlinks ] . new_tid = tuple . t_data - > t_ctid ;
vtlinks [ num_vtlinks ] . this_tid = tuple . t_self ;
free_vtlinks - - ;
num_vtlinks + + ;
}
}
}
/*
@ -859,13 +947,31 @@ vc_scanheap(VRelStats *vacrelstats, Relation onerel,
}
}
if ( usable_free_size > 0 & & num_vtlinks > 0 )
{
qsort ( ( char * ) vtlinks , num_vtlinks , sizeof ( VTupleLinkData ) ,
vc_cmp_vtlinks ) ;
vacrelstats - > vtlinks = vtlinks ;
vacrelstats - > num_vtlinks = num_vtlinks ;
}
else
{
vacrelstats - > vtlinks = NULL ;
vacrelstats - > num_vtlinks = 0 ;
pfree ( vtlinks ) ;
}
getrusage ( RUSAGE_SELF , & ru1 ) ;
elog ( MESSAGE_LEVEL , " Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
Tup % u : Vac % u , Crash % u , UnUsed % u , MinLen % u , MaxLen % u ; Re - using : Free / Avail . Space % u / % u ; EndEmpty / Avail . Pages % u / % u . Elapsed % u / % u sec . " ,
nblocks , changed_pages , vacuum_pages - > vpl_num_pages , empty_pages , new_pages ,
num_tuples , tups_vacuumed , ncrash , nunused , min_tlen , max_tlen ,
free_size , usable_free_size , empty_end_pages , fraged_pages - > vpl_num_pages ,
Tup % u : Vac % u , Keep / VTL % u / % u , Crash % u , UnUsed % u , MinLen % u , MaxLen % u ; \
Re - using : Free / Avail . Space % u / % u ; EndEmpty / Avail . Pages % u / % u . \
Elapsed % u / % u sec . " ,
nblocks , changed_pages , vacuum_pages - > vpl_num_pages , empty_pages ,
new_pages , num_tuples , tups_vacuumed ,
nkeep , vacrelstats - > num_vtlinks , ncrash ,
nunused , min_tlen , max_tlen , free_size , usable_free_size ,
empty_end_pages , fraged_pages - > vpl_num_pages ,
ru1 . ru_stime . tv_sec - ru0 . ru_stime . tv_sec ,
ru1 . ru_utime . tv_sec - ru0 . ru_utime . tv_sec ) ;
@ -917,7 +1023,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
* idcur ;
int last_fraged_block ,
last_vacuum_block ,
i ;
i = 0 ;
Size tuple_len ;
int num_moved ,
num_fraged_pages ,
@ -1022,6 +1128,280 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
tuple_len = tuple . t_len = ItemIdGetLength ( itemid ) ;
ItemPointerSet ( & ( tuple . t_self ) , blkno , offnum ) ;
if ( ! ( tuple . t_data - > t_infomask & HEAP_XMIN_COMMITTED ) )
{
if ( ( TransactionId ) tuple . t_data - > t_cmin ! = myXID )
elog ( ERROR , " Invalid XID in t_cmin " ) ;
if ( tuple . t_data - > t_infomask & HEAP_MOVED_OFF )
continue ; /* already removed by me */
if ( tuple . t_data - > t_infomask & HEAP_MOVED_IN )
break ;
elog ( ERROR , " HEAP_MOVED_OFF/HEAP_MOVED_IN was expected " ) ;
}
/*
* If this tuple is in the chain of tuples created in
* updates by " recent " transactions then we have to
* move all chain of tuples to another places .
*/
if ( ( tuple . t_data - > t_infomask & HEAP_UPDATED & &
tuple . t_data - > t_xmin > = XmaxRecent ) | |
( ! ( tuple . t_data - > t_infomask & HEAP_XMAX_INVALID ) & &
! ( ItemPointerEquals ( & ( tuple . t_self ) , & ( tuple . t_data - > t_ctid ) ) ) ) )
{
Buffer Cbuf = buf ;
Page Cpage ;
ItemId Citemid ;
ItemPointerData Ctid ;
HeapTupleData tp = tuple ;
Size tlen = tuple_len ;
VTupleMove vtmove = ( VTupleMove )
palloc ( 100 * sizeof ( VTupleMoveData ) ) ;
int num_vtmove = 0 ;
int free_vtmove = 100 ;
VPageDescr to_vpd = fraged_pages - > vpl_pagedesc [ 0 ] ;
int to_item = 0 ;
bool freeCbuf = false ;
int ti ;
if ( vacrelstats - > vtlinks = = NULL )
elog ( ERROR , " No one parent tuple was found " ) ;
if ( cur_buffer ! = InvalidBuffer )
{
WriteBuffer ( cur_buffer ) ;
cur_buffer = InvalidBuffer ;
}
/*
* If this tuple is in the begin / middle of the chain
* then we have to move to the end of chain .
*/
while ( ! ( tp . t_data - > t_infomask & HEAP_XMAX_INVALID ) & &
! ( ItemPointerEquals ( & ( tp . t_self ) , & ( tp . t_data - > t_ctid ) ) ) )
{
Ctid = tp . t_data - > t_ctid ;
if ( freeCbuf )
ReleaseBuffer ( Cbuf ) ;
freeCbuf = true ;
Cbuf = ReadBuffer ( onerel ,
ItemPointerGetBlockNumber ( & Ctid ) ) ;
Cpage = BufferGetPage ( Cbuf ) ;
Citemid = PageGetItemId ( Cpage ,
ItemPointerGetOffsetNumber ( & Ctid ) ) ;
if ( ! ItemIdIsUsed ( Citemid ) )
elog ( ERROR , " Child itemid marked as unused " ) ;
tp . t_data = ( HeapTupleHeader ) PageGetItem ( Cpage , Citemid ) ;
tp . t_self = Ctid ;
tlen = tp . t_len = ItemIdGetLength ( Citemid ) ;
}
/* first, can chain be moved ? */
for ( ; ; )
{
if ( ! vc_enough_space ( to_vpd , tlen ) )
{
if ( to_vpd ! = last_fraged_page & &
! vc_enough_space ( to_vpd , vacrelstats - > min_tlen ) )
{
Assert ( num_fraged_pages > to_item + 1 ) ;
memmove ( fraged_pages - > vpl_pagedesc + to_item ,
fraged_pages - > vpl_pagedesc + to_item + 1 ,
sizeof ( VPageDescr * ) * ( num_fraged_pages - to_item - 1 ) ) ;
num_fraged_pages - - ;
Assert ( last_fraged_page = = fraged_pages - > vpl_pagedesc [ num_fraged_pages - 1 ] ) ;
}
for ( i = 0 ; i < num_fraged_pages ; i + + )
{
if ( vc_enough_space ( fraged_pages - > vpl_pagedesc [ i ] , tlen ) )
break ;
}
if ( i = = num_fraged_pages ) /* can't move item anywhere */
{
for ( i = 0 ; i < num_vtmove ; i + + )
{
Assert ( vtmove [ i ] . vpd - > vpd_offsets_used > 0 ) ;
( vtmove [ i ] . vpd - > vpd_offsets_used ) - - ;
}
num_vtmove = 0 ;
break ;
}
to_item = i ;
to_vpd = fraged_pages - > vpl_pagedesc [ to_item ] ;
}
to_vpd - > vpd_free - = DOUBLEALIGN ( tlen ) ;
if ( to_vpd - > vpd_offsets_used > = to_vpd - > vpd_offsets_free )
to_vpd - > vpd_free - = DOUBLEALIGN ( sizeof ( ItemIdData ) ) ;
( to_vpd - > vpd_offsets_used ) + + ;
if ( free_vtmove = = 0 )
{
free_vtmove = 1000 ;
vtmove = ( VTupleMove ) repalloc ( vtmove ,
( free_vtmove + num_vtmove ) *
sizeof ( VTupleMoveData ) ) ;
}
vtmove [ num_vtmove ] . tid = tp . t_self ;
vtmove [ num_vtmove ] . vpd = to_vpd ;
if ( to_vpd - > vpd_offsets_used = = 1 )
vtmove [ num_vtmove ] . cleanVpd = true ;
else
vtmove [ num_vtmove ] . cleanVpd = false ;
free_vtmove - - ;
num_vtmove + + ;
/*
* All done ?
*/
if ( ! ( tp . t_data - > t_infomask & HEAP_UPDATED ) | |
tp . t_data - > t_xmin < XmaxRecent )
break ;
/*
* Well , try to find tuple with old row version
*/
for ( ; ; )
{
Buffer Pbuf ;
Page Ppage ;
ItemId Pitemid ;
HeapTupleData Ptp ;
VTupleLinkData vtld ,
* vtlp ;
vtld . new_tid = tp . t_self ;
vtlp = ( VTupleLink )
vc_find_eq ( ( void * ) ( vacrelstats - > vtlinks ) ,
vacrelstats - > num_vtlinks ,
sizeof ( VTupleLinkData ) ,
( void * ) & vtld ,
vc_cmp_vtlinks ) ;
if ( vtlp = = NULL )
elog ( ERROR , " Parent tuple was not found " ) ;
tp . t_self = vtlp - > this_tid ;
Pbuf = ReadBuffer ( onerel ,
ItemPointerGetBlockNumber ( & ( tp . t_self ) ) ) ;
Ppage = BufferGetPage ( Pbuf ) ;
Pitemid = PageGetItemId ( Ppage ,
ItemPointerGetOffsetNumber ( & ( tp . t_self ) ) ) ;
if ( ! ItemIdIsUsed ( Pitemid ) )
elog ( ERROR , " Parent itemid marked as unused " ) ;
Ptp . t_data = ( HeapTupleHeader ) PageGetItem ( Ppage , Pitemid ) ;
Assert ( Ptp . t_data - > t_xmax = = tp . t_data - > t_xmin ) ;
/*
* If this tuple is updated version of row and
* it was created by the same transaction then
* no one is interested in this tuple -
* mark it as removed .
*/
if ( Ptp . t_data - > t_infomask & HEAP_UPDATED & &
Ptp . t_data - > t_xmin = = Ptp . t_data - > t_xmax )
{
TransactionIdStore ( myXID ,
( TransactionId * ) & ( Ptp . t_data - > t_cmin ) ) ;
Ptp . t_data - > t_infomask & =
~ ( HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN ) ;
Ptp . t_data - > t_infomask | = HEAP_MOVED_OFF ;
WriteBuffer ( Pbuf ) ;
continue ;
}
tp . t_data = Ptp . t_data ;
tlen = tp . t_len = ItemIdGetLength ( Pitemid ) ;
if ( freeCbuf )
ReleaseBuffer ( Cbuf ) ;
Cbuf = Pbuf ;
freeCbuf = true ;
break ;
}
}
if ( freeCbuf )
ReleaseBuffer ( Cbuf ) ;
if ( num_vtmove = = 0 ) /* chain can't be moved */
{
pfree ( vtmove ) ;
break ;
}
ItemPointerSetInvalid ( & Ctid ) ;
for ( ti = 0 ; ti < num_vtmove ; ti + + )
{
/* Get tuple from chain */
tuple . t_self = vtmove [ ti ] . tid ;
Cbuf = ReadBuffer ( onerel ,
ItemPointerGetBlockNumber ( & ( tuple . t_self ) ) ) ;
Cpage = BufferGetPage ( Cbuf ) ;
Citemid = PageGetItemId ( Cpage ,
ItemPointerGetOffsetNumber ( & ( tuple . t_self ) ) ) ;
tuple . t_data = ( HeapTupleHeader ) PageGetItem ( Cpage , Citemid ) ;
tuple_len = tuple . t_len = ItemIdGetLength ( Citemid ) ;
/* Get page to move in */
cur_buffer = ReadBuffer ( onerel , vtmove [ ti ] . vpd - > vpd_blkno ) ;
ToPage = BufferGetPage ( cur_buffer ) ;
/* if this page was not used before - clean it */
if ( ! PageIsEmpty ( ToPage ) & & vtmove [ i ] . cleanVpd )
vc_vacpage ( ToPage , vtmove [ ti ] . vpd ) ;
heap_copytuple_with_tuple ( & tuple , & newtup ) ;
RelationInvalidateHeapTuple ( onerel , & tuple ) ;
TransactionIdStore ( myXID , ( TransactionId * ) & ( newtup . t_data - > t_cmin ) ) ;
newtup . t_data - > t_infomask & =
~ ( HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_OFF ) ;
newtup . t_data - > t_infomask | = HEAP_MOVED_IN ;
newoff = PageAddItem ( ToPage , ( Item ) newtup . t_data , tuple_len ,
InvalidOffsetNumber , LP_USED ) ;
if ( newoff = = InvalidOffsetNumber )
{
elog ( ERROR , " \
moving chain : failed to add item with len = % u to page % u " ,
tuple_len , vtmove [ ti ] . vpd - > vpd_blkno ) ;
}
newitemid = PageGetItemId ( ToPage , newoff ) ;
pfree ( newtup . t_data ) ;
newtup . t_data = ( HeapTupleHeader ) PageGetItem ( ToPage , newitemid ) ;
ItemPointerSet ( & ( newtup . t_self ) , vtmove [ i ] . vpd - > vpd_blkno , newoff ) ;
/*
* Set t_ctid pointing to itself for last tuple in
* chain and to next tuple in chain otherwise .
*/
if ( ! ItemPointerIsValid ( & Ctid ) )
newtup . t_data - > t_ctid = newtup . t_self ;
else
newtup . t_data - > t_ctid = Ctid ;
Ctid = newtup . t_self ;
TransactionIdStore ( myXID , ( TransactionId * ) & ( tuple . t_data - > t_cmin ) ) ;
tuple . t_data - > t_infomask & =
~ ( HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN ) ;
tuple . t_data - > t_infomask | = HEAP_MOVED_OFF ;
num_moved + + ;
if ( Cbuf = = buf )
vpc - > vpd_offsets [ vpc - > vpd_offsets_free + + ] =
ItemPointerGetOffsetNumber ( & ( tuple . t_self ) ) ;
if ( Irel ! = ( Relation * ) NULL )
{
for ( i = 0 , idcur = Idesc ; i < nindices ; i + + , idcur + + )
{
FormIndexDatum ( idcur - > natts ,
( AttrNumber * ) & ( idcur - > tform - > indkey [ 0 ] ) ,
& newtup ,
tupdesc ,
idatum ,
inulls ,
idcur - > finfoP ) ;
iresult = index_insert ( Irel [ i ] ,
idatum ,
inulls ,
& newtup . t_self ,
onerel ) ;
if ( iresult )
pfree ( iresult ) ;
}
}
WriteBuffer ( cur_buffer ) ;
if ( Cbuf = = buf )
ReleaseBuffer ( Cbuf ) ;
else
WriteBuffer ( Cbuf ) ;
}
cur_buffer = InvalidBuffer ;
pfree ( vtmove ) ;
continue ;
}
/* try to find new page for this tuple */
if ( cur_buffer = = InvalidBuffer | |
! vc_enough_space ( cur_page , tuple_len ) )
@ -1070,13 +1450,14 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
RelationInvalidateHeapTuple ( onerel , & tuple ) ;
/* store transaction information */
TransactionIdStore ( myXID , & ( newtup . t_data - > t_xmin ) ) ;
newtup . t_data - > t_cmin = myCID ;
StoreInvalidTransactionId ( & ( newtup . t_data - > t_xmax ) ) ;
/* set xmin to unknown and xmax to invalid */
newtup . t_data - > t_infomask & = ~ ( HEAP_XACT_MASK ) ;
newtup . t_data - > t_infomask | = HEAP_XMAX_INVALID ;
/*
* Mark new tuple as moved_in by vacuum and
* store vacuum XID in t_cmin ! ! !
*/
TransactionIdStore ( myXID , ( TransactionId * ) & ( newtup . t_data - > t_cmin ) ) ;
newtup . t_data - > t_infomask & =
~ ( HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_OFF ) ;
newtup . t_data - > t_infomask | = HEAP_MOVED_IN ;
/* add tuple to the page */
newoff = PageAddItem ( ToPage , ( Item ) newtup . t_data , tuple_len ,
@ -1094,11 +1475,14 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
ItemPointerSet ( & ( newtup . t_data - > t_ctid ) , cur_page - > vpd_blkno , newoff ) ;
newtup . t_self = newtup . t_data - > t_ctid ;
/* now logically delete end-tuple */
TransactionIdStore ( myXID , & ( tuple . t_data - > t_xmax ) ) ;
tuple . t_data - > t_cmax = myCID ;
/* set xmax to unknown */
tuple . t_data - > t_infomask & = ~ ( HEAP_XMAX_INVALID | HEAP_XMAX_COMMITTED ) ;
/*
* Mark old tuple as moved_off by vacuum and
* store vacuum XID in t_cmin ! ! !
*/
TransactionIdStore ( myXID , ( TransactionId * ) & ( tuple . t_data - > t_cmin ) ) ;
tuple . t_data - > t_infomask & =
~ ( HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID | HEAP_MOVED_IN ) ;
tuple . t_data - > t_infomask | = HEAP_MOVED_OFF ;
cur_page - > vpd_offsets_used + + ;
num_moved + + ;
@ -1131,6 +1515,8 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
if ( vpc - > vpd_offsets_free > 0 ) /* some tuples were moved */
{
qsort ( ( char * ) ( vpc - > vpd_offsets ) , vpc - > vpd_offsets_free ,
sizeof ( OffsetNumber ) , vc_cmp_offno ) ;
vc_reappage ( & Nvpl , vpc ) ;
WriteBuffer ( buf ) ;
}
@ -1167,7 +1553,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
}
/*
* Clean uncleaned reapped pages from vacuum_pages list and set xmin
* Clean uncleaned reapped pages from vacuum_pages list list and set xmin
* committed for inserted tuples
*/
checked_moved = 0 ;
@ -1178,16 +1564,10 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
page = BufferGetPage ( buf ) ;
if ( ( * vpp ) - > vpd_offsets_used = = 0 ) /* this page was not used */
{
/*
* noff = = 0 in empty pages only - such pages should be
* re - used
*/
Assert ( ( * vpp ) - > vpd_offsets_free > 0 ) ;
vc_vacpage ( page , * vpp ) ;
if ( ! PageIsEmpty ( page ) )
vc_vacpage ( page , * vpp ) ;
}
else
/* this page was used */
else /* this page was used */
{
num_tuples = 0 ;
max_offset = PageGetMaxOffsetNumber ( page ) ;
@ -1199,10 +1579,19 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
if ( ! ItemIdIsUsed ( itemid ) )
continue ;
tuple . t_data = ( HeapTupleHeader ) PageGetItem ( page , itemid ) ;
if ( TransactionIdEquals ( ( TransactionId ) tuple . t_data - > t_xmin , myXI D ) )
if ( ! ( tuple . t_data - > t_infomask & HEAP_XMIN_COMMITTE D ) )
{
tuple . t_data - > t_infomask | = HEAP_XMIN_COMMITTED ;
num_tuples + + ;
if ( ( TransactionId ) tuple . t_data - > t_cmin ! = myXID )
elog ( ERROR , " Invalid XID in t_cmin (2) " ) ;
if ( tuple . t_data - > t_infomask & HEAP_MOVED_IN )
{
tuple . t_data - > t_infomask | = HEAP_XMIN_COMMITTED ;
num_tuples + + ;
}
else if ( tuple . t_data - > t_infomask & HEAP_MOVED_OFF )
tuple . t_data - > t_infomask | = HEAP_XMIN_INVALID ;
else
elog ( ERROR , " HEAP_MOVED_OFF/HEAP_MOVED_IN was expected (2) " ) ;
}
}
Assert ( ( * vpp ) - > vpd_offsets_used = = num_tuples ) ;
@ -1244,16 +1633,13 @@ Elapsed %u/%u sec.",
}
/*
* clean moved tuples from last page in Nvpl list if some tuples
* left there
* clean moved tuples from last page in Nvpl list
*/
if ( vpc - > vpd_offsets_free > 0 & & offnum < = maxoff )
if ( vpc - > vpd_blkno = = blkno - 1 & & vpc - > vpd_offsets_free > 0 )
{
Assert ( vpc - > vpd_blkno = = blkno - 1 ) ;
buf = ReadBuffer ( onerel , vpc - > vpd_blkno ) ;
page = BufferGetPage ( buf ) ;
num_tuples = 0 ;
maxoff = offnum ;
for ( offnum = FirstOffsetNumber ;
offnum < maxoff ;
offnum = OffsetNumberNext ( offnum ) )
@ -1262,9 +1648,20 @@ Elapsed %u/%u sec.",
if ( ! ItemIdIsUsed ( itemid ) )
continue ;
tuple . t_data = ( HeapTupleHeader ) PageGetItem ( page , itemid ) ;
Assert ( TransactionIdEquals ( ( TransactionId ) tuple . t_data - > t_xmax , myXID ) ) ;
itemid - > lp_flags & = ~ LP_USED ;
num_tuples + + ;
if ( ! ( tuple . t_data - > t_infomask & HEAP_XMIN_COMMITTED ) )
{
if ( ( TransactionId ) tuple . t_data - > t_cmin ! = myXID )
elog ( ERROR , " Invalid XID in t_cmin (3) " ) ;
if ( tuple . t_data - > t_infomask & HEAP_MOVED_OFF )
{
itemid - > lp_flags & = ~ LP_USED ;
num_tuples + + ;
}
else
elog ( ERROR , " HEAP_MOVED_OFF was expected " ) ;
}
}
Assert ( vpc - > vpd_offsets_free = = num_tuples ) ;
PageRepairFragmentation ( page ) ;
@ -1298,6 +1695,8 @@ Elapsed %u/%u sec.",
}
pfree ( vpc ) ;
if ( vacrelstats - > vtlinks ! = NULL )
pfree ( vacrelstats - > vtlinks ) ;
} /* vc_rpfheap */
@ -1522,8 +1921,8 @@ vc_tidreapped(ItemPointer itemptr, VPageList vpl)
ioffno = ItemPointerGetOffsetNumber ( itemptr ) ;
vp = & vpd ;
vpp = ( VPageDescr * ) vc_find_eq ( ( char * ) ( vpl - > vpl_pagedesc ) ,
vpl - > vpl_num_pages , sizeof ( VPageDescr ) , ( char * ) & vp ,
vpp = ( VPageDescr * ) vc_find_eq ( ( void * ) ( vpl - > vpl_pagedesc ) ,
vpl - > vpl_num_pages , sizeof ( VPageDescr ) , ( void * ) & vp ,
vc_cmp_blk ) ;
if ( vpp = = ( VPageDescr * ) NULL )
@ -1537,8 +1936,8 @@ vc_tidreapped(ItemPointer itemptr, VPageList vpl)
return vp ;
}
voff = ( OffsetNumber * ) vc_find_eq ( ( char * ) ( vp - > vpd_offsets ) ,
vp - > vpd_offsets_free , sizeof ( OffsetNumber ) , ( char * ) & ioffno ,
voff = ( OffsetNumber * ) vc_find_eq ( ( void * ) ( vp - > vpd_offsets ) ,
vp - > vpd_offsets_free , sizeof ( OffsetNumber ) , ( void * ) & ioffno ,
vc_cmp_offno ) ;
if ( voff = = ( OffsetNumber * ) NULL )
@ -1998,8 +2397,9 @@ vc_free(VRelList vrl)
MemoryContextSwitchTo ( old ) ;
}
static char *
vc_find_eq ( char * bot , int nelem , int size , char * elm , int ( * compar ) ( char * , char * ) )
static void *
vc_find_eq ( void * bot , int nelem , int size , void * elm ,
int ( * compar ) ( const void * , const void * ) )
{
int res ;
int last = nelem - 1 ;
@ -2053,7 +2453,7 @@ vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, cha
} /* vc_find_eq */
static int
vc_cmp_blk ( char * left , char * right )
vc_cmp_blk ( const void * left , const void * right )
{
BlockNumber lblk ,
rblk ;
@ -2070,7 +2470,7 @@ vc_cmp_blk(char *left, char *right)
} /* vc_cmp_blk */
static int
vc_cmp_offno ( char * left , char * right )
vc_cmp_offno ( const void * left , const void * right )
{
if ( * ( OffsetNumber * ) left < * ( OffsetNumber * ) right )
@ -2081,6 +2481,33 @@ vc_cmp_offno(char *left, char *right)
} /* vc_cmp_offno */
static int
vc_cmp_vtlinks ( const void * left , const void * right )
{
if ( ( ( VTupleLink ) left ) - > new_tid . ip_blkid . bi_hi <
( ( VTupleLink ) right ) - > new_tid . ip_blkid . bi_hi )
return - 1 ;
if ( ( ( VTupleLink ) left ) - > new_tid . ip_blkid . bi_hi >
( ( VTupleLink ) right ) - > new_tid . ip_blkid . bi_hi )
return 1 ;
/* bi_hi-es are equal */
if ( ( ( VTupleLink ) left ) - > new_tid . ip_blkid . bi_lo <
( ( VTupleLink ) right ) - > new_tid . ip_blkid . bi_lo )
return - 1 ;
if ( ( ( VTupleLink ) left ) - > new_tid . ip_blkid . bi_lo >
( ( VTupleLink ) right ) - > new_tid . ip_blkid . bi_lo )
return 1 ;
/* bi_lo-es are equal */
if ( ( ( VTupleLink ) left ) - > new_tid . ip_posid <
( ( VTupleLink ) right ) - > new_tid . ip_posid )
return - 1 ;
if ( ( ( VTupleLink ) left ) - > new_tid . ip_posid >
( ( VTupleLink ) right ) - > new_tid . ip_posid )
return 1 ;
return 0 ;
}
static void
vc_getindices ( Oid relid , int * nindices , Relation * * Irel )
@ -2230,7 +2657,7 @@ vc_enough_space(VPageDescr vpd, Size len)
return true ; /* and len <= free_space */
/* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */
if ( len < = vpd - > vpd_free - sizeof ( ItemIdData ) )
if ( len + DOUBLEALIGN ( sizeof ( ItemIdData ) ) < = vpd - > vpd_free )
return true ;
return false ;