88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.80 2000/04/12 17:15:34 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.81 2000/05/19 03:22:28 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -607,7 +607,6 @@ BufferAlloc(Relation reln,
607607{
608608SpinRelease (BufMgrLock );
609609elog (FATAL ,"buffer wasn't in the buffer table\n" );
610-
611610}
612611
613612/* record the database name and relation name for this buffer */
@@ -1585,9 +1584,9 @@ RelationGetNumberOfBlocks(Relation relation)
15851584/* ---------------------------------------------------------------------
15861585 *ReleaseRelationBuffers
15871586 *
1588- *this functionunmarks all thedirty pagesof a relation
1589- *in the buffer pool so that at the end of transaction
1590- *these pages will not be flushed . This is used when the
1587+ *This functionremoves all thebuffered pagesfor a relation
1588+ *from the buffer pool. Dirty pages are simply dropped, without
1589+ *bothering to write them out first . This is used when the
15911590 *relation is about to be deleted. We assume that the caller
15921591 *holds an exclusive lock on the relation, which should assure
15931592 *that no new buffers will be acquired for the rel meanwhile.
@@ -1600,7 +1599,6 @@ void
16001599ReleaseRelationBuffers (Relation rel )
16011600{
16021601Oid relid = RelationGetRelid (rel );
1603- bool holding = false;
16041602int i ;
16051603BufferDesc * buf ;
16061604
@@ -1610,22 +1608,23 @@ ReleaseRelationBuffers(Relation rel)
16101608{
16111609buf = & LocalBufferDescriptors [i ];
16121610if (buf -> tag .relId .relId == relid )
1611+ {
16131612buf -> flags &= ~(BM_DIRTY |BM_JUST_DIRTIED );
1613+ LocalRefCount [i ]= 0 ;
1614+ buf -> tag .relId .relId = InvalidOid ;
1615+ }
16141616}
16151617return ;
16161618}
16171619
1620+ SpinAcquire (BufMgrLock );
16181621for (i = 1 ;i <=NBuffers ;i ++ )
16191622{
16201623buf = & BufferDescriptors [i - 1 ];
1621- if (!holding )
1622- {
1623- SpinAcquire (BufMgrLock );
1624- holding = true;
1625- }
16261624recheck :
1627- if (buf -> tag .relId .dbId == MyDatabaseId &&
1628- buf -> tag .relId .relId == relid )
1625+ if (buf -> tag .relId .relId == relid &&
1626+ (buf -> tag .relId .dbId == MyDatabaseId ||
1627+ buf -> tag .relId .dbId == (Oid )NULL ))
16291628{
16301629
16311630/*
@@ -1661,21 +1660,24 @@ ReleaseRelationBuffers(Relation rel)
16611660buf -> refcount == 1 );
16621661/* ReleaseBuffer expects we do not hold the lock at entry */
16631662SpinRelease (BufMgrLock );
1664- holding = false;
16651663ReleaseBuffer (i );
1664+ SpinAcquire (BufMgrLock );
16661665}
1666+ /*
1667+ * And mark the buffer as no longer occupied by this rel.
1668+ */
1669+ BufTableDelete (buf );
16671670}
16681671}
1669-
1670- if (holding )
1671- SpinRelease (BufMgrLock );
1672+ SpinRelease (BufMgrLock );
16721673}
16731674
16741675/* ---------------------------------------------------------------------
16751676 *DropBuffers
16761677 *
1677- *This function marks all the buffers in the buffer cache for a
1678- *particular database as clean. This is used when we destroy a
1678+ *This function removes all the buffers in the buffer cache for a
1679+ *particular database. Dirty pages are simply dropped, without
1680+ *bothering to write them out first. This is used when we destroy a
16791681 *database, to avoid trying to flush data to disk when the directory
16801682 *tree no longer exists.Implementation is pretty similar to
16811683 *ReleaseRelationBuffers() which is for destroying just one relation.
@@ -1719,6 +1721,10 @@ DropBuffers(Oid dbid)
17191721 * backends are running in that database.
17201722 */
17211723Assert (buf -> flags & BM_FREE );
1724+ /*
1725+ * And mark the buffer as no longer occupied by this page.
1726+ */
1727+ BufTableDelete (buf );
17221728}
17231729}
17241730SpinRelease (BufMgrLock );
@@ -1812,34 +1818,39 @@ BufferPoolBlowaway()
18121818/* ---------------------------------------------------------------------
18131819 *FlushRelationBuffers
18141820 *
1815- *This function removes from the buffer pool all pages of a relation
1816- *that have blocknumber >= specified block. Pages that are dirty are
1817- *written out first.If expectDirty is false, a notice is emitted
1818- *warning of dirty buffers, but we proceed anyway. An error code is
1819- *returned if we fail to dump a dirty buffer or if we find one of
1821+ *This function flushes all dirty pages of a relation out to disk.
1822+ *Furthermore, pages that have blocknumber >= firstDelBlock are
1823+ *actually removed from the buffer pool. An error code is returned
1824+ *if we fail to dump a dirty buffer or if we find one of
18201825 *the target pages is pinned into the cache.
18211826 *
18221827 *This is used by VACUUM before truncating the relation to the given
1823- *number of blocks. For VACUUM, we pass expectDirty = false since it
1824- *could mean a bug in VACUUM if any of the unwanted pages were still
1825- *dirty.(TRUNCATE TABLE also uses it in the same way.)
1826- *
1827- *This is also used by RENAME TABLE (with block=0 and expectDirty=true)
1828+ *number of blocks. (TRUNCATE TABLE also uses it in the same way.)
1829+ *It might seem unnecessary to flush dirty pages before firstDelBlock,
1830+ *since VACUUM should already have committed its changes. However,
1831+ *it is possible for there still to be dirty pages: if some page
1832+ *had unwritten on-row tuple status updates from a prior transaction,
1833+ *and VACUUM had no additional changes to make to that page, then
1834+ *VACUUM won't have written it. This is harmless in most cases but
1835+ *will break pg_upgrade, which relies on VACUUM to ensure that *all*
1836+ *tuples have correct on-row status. So, we check and flush all
1837+ *dirty pages of the rel regardless of block number.
1838+ *
1839+ *This is also used by RENAME TABLE (with firstDelBlock = 0)
18281840 *to clear out the buffer cache before renaming the physical files of
18291841 *a relation. Without that, some other backend might try to do a
18301842 *blind write of a buffer page (relying on the BlindId of the buffer)
18311843 *and fail because it's not got the right filename anymore.
18321844 *
1833- *Inboth cases, the caller should be holding AccessExclusiveLock on
1845+ *Inall cases, the caller should be holding AccessExclusiveLock on
18341846 *the target relation to ensure that no other backend is busy reading
18351847 *more blocks of the relation.
18361848 *
1837- *Formerly, we considered it an error condition if we foundunexpectedly
1838- *dirty buffers.However, since BufferSync no longer forces out all
1849+ *Formerly, we considered it an error condition if we founddirty
1850+ *buffers here .However, since BufferSync no longer forces out all
18391851 *dirty buffers at every xact commit, it's possible for dirty buffers
18401852 *to still be present in the cache due to failure of an earlier
1841- *transaction. So, downgrade the error to a mere notice. Maybe we
1842- *shouldn't even emit a notice...
1853+ *transaction. So, must flush dirty buffers without complaint.
18431854 *
18441855 *Returns: 0 - Ok, -1 - FAILED TO WRITE DIRTY BUFFER, -2 - PINNED
18451856 *
@@ -1848,8 +1859,9 @@ BufferPoolBlowaway()
18481859 * --------------------------------------------------------------------
18491860 */
18501861int
1851- FlushRelationBuffers (Relation rel ,BlockNumber block , bool expectDirty )
1862+ FlushRelationBuffers (Relation rel ,BlockNumber firstDelBlock )
18521863{
1864+ Oid relid = RelationGetRelid (rel );
18531865int i ;
18541866BufferDesc * buf ;
18551867
@@ -1858,31 +1870,29 @@ FlushRelationBuffers(Relation rel, BlockNumber block, bool expectDirty)
18581870for (i = 0 ;i < NLocBuffer ;i ++ )
18591871{
18601872buf = & LocalBufferDescriptors [i ];
1861- if (buf -> tag .relId .relId == RelationGetRelid (rel )&&
1862- buf -> tag .blockNum >=block )
1873+ if (buf -> tag .relId .relId == relid )
18631874{
18641875if (buf -> flags & BM_DIRTY )
18651876{
1866- if (!expectDirty )
1867- elog (NOTICE ,"FlushRelationBuffers(%s (local), %u): block %u is dirty" ,
1868- RelationGetRelationName (rel ),
1869- block ,buf -> tag .blockNum );
18701877if (FlushBuffer (- i - 1 , false)!= STATUS_OK )
18711878{
18721879elog (NOTICE ,"FlushRelationBuffers(%s (local), %u): block %u is dirty, could not flush it" ,
1873- RelationGetRelationName (rel ),
1874- block , buf -> tag .blockNum );
1880+ RelationGetRelationName (rel ),firstDelBlock ,
1881+ buf -> tag .blockNum );
18751882return -1 ;
18761883}
18771884}
18781885if (LocalRefCount [i ]> 0 )
18791886{
18801887elog (NOTICE ,"FlushRelationBuffers(%s (local), %u): block %u is referenced (%ld)" ,
1881- RelationGetRelationName (rel ),block ,
1888+ RelationGetRelationName (rel ),firstDelBlock ,
18821889buf -> tag .blockNum ,LocalRefCount [i ]);
18831890return -2 ;
18841891}
1885- buf -> tag .relId .relId = InvalidOid ;
1892+ if (buf -> tag .blockNum >=firstDelBlock )
1893+ {
1894+ buf -> tag .relId .relId = InvalidOid ;
1895+ }
18861896}
18871897}
18881898return 0 ;
@@ -1891,26 +1901,20 @@ FlushRelationBuffers(Relation rel, BlockNumber block, bool expectDirty)
18911901SpinAcquire (BufMgrLock );
18921902for (i = 0 ;i < NBuffers ;i ++ )
18931903{
1894- recheck :
18951904buf = & BufferDescriptors [i ];
1896- if (buf -> tag .relId .relId == RelationGetRelid (rel )&&
1905+ recheck :
1906+ if (buf -> tag .relId .relId == relid &&
18971907(buf -> tag .relId .dbId == MyDatabaseId ||
1898- buf -> tag .relId .dbId == (Oid )NULL )&&
1899- buf -> tag .blockNum >=block )
1908+ buf -> tag .relId .dbId == (Oid )NULL ))
19001909{
19011910if (buf -> flags & BM_DIRTY )
19021911{
19031912PinBuffer (buf );
19041913SpinRelease (BufMgrLock );
1905- if (!expectDirty )
1906- elog (NOTICE ,"FlushRelationBuffers(%s, %u): block %u is dirty (private %ld, global %d)" ,
1907- RelationGetRelationName (rel ),block ,
1908- buf -> tag .blockNum ,
1909- PrivateRefCount [i ],buf -> refcount );
19101914if (FlushBuffer (i + 1 , true)!= STATUS_OK )
19111915{
19121916elog (NOTICE ,"FlushRelationBuffers(%s, %u): block %u is dirty (private %ld, global %d), could not flush it" ,
1913- RelationGetRelationName (rel ),block ,
1917+ RelationGetRelationName (rel ),firstDelBlock ,
19141918buf -> tag .blockNum ,
19151919PrivateRefCount [i ],buf -> refcount );
19161920return -1 ;
@@ -1927,12 +1931,15 @@ FlushRelationBuffers(Relation rel, BlockNumber block, bool expectDirty)
19271931{
19281932SpinRelease (BufMgrLock );
19291933elog (NOTICE ,"FlushRelationBuffers(%s, %u): block %u is referenced (private %ld, global %d)" ,
1930- RelationGetRelationName (rel ),block ,
1934+ RelationGetRelationName (rel ),firstDelBlock ,
19311935buf -> tag .blockNum ,
19321936PrivateRefCount [i ],buf -> refcount );
19331937return -2 ;
19341938}
1935- BufTableDelete (buf );
1939+ if (buf -> tag .blockNum >=firstDelBlock )
1940+ {
1941+ BufTableDelete (buf );
1942+ }
19361943}
19371944}
19381945SpinRelease (BufMgrLock );