Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 7f60b81

Browse files
committed
Fix failure in CreateCheckPoint on some Alpha boxes --- it's not OK to
assume that TAS() will always succeed the first time, even if the lock is known to be free. Also, make sure that code will eventually time out and report a stuck spinlock, rather than looping forever. Small cleanups in s_lock.h, too.
1 parent 7d363c4 commit 7f60b81

File tree

4 files changed

+194
-177
lines changed

4 files changed

+194
-177
lines changed

src/backend/access/transam/xlog.c

Lines changed: 27 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.45 2000/12/28 13:00:08 vadim Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.46 2000/12/29 21:31:21 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -411,7 +411,7 @@ begin:;
411411
}
412412
}
413413
}
414-
s_lock_sleep(i++);
414+
S_LOCK_SLEEP(&(XLogCtl->insert_lck), i++);
415415
if (!TAS(&(XLogCtl->insert_lck)))
416416
break;
417417
}
@@ -599,17 +599,10 @@ begin:;
599599

600600
if (updrqst)
601601
{
602-
for (;;)
603-
{
604-
if (!TAS(&(XLogCtl->info_lck)))
605-
{
606-
if (XLByteLT(XLogCtl->LgwrRqst.Write, LgwrRqst.Write))
607-
XLogCtl->LgwrRqst.Write = LgwrRqst.Write;
608-
S_UNLOCK(&(XLogCtl->info_lck));
609-
break;
610-
}
611-
s_lock_sleep(i++);
612-
}
602+
S_LOCK(&(XLogCtl->info_lck));
603+
if (XLByteLT(XLogCtl->LgwrRqst.Write, LgwrRqst.Write))
604+
XLogCtl->LgwrRqst.Write = LgwrRqst.Write;
605+
S_UNLOCK(&(XLogCtl->info_lck));
613606
}
614607

615608
END_CRIT_CODE;
@@ -622,7 +615,7 @@ XLogFlush(XLogRecPtr record)
622615
XLogRecPtr WriteRqst;
623616
char buffer[BLCKSZ];
624617
char *usebuf = NULL;
625-
unsigned i = 0;
618+
unsigned spins = 0;
626619
bool force_lgwr = false;
627620

628621
if (XLOG_DEBUG)
@@ -715,7 +708,7 @@ XLogFlush(XLogRecPtr record)
715708
break;
716709
}
717710
}
718-
s_lock_sleep(i++);
711+
S_LOCK_SLEEP(&(XLogCtl->lgwr_lck), spins++);
719712
}
720713

721714
if (logFile >= 0 && (LgwrResult.Write.xlogid != logId ||
@@ -740,18 +733,12 @@ XLogFlush(XLogRecPtr record)
740733
logId, logSeg);
741734
LgwrResult.Flush = LgwrResult.Write;
742735

743-
for (i = 0;;)
744-
{
745-
if (!TAS(&(XLogCtl->info_lck)))
746-
{
747-
XLogCtl->LgwrResult = LgwrResult;
748-
if (XLByteLT(XLogCtl->LgwrRqst.Write, LgwrResult.Write))
749-
XLogCtl->LgwrRqst.Write = LgwrResult.Write;
750-
S_UNLOCK(&(XLogCtl->info_lck));
751-
break;
752-
}
753-
s_lock_sleep(i++);
754-
}
736+
S_LOCK(&(XLogCtl->info_lck));
737+
XLogCtl->LgwrResult = LgwrResult;
738+
if (XLByteLT(XLogCtl->LgwrRqst.Write, LgwrResult.Write))
739+
XLogCtl->LgwrRqst.Write = LgwrResult.Write;
740+
S_UNLOCK(&(XLogCtl->info_lck));
741+
755742
XLogCtl->Write.LgwrResult = LgwrResult;
756743

757744
S_UNLOCK(&(XLogCtl->lgwr_lck));
@@ -767,6 +754,7 @@ GetFreeXLBuffer()
767754
XLogCtlInsert *Insert = &XLogCtl->Insert;
768755
XLogCtlWrite *Write = &XLogCtl->Write;
769756
uint16 curridx = NextBufIdx(Insert->curridx);
757+
unsigned spins = 0;
770758

771759
LgwrRqst.Write = XLogCtl->xlblocks[Insert->curridx];
772760
for (;;)
@@ -809,9 +797,8 @@ GetFreeXLBuffer()
809797
InitXLBuffer(curridx);
810798
return;
811799
}
800+
S_LOCK_SLEEP(&(XLogCtl->lgwr_lck), spins++);
812801
}
813-
814-
return;
815802
}
816803

