Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd5f7d2c

Browse files
committed
Adopt a random backoff algorithm for sleep delays when waiting for a
spinlock. Per recent pghackers discussion.
1 parenta667288 commitd5f7d2c

File tree

1 file changed

+53
-18
lines changed

1 file changed

+53
-18
lines changed

‎src/backend/storage/lmgr/s_lock.c

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/s_lock.c,v 1.14 2003/08/04 15:28:33 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/s_lock.c,v 1.15 2003/08/06 16:43:43 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -31,7 +31,7 @@ s_lock_stuck(volatile slock_t *lock, const char *file, int line)
3131
fprintf(stderr,
3232
"\nStuck spinlock (%p) detected at %s:%d.\n",
3333
lock,file,line);
34-
abort();
34+
exit(1);
3535
#else
3636
elog(PANIC,"stuck spinlock (%p) detected at %s:%d",
3737
lock,file,line);
@@ -45,35 +45,68 @@ s_lock_stuck(volatile slock_t *lock, const char *file, int line)
4545
void
4646
s_lock(volatileslock_t*lock,constchar*file,intline)
4747
{
48-
unsignedspins=0;
49-
unsigneddelays=0;
50-
structtimevaldelay;
51-
5248
/*
5349
* We loop tightly for awhile, then delay using select() and try
5450
* again. Preferably, "awhile" should be a small multiple of the
5551
* maximum time we expect a spinlock to be held. 100 iterations seems
56-
* about right.
52+
* about right. In most multi-CPU scenarios, the spinlock is probably
53+
* held by a process on another CPU and will be released before we
54+
* finish 100 iterations. However, on a uniprocessor, the tight loop
55+
* is just a waste of cycles, so don't iterate thousands of times.
56+
*
57+
* Once we do decide to block, we use randomly increasing select() delays.
58+
* The first delay is 10 msec, then the delay randomly increases to about
59+
* one second, after which we reset to 10 msec and start again. The idea
60+
* here is that in the presence of heavy contention we need to increase
61+
* the delay, else the spinlock holder may never get to run and release
62+
* the lock. (Consider situation where spinlock holder has been nice'd
63+
* down in priority by the scheduler --- it will not get scheduled until
64+
* all would-be acquirers are sleeping, so if we always use a 10-msec
65+
* sleep, there is a real possibility of starvation.) But we can't just
66+
* clamp the delay to an upper bound, else it would take a long time to
67+
* make a reasonable number of tries.
5768
*
58-
* We use a 10 millisec select delay because that is the lower limit on
59-
* many platforms.The timeout is figured on this delay only, and so
60-
* the nominal 1 minute is a lower bound.
69+
* We time out and declare error after NUM_DELAYS delays (thus, exactly
70+
* that many tries). With the given settings, this will usually take
71+
* 3 or so minutes. It seems better to fix the total number of tries (and
72+
* thus the probability of unintended failure) than to fix the total time
73+
* spent.
74+
*
75+
* The select() delays are measured in centiseconds (0.01 sec) because
76+
* 10 msec is a common resolution limit at the OS level.
6177
*/
6278
#defineSPINS_PER_DELAY100
63-
#defineDELAY_MSEC10
64-
#defineTIMEOUT_MSEC(60 * 1000)
79+
#defineNUM_DELAYS1000
80+
#defineMIN_DELAY_CSEC1
81+
#defineMAX_DELAY_CSEC100
82+
83+
intspins=0;
84+
intdelays=0;
85+
intcur_delay=MIN_DELAY_CSEC;
86+
structtimevaldelay;
6587

6688
while (TAS(lock))
6789
{
6890
if (++spins>SPINS_PER_DELAY)
6991
{
70-
if (++delays>(TIMEOUT_MSEC /DELAY_MSEC))
92+
if (++delays>NUM_DELAYS)
7193
s_lock_stuck(lock,file,line);
7294

73-
delay.tv_sec=0;
74-
delay.tv_usec=DELAY_MSEC*1000;
95+
delay.tv_sec=cur_delay /100;
96+
delay.tv_usec=(cur_delay %100)*10000;
7597
(void)select(0,NULL,NULL,NULL,&delay);
7698

99+
#if defined(S_LOCK_TEST)
100+
fprintf(stdout,"*");fflush(stdout);
101+
#endif
102+
103+
/* increase delay by a random fraction between 1X and 2X */
104+
cur_delay+= (int) (cur_delay*
105+
(((double)random()) / ((double)MAX_RANDOM_VALUE))+0.5);
106+
/* wrap back to minimum delay when max is exceeded */
107+
if (cur_delay>MAX_DELAY_CSEC)
108+
cur_delay=MIN_DELAY_CSEC;
109+
77110
spins=0;
78111
}
79112
}
@@ -217,6 +250,8 @@ volatile slock_t test_lock;
217250
int
218251
main()
219252
{
253+
srandom((unsignedint)time(NULL));
254+
220255
S_INIT_LOCK(&test_lock);
221256

222257
if (!S_LOCK_FREE(&test_lock))
@@ -249,9 +284,9 @@ main()
249284
return1;
250285
}
251286

252-
printf("S_LOCK_TEST: this willhang for a minute or soand then abort\n");
253-
printf(" with a 'stuck spinlock' message if S_LOCK()\n");
254-
printf(" and TAS() are working.\n");
287+
printf("S_LOCK_TEST: this willprint %d starsand then\n",NUM_DELAYS);
288+
printf("exitwith a 'stuck spinlock' message\n");
289+
printf("if S_LOCK()and TAS() are working.\n");
255290
fflush(stdout);
256291

257292
s_lock(&test_lock,__FILE__,__LINE__);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp