@ -8,15 +8,15 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $ Header : / cvsroot / pgsql / src / backend / storage / page / bufpage . c , v 1.37 2001 / 03 / 22 03 : 59 : 47 momjian Exp $
* $ Header : / cvsroot / pgsql / src / backend / storage / page / bufpage . c , v 1.38 2001 / 10 / 23 02 : 20 : 15 tgl Exp $
*
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
*/
# include "postgres.h"
# include <sys/types.h>
# include <sys/types.h>
# include <sys/file.h>
# include <sys/file.h>
# include "postgres.h"
# include "storage/bufpage.h"
# include "storage/bufpage.h"
@ -38,12 +38,12 @@ PageInit(Page page, Size pageSize, Size specialSize)
{
{
PageHeader p = ( PageHeader ) page ;
PageHeader p = ( PageHeader ) page ;
specialSize = MAXALIGN ( specialSize ) ;
Assert ( pageSize = = BLCKSZ ) ;
Assert ( pageSize = = BLCKSZ ) ;
Assert ( pageSize >
Assert ( pageSize >
specialSize + sizeof ( PageHeaderData ) - sizeof ( ItemIdData ) ) ;
specialSize + sizeof ( PageHeaderData ) - sizeof ( ItemIdData ) ) ;
specialSize = MAXALIGN ( specialSize ) ;
p - > pd_lower = sizeof ( PageHeaderData ) - sizeof ( ItemIdData ) ;
p - > pd_lower = sizeof ( PageHeaderData ) - sizeof ( ItemIdData ) ;
p - > pd_upper = pageSize - specialSize ;
p - > pd_upper = pageSize - specialSize ;
p - > pd_special = pageSize - specialSize ;
p - > pd_special = pageSize - specialSize ;
@ -93,7 +93,7 @@ PageAddItem(Page page,
ItemId itemId ;
ItemId itemId ;
OffsetNumber limit ;
OffsetNumber limit ;
bool needshuffle = false ;
bool needshuffle = false ;
bool overwritemode = flags & OverwritePageMode ;
bool overwritemode = ( flags & OverwritePageMode ) ! = 0 ;
flags & = ~ OverwritePageMode ;
flags & = ~ OverwritePageMode ;
@ -209,7 +209,7 @@ PageGetTempPage(Page page, Size specialSize)
thdr = ( PageHeader ) temp ;
thdr = ( PageHeader ) temp ;
/* copy old page in */
/* copy old page in */
memmove ( temp , page , pageSize ) ;
memcpy ( temp , page , pageSize ) ;
/* clear out the middle */
/* clear out the middle */
size = ( pageSize - sizeof ( PageHeaderData ) ) + sizeof ( ItemIdData ) ;
size = ( pageSize - sizeof ( PageHeaderData ) ) + sizeof ( ItemIdData ) ;
@ -239,27 +239,22 @@ PageRestoreTempPage(Page tempPage, Page oldPage)
pfree ( tempPage ) ;
pfree ( tempPage ) ;
}
}
/* ----------------
/*
* itemid stuff for PageRepairFragmentation
* sorting support for PageRepairFragmentation
* - - - - - - - - - - - - - - - -
*/
*/
struct itemIdSortData
struct itemIdSortData
{
{
int offsetindex ; /* linp array index */
int offsetindex ; /* linp array index */
ItemIdData itemiddata ;
int itemoff ; /* page offset of item data */
Size alignedlen ; /* MAXALIGN(item data len) */
} ;
} ;
static int
static int
itemid compare ( const void * itemidp1 , const void * itemidp2 )
itemoff compare ( const void * itemidp1 , const void * itemidp2 )
{
{
if ( ( ( struct itemIdSortData * ) itemidp1 ) - > itemiddata . lp_off = =
/* Sort in decreasing itemoff order */
( ( struct itemIdSortData * ) itemidp2 ) - > itemiddata . lp_off )
return ( ( struct itemIdSortData * ) itemidp2 ) - > itemoff -
return 0 ;
( ( struct itemIdSortData * ) itemidp1 ) - > itemoff ;
else if ( ( ( struct itemIdSortData * ) itemidp1 ) - > itemiddata . lp_off <
( ( struct itemIdSortData * ) itemidp2 ) - > itemiddata . lp_off )
return 1 ;
else
return - 1 ;
}
}
/*
/*
@ -269,20 +264,40 @@ itemidcompare(const void *itemidp1, const void *itemidp2)
* It doesn ' t remove unused line pointers ! Please don ' t change this .
* It doesn ' t remove unused line pointers ! Please don ' t change this .
* This routine is usable for heap pages only .
* This routine is usable for heap pages only .
*
*
* Returns number of unused line pointers on page . If " unused " is not NULL
* then the unused [ ] array is filled with indexes of unused line pointers .
*/
*/
int
int
PageRepairFragmentation ( Page page , OffsetNumber * unused )
PageRepairFragmentation ( Page page , OffsetNumber * unused )
{
{
int i ;
Offset pd_lower = ( ( PageHeader ) page ) - > pd_lower ;
Offset pd_upper = ( ( PageHeader ) page ) - > pd_upper ;
Offset pd_special = ( ( PageHeader ) page ) - > pd_special ;
struct itemIdSortData * itemidbase ,
struct itemIdSortData * itemidbase ,
* itemidptr ;
* itemidptr ;
ItemId lp ;
ItemId lp ;
int nline ,
int nline ,
nused ;
nused ;
int i ;
Size totallen ;
Offset upper ;
Offset upper ;
Size alignedSize ;
nline = ( int16 ) PageGetMaxOffsetNumber ( page ) ;
/*
* It ' s worth the trouble to be more paranoid here than in most places ,
* because we are about to reshuffle data in ( what is usually ) a shared
* disk buffer . If we aren ' t careful then corrupted pointers , lengths ,
* etc could cause us to clobber adjacent disk buffers , spreading the
* data loss further . So , check everything .
*/
if ( pd_lower < ( sizeof ( PageHeaderData ) - sizeof ( ItemIdData ) ) | |
pd_lower > pd_upper | |
pd_upper > pd_special | |
pd_special > BLCKSZ | |
pd_special ! = MAXALIGN ( pd_special ) )
elog ( ERROR , " PageRepairFragmentation: corrupted page pointers: lower = %u, upper = %u, special = %u " ,
pd_lower , pd_upper , pd_special ) ;
nline = PageGetMaxOffsetNumber ( page ) ;
nused = 0 ;
nused = 0 ;
for ( i = 0 ; i < nline ; i + + )
for ( i = 0 ; i < nline ; i + + )
{
{
@ -297,56 +312,65 @@ PageRepairFragmentation(Page page, OffsetNumber *unused)
if ( nused = = 0 )
if ( nused = = 0 )
{
{
/* Page is completely empty, so just reset it quickly */
for ( i = 0 ; i < nline ; i + + )
for ( i = 0 ; i < nline ; i + + )
{
{
lp = ( ( PageHeader ) page ) - > pd_linp + i ;
lp = ( ( PageHeader ) page ) - > pd_linp + i ;
if ( ( * lp ) . lp_len > 0 ) /* unused, but allocated */
( * lp ) . lp_len = 0 ; /* indicate unused & deallocated */
( * lp ) . lp_len = 0 ; /* indicate unused & deallocated */
}
}
( ( PageHeader ) page ) - > pd_upper = pd_special ;
( ( PageHeader ) page ) - > pd_upper = ( ( PageHeader ) page ) - > pd_special ;
}
}
else
else
{ /* nused != 0 */
{ /* nused != 0 */
/* Need to compact the page the hard way */
itemidbase = ( struct itemIdSortData * )
itemidbase = ( struct itemIdSortData * )
palloc ( sizeof ( struct itemIdSortData ) * nused ) ;
palloc ( sizeof ( struct itemIdSortData ) * nused ) ;
MemSet ( ( char * ) itemidbase , 0 , sizeof ( struct itemIdSortData ) * nused ) ;
itemidptr = itemidbase ;
itemidptr = itemidbase ;
totallen = 0 ;
for ( i = 0 ; i < nline ; i + + )
for ( i = 0 ; i < nline ; i + + )
{
{
lp = ( ( PageHeader ) page ) - > pd_linp + i ;
lp = ( ( PageHeader ) page ) - > pd_linp + i ;
if ( ( * lp ) . lp_flags & LP_USED )
if ( ( * lp ) . lp_flags & LP_USED )
{
{
itemidptr - > offsetindex = i ;
itemidptr - > offsetindex = i ;
itemidptr - > itemiddata = * lp ;
itemidptr - > itemoff = ( * lp ) . lp_off ;
if ( itemidptr - > itemoff < ( int ) pd_upper | |
itemidptr - > itemoff > = ( int ) pd_special )
elog ( ERROR , " PageRepairFragmentation: corrupted item pointer %u " ,
itemidptr - > itemoff ) ;
itemidptr - > alignedlen = MAXALIGN ( ( * lp ) . lp_len ) ;
totallen + = itemidptr - > alignedlen ;
itemidptr + + ;
itemidptr + + ;
}
}
else
else
{
{
if ( ( * lp ) . lp_len > 0 ) /* unused, but allocated */
( * lp ) . lp_len = 0 ; /* indicate unused & deallocated */
( * lp ) . lp_len = 0 ; /* indicate unused & deallocated */
}
}
}
}
/* sort itemIdSortData array... */
if ( totallen > ( Size ) ( pd_special - pd_lower ) )
elog ( ERROR , " PageRepairFragmentation: corrupted item lengths, total %u, avail %u " ,
totallen , pd_special - pd_lower ) ;
/* sort itemIdSortData array into decreasing itemoff order */
qsort ( ( char * ) itemidbase , nused , sizeof ( struct itemIdSortData ) ,
qsort ( ( char * ) itemidbase , nused , sizeof ( struct itemIdSortData ) ,
itemidcompare ) ;
itemoff compare ) ;
/* compactify page */
/* compactify page */
( ( PageHeader ) page ) - > pd_ upper = ( ( PageHeader ) page ) - > pd_special ;
upper = pd_special ;
for ( i = 0 , itemidptr = itemidbase ; i < nused ; i + + , itemidptr + + )
for ( i = 0 , itemidptr = itemidbase ; i < nused ; i + + , itemidptr + + )
{
{
lp = ( ( PageHeader ) page ) - > pd_linp + itemidptr - > offsetindex ;
lp = ( ( PageHeader ) page ) - > pd_linp + itemidptr - > offsetindex ;
alignedSize = MAXALIGN ( ( * lp ) . lp_len ) ;
upper - = itemidptr - > alignedlen ;
upper = ( ( PageHeader ) page ) - > pd_upper - alignedSize ;
memmove ( ( char * ) page + upper ,
memmove ( ( char * ) page + upper ,
( char * ) page + ( * lp ) . lp_ off,
( char * ) page + itemidptr - > item off,
( * lp ) . lp_ len) ;
itemidptr - > aligned len) ;
( * lp ) . lp_off = upper ;
( * lp ) . lp_off = upper ;
( ( PageHeader ) page ) - > pd_upper = upper ;
}
}
( ( PageHeader ) page ) - > pd_upper = upper ;
pfree ( itemidbase ) ;
pfree ( itemidbase ) ;
}
}
@ -362,12 +386,11 @@ PageGetFreeSpace(Page page)
{
{
Size space ;
Size space ;
space = ( ( PageHeader ) page ) - > pd_upper - ( ( PageHeader ) page ) - > pd_lower ;
space = ( ( PageHeader ) page ) - > pd_upper - ( ( PageHeader ) page ) - > pd_lower ;
if ( space < sizeof ( ItemIdData ) )
if ( space < sizeof ( ItemIdData ) )
return 0 ;
return 0 ;
space - = sizeof ( ItemIdData ) ; /* XXX not always tru e */
space - = sizeof ( ItemIdData ) ; /* XXX not always appropria te */
return space ;
return space ;
}
}