817804
static void
@@ -820,7 +807,6 @@ XLogWrite(char *buffer)
820807
XLogCtlWrite *Write = &XLogCtl->Write;
821808
char *from;
822809
uint32 wcnt = 0;
823-
int i = 0;
824810
bool usexistent;
825811

826812
for (; XLByteLT(LgwrResult.Write, LgwrRqst.Write);)
@@ -919,18 +905,12 @@ XLogWrite(char *buffer)
919905
LgwrResult.Flush = LgwrResult.Write;
920906
}
921907

922-
for (;;)
923-
{
924-
if (!TAS(&(XLogCtl->info_lck)))
925-
{
926-
XLogCtl->LgwrResult = LgwrResult;
927-
if (XLByteLT(XLogCtl->LgwrRqst.Write, LgwrResult.Write))
928-
XLogCtl->LgwrRqst.Write = LgwrResult.Write;
929-
S_UNLOCK(&(XLogCtl->info_lck));
930-
break;
931-
}
932-
s_lock_sleep(i++);
933-
}
908+
S_LOCK(&(XLogCtl->info_lck));
909+
XLogCtl->LgwrResult = LgwrResult;
910+
if (XLByteLT(XLogCtl->LgwrRqst.Write, LgwrResult.Write))
911+
XLogCtl->LgwrRqst.Write = LgwrResult.Write;
912+
S_UNLOCK(&(XLogCtl->info_lck));
913+
934914
Write->LgwrResult = LgwrResult;
935915
}
936916

@@ -2062,18 +2042,17 @@ CreateCheckPoint(bool shutdown)
20622042
uint32 _logId;
20632043
uint32 _logSeg;
20642044
char archdir[MAXPGPATH];
2045+
unsigned spins = 0;
20652046

20662047
if (MyLastRecPtr.xrecoff != 0)
20672048
elog(ERROR, "CreateCheckPoint: cannot be called inside transaction block");
20682049

20692050
START_CRIT_CODE;
2051+
2052+
/* Grab lock, using larger than normal sleep between tries (1 sec) */
20702053
while (TAS(&(XLogCtl->chkp_lck)))
20712054
{
2072-
struct timeval delay = {2, 0};
2073-
2074-
if (shutdown)
2075-
elog(STOP, "Checkpoint lock is busy while data base is shutting down");
2076-
(void) select(0, NULL, NULL, NULL, &delay);
2055+
S_LOCK_SLEEP_INTERVAL(&(XLogCtl->chkp_lck), spins++, 1000000);
20772056
}
20782057

20792058
memset(&checkPoint, 0, sizeof(checkPoint));
@@ -2087,14 +2066,7 @@ CreateCheckPoint(bool shutdown)
20872066
checkPoint.Shutdown = shutdown;
20882067

20892068
/* Get REDO record ptr */
2090-
while (TAS(&(XLogCtl->insert_lck)))
2091-
{
2092-
struct timeval delay = {1, 0};
2093-
2094-
if (shutdown)
2095-
elog(STOP, "XLog insert lock is busy while data base is shutting down");
2096-
(void) select(0, NULL, NULL, NULL, &delay);
2097-
}
2069+
S_LOCK(&(XLogCtl->insert_lck));
20982070
freespace = ((char *) Insert->currpage) + BLCKSZ - Insert->currpos;
20992071
if (freespace < SizeOfXLogRecord)
21002072
{

src/backend/storage/buffer/bufmgr.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.100 2000/12/28 13:00:21 vadim Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.101 2000/12/29 21:31:21 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1987,7 +1987,7 @@ LockBuffer(Buffer buffer, int mode)
19871987
while (buf->ri_lock || buf->w_lock)
19881988
{
19891989
S_UNLOCK(&(buf->cntx_lock));
1990-
s_lock_sleep(i++);
1990+
S_LOCK_SLEEP(&(buf->cntx_lock), i++);
19911991
S_LOCK(&(buf->cntx_lock));
19921992
}
19931993
(buf->r_locks)++;
@@ -2013,7 +2013,7 @@ LockBuffer(Buffer buffer, int mode)
20132013
buf->ri_lock = true;
20142014
}
20152015
S_UNLOCK(&(buf->cntx_lock));
2016-
s_lock_sleep(i++);
2016+
S_LOCK_SLEEP(&(buf->cntx_lock), i++);
20172017
S_LOCK(&(buf->cntx_lock));
20182018
}
20192019
buf->w_lock = true;

