Download Documentation

Transcript
12
ANCILLARY CODE
12.7.3
316
A refined solution
The preceding approach seems fairly robust, but there is a major problem — if a
process locks a key generator and then dies, the generator is locked forever. We
therefore need a robust timeout. If all processes are accessing the same source of
a timestamp, here is one solution:
1. Lock the generator as above (assuming the initial value in uValueLockTxt
is the same as uValue), but write a timestamp (provided as $now) to uValueLock.26 This will cause subsequent attempts to fail nastily! But anyone
failing can now see when the value was set.
$count = 0;
$ok = 0;
while (! $ok && ($count < 1000))
{ $count ++;
$ok = TryDoSQL($handDB,
"UPDATE UIDS
SET uValueLock = ’$now’
WHERE uValue = cast(uValueLock AS INTEGER)",
’lock generator’);
Here’s the catch. Within the same loop, if we fail, check that the previous
person who grabbed control hasn’t died disgracefully. If this isn’t the case
(no time-out) then we delay and try again, but if the person has timed out,
we still grant them the increment (by doing it ourself), but reset uValueLock
to again make it accessible:
if (! ok)
{ ($timeout) = GetSQL($handDB,
"SELECT uValueLock FROM UIDS",
’get lock time’);
$delta = Julian($now) - Julian($timeout);
if ($delta > $MAXTIMEOUT)
{ DoSQL($handDB,
"UPDATE UIDS
SET uValueLock = cast(uValue+1 as varchar(32)),
uValue = uValue+1
WHERE uValueLock = ’$timeout’",
’restore function’);
} else
{ # here we might insert a random delay!
26
We assume that $now is an accurate timestamp, with a millisecond value and preferably a
microsecond value.