1313 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
1414 * Portions Copyright (c) 1994, Regents of the University of California
1515 *
16- * $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.3 2001/08/26 16:55:59 tgl Exp $
16+ * $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.4 2001/09/29 04:02:21 tgl Exp $
1717 *
1818 *-------------------------------------------------------------------------
1919 */
2727#include <unistd.h>
2828
2929#include "access/clog.h"
30- #include "storage/s_lock .h"
30+ #include "storage/lwlock .h"
3131#include "miscadmin.h"
3232
3333
7474 * The management algorithm is straight LRU except that we will never swap
7575 * out the latest page (since we know it's going to be hit again eventually).
7676 *
77- * We use an overallspinlock to protect the shared data structures, plus
78- * per-bufferspinlocks that synchronize I/O for each buffer. A process
77+ * We use an overallLWLock to protect the shared data structures, plus
78+ * per-bufferLWLocks that synchronize I/O for each buffer. A process
7979 * that is reading in or writing out a page buffer does not hold the control
8080 * lock, only the per-buffer lock for the buffer it is working on.
8181 *
105105 * by setting the page's state from WRITE_IN_PROGRESS to DIRTY. The writing
106106 * process must notice this and not mark the page CLEAN when it's done.
107107 *
108- * XXX it's probably okay to use a spinlock for the control lock, since
109- * that lock is only held for very short operations. It'd be nice to use
110- * some other form of lock for the per-buffer I/O locks, however.
111- *
112108 * XLOG interactions: this module generates an XLOG record whenever a new
113109 * CLOG page is initialized to zeroes. Other writes of CLOG come from
114110 * recording of transaction commit or abort in xact.c, which generates its
121117 * synchronization already.
122118 *----------
123119 */
124- #define NUM_CLOG_BUFFERS 8
125120
126121typedef enum
127122{
@@ -153,13 +148,17 @@ typedef struct ClogCtlData
153148 * swapping out the latest page.
154149 */
155150int latest_page_number ;
156-
157- slock_t control_lck ;/* Lock for ClogCtlData itself */
158- slock_t buffer_lck [NUM_CLOG_BUFFERS ];/* Per-buffer I/O locks */
159151}ClogCtlData ;
160152
161153static ClogCtlData * ClogCtl = NULL ;
162154
155+ /*
156+ * ClogBufferLocks is set during CLOGShmemInit and does not change thereafter.
157+ * The value is automatically inherited by backends via fork, and
158+ * doesn't need to be in shared memory.
159+ */
160+ static LWLockId ClogBufferLocks [NUM_CLOG_BUFFERS ];/* Per-buffer I/O locks */
161+
163162/*
164163 * ClogDir is set during CLOGShmemInit and does not change thereafter.
165164 * The value is automatically inherited by backends via fork, and
@@ -211,7 +210,7 @@ TransactionIdSetStatus(TransactionId xid, XidStatus status)
211210Assert (status == TRANSACTION_STATUS_COMMITTED ||
212211status == TRANSACTION_STATUS_ABORTED );
213212
214- S_LOCK ( & ( ClogCtl -> control_lck ) );
213+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
215214
216215slotno = ReadCLOGPage (pageno );
217216byteptr = ClogCtl -> page_buffer [slotno ]+ byteno ;
@@ -224,7 +223,7 @@ TransactionIdSetStatus(TransactionId xid, XidStatus status)
224223
225224ClogCtl -> page_status [slotno ]= CLOG_PAGE_DIRTY ;
226225
227- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
226+ LWLockRelease ( CLogControlLock );
228227}
229228
230229/*
@@ -243,14 +242,14 @@ TransactionIdGetStatus(TransactionId xid)
243242char * byteptr ;
244243XidStatus status ;
245244
246- S_LOCK ( & ( ClogCtl -> control_lck ) );
245+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
247246
248247slotno = ReadCLOGPage (pageno );
249248byteptr = ClogCtl -> page_buffer [slotno ]+ byteno ;
250249
251250status = (* byteptr >>bshift )& CLOG_XACT_BITMASK ;
252251
253- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
252+ LWLockRelease ( CLogControlLock );
254253
255254return status ;
256255}
@@ -283,15 +282,13 @@ CLOGShmemInit(void)
283282
284283memset (ClogCtl ,0 ,sizeof (ClogCtlData ));
285284
286- S_INIT_LOCK (& (ClogCtl -> control_lck ));
287-
288285bufptr = ((char * )ClogCtl )+ sizeof (ClogCtlData );
289286
290287for (slotno = 0 ;slotno < NUM_CLOG_BUFFERS ;slotno ++ )
291288{
292289ClogCtl -> page_buffer [slotno ]= bufptr ;
293290ClogCtl -> page_status [slotno ]= CLOG_PAGE_EMPTY ;
294- S_INIT_LOCK ( & ( ClogCtl -> buffer_lck [slotno ]) );
291+ ClogBufferLocks [slotno ]= LWLockAssign ( );
295292bufptr += CLOG_BLCKSZ ;
296293}
297294
@@ -312,7 +309,7 @@ BootStrapCLOG(void)
312309{
313310int slotno ;
314311
315- S_LOCK ( & ( ClogCtl -> control_lck ) );
312+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
316313
317314/* Create and zero the first page of the commit log */
318315slotno = ZeroCLOGPage (0 , false);
@@ -321,7 +318,7 @@ BootStrapCLOG(void)
321318WriteCLOGPage (slotno );
322319Assert (ClogCtl -> page_status [slotno ]== CLOG_PAGE_CLEAN );
323320
324- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
321+ LWLockRelease ( CLogControlLock );
325322}
326323
327324/*
@@ -411,8 +408,8 @@ ReadCLOGPage(int pageno)
411408ClogCtl -> page_lru_count [slotno ]= 0 ;
412409
413410/* Release shared lock, grab per-buffer lock instead */
414- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
415- S_LOCK ( & ( ClogCtl -> buffer_lck [slotno ]) );
411+ LWLockRelease ( CLogControlLock );
412+ LWLockAcquire ( ClogBufferLocks [slotno ], LW_EXCLUSIVE );
416413
417414/*
418415 * Check to see if someone else already did the read, or took the
@@ -421,23 +418,23 @@ ReadCLOGPage(int pageno)
421418if (ClogCtl -> page_number [slotno ]!= pageno ||
422419ClogCtl -> page_status [slotno ]!= CLOG_PAGE_READ_IN_PROGRESS )
423420{
424- S_UNLOCK ( & ( ClogCtl -> buffer_lck [slotno ]) );
425- S_LOCK ( & ( ClogCtl -> control_lck ) );
421+ LWLockRelease ( ClogBufferLocks [slotno ]);
422+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
426423continue ;
427424}
428425
429426/* Okay, do the read */
430427CLOGPhysicalReadPage (pageno ,slotno );
431428
432429/* Re-acquire shared control lock and update page state */
433- S_LOCK ( & ( ClogCtl -> control_lck ) );
430+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
434431
435432Assert (ClogCtl -> page_number [slotno ]== pageno &&
436433ClogCtl -> page_status [slotno ]== CLOG_PAGE_READ_IN_PROGRESS );
437434
438435ClogCtl -> page_status [slotno ]= CLOG_PAGE_CLEAN ;
439436
440- S_UNLOCK ( & ( ClogCtl -> buffer_lck [slotno ]) );
437+ LWLockRelease ( ClogBufferLocks [slotno ]);
441438
442439ClogRecentlyUsed (slotno );
443440return slotno ;
@@ -468,8 +465,8 @@ WriteCLOGPage(int slotno)
468465pageno = ClogCtl -> page_number [slotno ];
469466
470467/* Release shared lock, grab per-buffer lock instead */
471- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
472- S_LOCK ( & ( ClogCtl -> buffer_lck [slotno ]) );
468+ LWLockRelease ( CLogControlLock );
469+ LWLockAcquire ( ClogBufferLocks [slotno ], LW_EXCLUSIVE );
473470
474471/*
475472 * Check to see if someone else already did the write, or took the
@@ -482,8 +479,8 @@ WriteCLOGPage(int slotno)
482479(ClogCtl -> page_status [slotno ]!= CLOG_PAGE_DIRTY &&
483480ClogCtl -> page_status [slotno ]!= CLOG_PAGE_WRITE_IN_PROGRESS ))
484481{
485- S_UNLOCK ( & ( ClogCtl -> buffer_lck [slotno ]) );
486- S_LOCK ( & ( ClogCtl -> control_lck ) );
482+ LWLockRelease ( ClogBufferLocks [slotno ]);
483+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
487484return ;
488485}
489486
@@ -504,7 +501,7 @@ WriteCLOGPage(int slotno)
504501CLOGPhysicalWritePage (pageno ,slotno );
505502
506503/* Re-acquire shared control lock and update page state */
507- S_LOCK ( & ( ClogCtl -> control_lck ) );
504+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
508505
509506Assert (ClogCtl -> page_number [slotno ]== pageno &&
510507 (ClogCtl -> page_status [slotno ]== CLOG_PAGE_WRITE_IN_PROGRESS ||
@@ -514,7 +511,7 @@ WriteCLOGPage(int slotno)
514511if (ClogCtl -> page_status [slotno ]== CLOG_PAGE_WRITE_IN_PROGRESS )
515512ClogCtl -> page_status [slotno ]= CLOG_PAGE_CLEAN ;
516513
517- S_UNLOCK ( & ( ClogCtl -> buffer_lck [slotno ]) );
514+ LWLockRelease ( ClogBufferLocks [slotno ]);
518515}
519516
520517/*
@@ -714,7 +711,7 @@ ShutdownCLOG(void)
714711{
715712int slotno ;
716713
717- S_LOCK ( & ( ClogCtl -> control_lck ) );
714+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
718715
719716for (slotno = 0 ;slotno < NUM_CLOG_BUFFERS ;slotno ++ )
720717{
@@ -723,7 +720,7 @@ ShutdownCLOG(void)
723720ClogCtl -> page_status [slotno ]== CLOG_PAGE_CLEAN );
724721}
725722
726- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
723+ LWLockRelease ( CLogControlLock );
727724}
728725
729726/*
@@ -734,7 +731,7 @@ CheckPointCLOG(void)
734731{
735732int slotno ;
736733
737- S_LOCK ( & ( ClogCtl -> control_lck ) );
734+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
738735
739736for (slotno = 0 ;slotno < NUM_CLOG_BUFFERS ;slotno ++ )
740737{
@@ -745,7 +742,7 @@ CheckPointCLOG(void)
745742 */
746743}
747744
748- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
745+ LWLockRelease ( CLogControlLock );
749746}
750747
751748
@@ -772,12 +769,12 @@ ExtendCLOG(TransactionId newestXact)
772769
773770pageno = TransactionIdToPage (newestXact );
774771
775- S_LOCK ( & ( ClogCtl -> control_lck ) );
772+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
776773
777774/* Zero the page and make an XLOG entry about it */
778775ZeroCLOGPage (pageno , true);
779776
780- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
777+ LWLockRelease ( CLogControlLock );
781778}
782779
783780
@@ -819,7 +816,7 @@ TruncateCLOG(TransactionId oldestXact)
819816 * should have been flushed already during the checkpoint, we're
820817 * just being extra careful here.)
821818 */
822- S_LOCK ( & ( ClogCtl -> control_lck ) );
819+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
823820
824821restart :;
825822/*
@@ -830,7 +827,7 @@ restart:;
830827 */
831828if (CLOGPagePrecedes (ClogCtl -> latest_page_number ,cutoffPage ))
832829{
833- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
830+ LWLockRelease ( CLogControlLock );
834831elog (LOG ,"unable to truncate commit log: apparent wraparound" );
835832return ;
836833}
@@ -861,7 +858,7 @@ restart:;
861858gotorestart ;
862859}
863860
864- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
861+ LWLockRelease ( CLogControlLock );
865862
866863/* Now we can remove the old CLOG segment(s) */
867864(void )ScanCLOGDirectory (cutoffPage , true);
@@ -974,13 +971,13 @@ clog_redo(XLogRecPtr lsn, XLogRecord *record)
974971
975972memcpy (& pageno ,XLogRecGetData (record ),sizeof (int ));
976973
977- S_LOCK ( & ( ClogCtl -> control_lck ) );
974+ LWLockAcquire ( CLogControlLock , LW_EXCLUSIVE );
978975
979976slotno = ZeroCLOGPage (pageno , false);
980977WriteCLOGPage (slotno );
981978Assert (ClogCtl -> page_status [slotno ]== CLOG_PAGE_CLEAN );
982979
983- S_UNLOCK ( & ( ClogCtl -> control_lck ) );
980+ LWLockRelease ( CLogControlLock );
984981}
985982}
986983