src/backend/storage/buffer/s_lock.c

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.27 2000/12/11 00:49:51 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.28 2000/12/29 21:31:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -25,19 +25,21 @@
2525
* number of microseconds to wait. This accomplishes pseudo random back-off.
2626
* Values are not critical but 10 milliseconds is a common platform
2727
* granularity.
28-
* note: total time to cycle through all 16 entries might be about .07 sec.
28+
*
29+
* Total time to cycle through all 20 entries might be about .07 sec,
30+
* so the given value of S_MAX_BUSY results in timeout after ~70 sec.
2931
*/
3032
#define S_NSPINCYCLE 20
3133
#define S_MAX_BUSY 1000 * S_NSPINCYCLE
3234

3335
int s_spincycle[S_NSPINCYCLE] =
34-
{0, 0, 0, 0, 10000, 0, 0, 0, 10000, 0,
36+
{ 0, 0, 0, 0, 10000, 0, 0, 0, 10000, 0,
3537
0, 10000, 0, 0, 10000, 0, 10000, 0, 10000, 10000
3638
};
3739

3840

3941
/*
40-
* s_lock_stuck(lock) - complain about a stuck spinlock
42+
* s_lock_stuck() - complain about a stuck spinlock
4143
*/
4244
static void
4345
s_lock_stuck(volatile slock_t *lock, const char *file, const int line)
@@ -52,13 +54,38 @@ s_lock_stuck(volatile slock_t *lock, const char *file, const int line)
5254
}
5355

5456

57+
/*
58+
* s_lock_sleep() - sleep a pseudo-random amount of time, check for timeout
59+
*
60+
* Normally 'microsec' is 0, specifying to use the next s_spincycle[] value.
61+
* Some callers may pass a nonzero interval, specifying to use exactly that
62+
* delay value rather than a pseudo-random delay.
63+
*/
5564
void
56-
s_lock_sleep(unsigned spin)
65+
s_lock_sleep(unsigned spins, int microsec,
66+
volatile slock_t *lock,
67+
const char *file, const int line)
5768
{
5869
struct timeval delay;
70+
unsigned max_spins;
71+
72+
if (microsec > 0)
73+
{
74+
delay.tv_sec = 0;
75+
delay.tv_usec = microsec;
76+
/* two-minute timeout in this case */
77+
max_spins = 120000000 / microsec;
78+
}
79+
else
80+
{
81+
delay.tv_sec = 0;
82+
delay.tv_usec = s_spincycle[spins % S_NSPINCYCLE];
83+
max_spins = S_MAX_BUSY;
84+
}
85+
86+
if (spins > max_spins)
87+
s_lock_stuck(lock, file, line);
5988

60-
delay.tv_sec = 0;
61-
delay.tv_usec = s_spincycle[spin % S_NSPINCYCLE];
6289
(void) select(0, NULL, NULL, NULL, &delay);
6390
}
6491

@@ -71,14 +98,13 @@ s_lock(volatile slock_t *lock, const char *file, const int line)
7198
{
7299
unsigned spins = 0;
73100

101+
/*
102+
* If you are thinking of changing this code, be careful. This same
103+
* loop logic is used in other places that call TAS() directly.
104+
*/
74105
while (TAS(lock))
75106
{
76-
s_lock_sleep(spins);
77-
if (++spins > S_MAX_BUSY)
78-
{
79-
/* It's been over a minute... */
80-
s_lock_stuck(lock, file, line);
81-
}
107+
s_lock_sleep(spins++, 0, lock, file, line);
82108
}
83109
}
84110

0 commit comments

Comments
 (0)