7
7
*
8
8
*
9
9
* IDENTIFICATION
10
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.66 1999/11/16 04:13:56 momjian Exp $
10
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.67 1999/11/22 01:19:42 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
@@ -1056,8 +1056,13 @@ BufferSync()
1056
1056
1057
1057
1058
1058
/*
1059
- * WaitIO -- Block until the IO_IN_PROGRESS flag on 'buf'
1060
- * is cleared. Because IO_IN_PROGRESS conflicts are
1059
+ * WaitIO -- Block until the IO_IN_PROGRESS flag on 'buf' is cleared.
1060
+ *
1061
+ * Should be entered with buffer manager spinlock held; releases it before
1062
+ * waiting and re-acquires it afterwards.
1063
+ *
1064
+ * OLD NOTES:
1065
+ * Because IO_IN_PROGRESS conflicts are
1061
1066
* expected to be rare, there is only one BufferIO
1062
1067
* lock in the entire system. All processes block
1063
1068
* on this semaphore when they try to use a buffer
@@ -1069,15 +1074,13 @@ BufferSync()
1069
1074
* is simple, but efficient enough if WaitIO is
1070
1075
* rarely called by multiple processes simultaneously.
1071
1076
*
1072
- * ProcSleep atomically releases the spinlock and goes to
1073
- * sleep.
1074
- *
1075
- * Note: there is an easy fix if the queue becomes long.
1076
- * save the id of the buffer we are waiting for in
1077
- * the queue structure. That way signal can figure
1078
- * out which proc to wake up.
1077
+ * NEW NOTES:
1078
+ * The above is true only on machines without test-and-set
1079
+ * semaphores (which we hope are few, these days). On better
1080
+ * hardware, each buffer has a spinlock that we can wait on.
1079
1081
*/
1080
1082
#ifdef HAS_TEST_AND_SET
1083
+
1081
1084
static void
1082
1085
WaitIO (BufferDesc * buf , SPINLOCK spinlock )
1083
1086
{
@@ -1087,7 +1090,8 @@ WaitIO(BufferDesc *buf, SPINLOCK spinlock)
1087
1090
SpinAcquire (spinlock );
1088
1091
}
1089
1092
1090
- #else /* HAS_TEST_AND_SET */
1093
+ #else /* !HAS_TEST_AND_SET */
1094
+
1091
1095
IpcSemaphoreId WaitIOSemId ;
1092
1096
IpcSemaphoreId WaitCLSemId ;
1093
1097
@@ -1387,26 +1391,30 @@ RelationGetNumberOfBlocks(Relation relation)
1387
1391
*
1388
1392
* this function unmarks all the dirty pages of a relation
1389
1393
* in the buffer pool so that at the end of transaction
1390
- * these pages will not be flushed.
1394
+ * these pages will not be flushed. This is used when the
1395
+ * relation is about to be deleted. We assume that the caller
1396
+ * holds an exclusive lock on the relation, which should assure
1397
+ * that no new buffers will be acquired for the rel meanwhile.
1398
+ *
1391
1399
* XXX currently it sequentially searches the buffer pool, should be
1392
1400
* changed to more clever ways of searching.
1393
1401
* --------------------------------------------------------------------
1394
1402
*/
1395
1403
void
1396
1404
ReleaseRelationBuffers (Relation rel )
1397
1405
{
1406
+ Oid relid = RelationGetRelid (rel );
1407
+ bool holding = false;
1398
1408
int i ;
1399
- int holding = 0 ;
1400
1409
BufferDesc * buf ;
1401
1410
1402
1411
if (rel -> rd_myxactonly )
1403
1412
{
1404
1413
for (i = 0 ; i < NLocBuffer ; i ++ )
1405
1414
{
1406
1415
buf = & LocalBufferDescriptors [i ];
1407
- if ((buf -> flags & BM_DIRTY ) &&
1408
- (buf -> tag .relId .relId == RelationGetRelid (rel )))
1409
- buf -> flags &= ~BM_DIRTY ;
1416
+ if (buf -> tag .relId .relId == relid )
1417
+ buf -> flags &= ~ ( BM_DIRTY | BM_JUST_DIRTIED );
1410
1418
}
1411
1419
return ;
1412
1420
}
@@ -1417,21 +1425,47 @@ ReleaseRelationBuffers(Relation rel)
1417
1425
if (!holding )
1418
1426
{
1419
1427
SpinAcquire (BufMgrLock );
1420
- holding = 1 ;
1428
+ holding = true ;
1421
1429
}
1422
- if (( buf -> flags & BM_DIRTY ) &&
1423
- (buf -> tag .relId .dbId == MyDatabaseId ) &&
1424
- ( buf -> tag .relId .relId == RelationGetRelid ( rel )) )
1430
+ recheck :
1431
+ if (buf -> tag .relId .dbId == MyDatabaseId &&
1432
+ buf -> tag .relId .relId == relid )
1425
1433
{
1426
- buf -> flags &= ~BM_DIRTY ;
1434
+ /*
1435
+ * If there is I/O in progress, better wait till it's done;
1436
+ * don't want to delete the relation out from under someone
1437
+ * who's just trying to flush the buffer!
1438
+ */
1439
+ if (buf -> flags & BM_IO_IN_PROGRESS )
1440
+ {
1441
+ WaitIO (buf , BufMgrLock );
1442
+ /* By now, the buffer very possibly belongs to some other
1443
+ * rel, so check again before proceeding.
1444
+ */
1445
+ goto recheck ;
1446
+ }
1447
+ /* Now we can do what we came for */
1448
+ buf -> flags &= ~ ( BM_DIRTY | BM_JUST_DIRTIED );
1449
+ CommitInfoNeedsSave [i - 1 ] = 0 ;
1450
+ /*
1451
+ * Release any refcount we may have.
1452
+ *
1453
+ * This is very probably dead code, and if it isn't then it's
1454
+ * probably wrong. I added the Assert to find out --- tgl 11/99.
1455
+ */
1427
1456
if (!(buf -> flags & BM_FREE ))
1428
1457
{
1458
+ /* Assert checks that buffer will actually get freed! */
1459
+ Assert (PrivateRefCount [i - 1 ] == 1 &&
1460
+ buf -> refcount == 1 );
1461
+ /* ReleaseBuffer expects we do not hold the lock at entry */
1429
1462
SpinRelease (BufMgrLock );
1430
- holding = 0 ;
1463
+ holding = false ;
1431
1464
ReleaseBuffer (i );
1432
1465
}
1433
1466
}
1434
1467
}
1468
+
1435
1469
if (holding )
1436
1470
SpinRelease (BufMgrLock );
1437
1471
}
0 commit comments