8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -607,7 +607,6 @@ BufferAlloc(Relation reln,
607
607
{
608
608
SpinRelease (BufMgrLock );
609
609
elog (FATAL , "buffer wasn't in the buffer table\n" );
610
-
611
610
}
612
611
613
612
/* record the database name and relation name for this buffer */
@@ -1585,9 +1584,9 @@ RelationGetNumberOfBlocks(Relation relation)
1585
1584
/* ---------------------------------------------------------------------
1586
1585
* ReleaseRelationBuffers
1587
1586
*
1588
- * this function unmarks all the dirty pages of 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 function removes all the buffered pages for 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
1591
1590
* relation is about to be deleted. We assume that the caller
1592
1591
* holds an exclusive lock on the relation, which should assure
1593
1592
* that no new buffers will be acquired for the rel meanwhile.
@@ -1600,7 +1599,6 @@ void
1600
1599
ReleaseRelationBuffers (Relation rel )
1601
1600
{
1602
1601
Oid relid = RelationGetRelid (rel );
1603
- bool holding = false;
1604
1602
int i ;
1605
1603
BufferDesc * buf ;
1606
1604
@@ -1610,22 +1608,23 @@ ReleaseRelationBuffers(Relation rel)
1610
1608
{
1611
1609
buf = & LocalBufferDescriptors [i ];
1612
1610
if (buf -> tag .relId .relId == relid )
1611
+ {
1613
1612
buf -> flags &= ~(BM_DIRTY | BM_JUST_DIRTIED );
1613
+ LocalRefCount [i ] = 0 ;
1614
+ buf -> tag .relId .relId = InvalidOid ;
1615
+ }
1614
1616
}
1615
1617
return ;
1616
1618
}
1617
1619
1620
+ SpinAcquire (BufMgrLock );
1618
1621
for (i = 1 ; i <= NBuffers ; i ++ )
1619
1622
{
1620
1623
buf = & BufferDescriptors [i - 1 ];
1621
- if (!holding )
1622
- {
1623
- SpinAcquire (BufMgrLock );
1624
- holding = true;
1625
- }
1626
1624
recheck :
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 ))
1629
1628
{
1630
1629
1631
1630
/*
@@ -1661,21 +1660,24 @@ ReleaseRelationBuffers(Relation rel)
1661
1660
buf -> refcount == 1 );
1662
1661
/* ReleaseBuffer expects we do not hold the lock at entry */
1663
1662
SpinRelease (BufMgrLock );
1664
- holding = false;
1665
1663
ReleaseBuffer (i );
1664
+ SpinAcquire (BufMgrLock );
1666
1665
}
1666
+ /*
1667
+ * And mark the buffer as no longer occupied by this rel.
1668
+ */
1669
+ BufTableDelete (buf );
1667
1670
}
1668
1671
}
1669
-
1670
- if (holding )
1671
- SpinRelease (BufMgrLock );
1672
+ SpinRelease (BufMgrLock );
1672
1673
}
1673
1674
1674
1675
/* ---------------------------------------------------------------------
1675
1676
* DropBuffers
1676
1677
*
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
1679
1681
* database, to avoid trying to flush data to disk when the directory
1680
1682
* tree no longer exists. Implementation is pretty similar to
1681
1683
* ReleaseRelationBuffers() which is for destroying just one relation.
@@ -1719,6 +1721,10 @@ DropBuffers(Oid dbid)
1719
1721
* backends are running in that database.
1720
1722
*/
1721
1723
Assert (buf -> flags & BM_FREE );
1724
+ /*
1725
+ * And mark the buffer as no longer occupied by this page.
1726
+ */
1727
+ BufTableDelete (buf );
1722
1728
}
1723
1729
}
1724
1730
SpinRelease (BufMgrLock );
@@ -1812,34 +1818,39 @@ BufferPoolBlowaway()
1812
1818
/* ---------------------------------------------------------------------
1813
1819
* FlushRelationBuffers
1814
1820
*
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
1820
1825
* the target pages is pinned into the cache.
1821
1826
*
1822
1827
* 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)
1828
1840
* to clear out the buffer cache before renaming the physical files of
1829
1841
* a relation. Without that, some other backend might try to do a
1830
1842
* blind write of a buffer page (relying on the BlindId of the buffer)
1831
1843
* and fail because it's not got the right filename anymore.
1832
1844
*
1833
- * In both cases, the caller should be holding AccessExclusiveLock on
1845
+ * In all cases, the caller should be holding AccessExclusiveLock on
1834
1846
* the target relation to ensure that no other backend is busy reading
1835
1847
* more blocks of the relation.
1836
1848
*
1837
- * Formerly, we considered it an error condition if we found unexpectedly
1838
- * dirty buffers. However, since BufferSync no longer forces out all
1849
+ * Formerly, we considered it an error condition if we found dirty
1850
+ * buffers here . However, since BufferSync no longer forces out all
1839
1851
* dirty buffers at every xact commit, it's possible for dirty buffers
1840
1852
* 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.
1843
1854
*
1844
1855
* Returns: 0 - Ok, -1 - FAILED TO WRITE DIRTY BUFFER, -2 - PINNED
1845
1856
*
@@ -1848,8 +1859,9 @@ BufferPoolBlowaway()
1848
1859
* --------------------------------------------------------------------
1849
1860
*/
1850
1861
int
1851
- FlushRelationBuffers (Relation rel , BlockNumber block , bool expectDirty )
1862
+ FlushRelationBuffers (Relation rel , BlockNumber firstDelBlock )
1852
1863
{
1864
+ Oid relid = RelationGetRelid (rel );
1853
1865
int i ;
1854
1866
BufferDesc * buf ;
1855
1867
@@ -1858,31 +1870,29 @@ FlushRelationBuffers(Relation rel, BlockNumber block, bool expectDirty)
1858
1870
for (i = 0 ; i < NLocBuffer ; i ++ )
1859
1871
{
1860
1872
buf = & LocalBufferDescriptors [i ];
1861
- if (buf -> tag .relId .relId == RelationGetRelid (rel ) &&
1862
- buf -> tag .blockNum >= block )
1873
+ if (buf -> tag .relId .relId == relid )
1863
1874
{
1864
1875
if (buf -> flags & BM_DIRTY )
1865
1876
{
1866
- if (!expectDirty )
1867
- elog (NOTICE , "FlushRelationBuffers(%s (local), %u): block %u is dirty" ,
1868
- RelationGetRelationName (rel ),
1869
- block , buf -> tag .blockNum );
1870
1877
if (FlushBuffer (- i - 1 , false) != STATUS_OK )
1871
1878
{
1872
1879
elog (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 );
1875
1882
return -1 ;
1876
1883
}
1877
1884
}
1878
1885
if (LocalRefCount [i ] > 0 )
1879
1886
{
1880
1887
elog (NOTICE , "FlushRelationBuffers(%s (local), %u): block %u is referenced (%ld)" ,
1881
- RelationGetRelationName (rel ), block ,
1888
+ RelationGetRelationName (rel ), firstDelBlock ,
1882
1889
buf -> tag .blockNum , LocalRefCount [i ]);
1883
1890
return -2 ;
1884
1891
}
1885
- buf -> tag .relId .relId = InvalidOid ;
1892
+ if (buf -> tag .blockNum >= firstDelBlock )
1893
+ {
1894
+ buf -> tag .relId .relId = InvalidOid ;
1895
+ }
1886
1896
}
1887
1897
}
1888
1898
return 0 ;
@@ -1891,26 +1901,20 @@ FlushRelationBuffers(Relation rel, BlockNumber block, bool expectDirty)
1891
1901
SpinAcquire (BufMgrLock );
1892
1902
for (i = 0 ; i < NBuffers ; i ++ )
1893
1903
{
1894
- recheck :
1895
1904
buf = & BufferDescriptors [i ];
1896
- if (buf -> tag .relId .relId == RelationGetRelid (rel ) &&
1905
+ recheck :
1906
+ if (buf -> tag .relId .relId == relid &&
1897
1907
(buf -> tag .relId .dbId == MyDatabaseId ||
1898
- buf -> tag .relId .dbId == (Oid ) NULL ) &&
1899
- buf -> tag .blockNum >= block )
1908
+ buf -> tag .relId .dbId == (Oid ) NULL ))
1900
1909
{
1901
1910
if (buf -> flags & BM_DIRTY )
1902
1911
{
1903
1912
PinBuffer (buf );
1904
1913
SpinRelease (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 );
1910
1914
if (FlushBuffer (i + 1 , true) != STATUS_OK )
1911
1915
{
1912
1916
elog (NOTICE , "FlushRelationBuffers(%s, %u): block %u is dirty (private %ld, global %d), could not flush it" ,
1913
- RelationGetRelationName (rel ), block ,
1917
+ RelationGetRelationName (rel ), firstDelBlock ,
1914
1918
buf -> tag .blockNum ,
1915
1919
PrivateRefCount [i ], buf -> refcount );
1916
1920
return -1 ;
@@ -1927,12 +1931,15 @@ FlushRelationBuffers(Relation rel, BlockNumber block, bool expectDirty)
1927
1931
{
1928
1932
SpinRelease (BufMgrLock );
1929
1933
elog (NOTICE , "FlushRelationBuffers(%s, %u): block %u is referenced (private %ld, global %d)" ,
1930
- RelationGetRelationName (rel ), block ,
1934
+ RelationGetRelationName (rel ), firstDelBlock ,
1931
1935
buf -> tag .blockNum ,
1932
1936
PrivateRefCount [i ], buf -> refcount );
1933
1937
return -2 ;
1934
1938
}
1935
- BufTableDelete (buf );
1939
+ if (buf -> tag .blockNum >= firstDelBlock )
1940
+ {
1941
+ BufTableDelete (buf );
1942
+ }
1936
1943
}
1937
1944
}
1938
1945
SpinRelease (BufMgrLock );
0 commit comments