Categories
Programming Web Development

PHP 5.3.4 Changes rand(), Filled My Error Log, Spikes Load

I ran into a peculiar situation with a PHP web application that went from working for several years without incident to suddenly resulting in timeouts and spiking the load on my server. Some investigation traced it back to a seemingly benign and obscure change to PHP’s rand() implementation between 5.3.3 and 5.3.4.

To summarize several hundred lines of code: it gets a value from an array where the index is a random number between X and Y. X and Y are highly unpredictable by nature of the application. It keeps trying with different values until something is returned. Something like:

function random($a, $b){
   if(MT_RAND){
       return mt_rand($a, $b);
   }
   return rand($a, $b);
}
 
$x = 0;
while($x == 0){
    $x = $arr[random($x, $y)];
}
return $x;

See it? If you don’t, you shouldn’t feel bad, I didn’t see it initially either.

Prior to PHP 5.3.4 mt_/rand did not check if the max is greater than the min. This has changed as a result of bug 46587. That 4 line change made an impact.

Take this example code:

print "right: " . mt_rand(1, 5) . "\n";
print "wrong: " . mt_rand(5, 1) . "\n";

In PHP 5.3.3 you’d get:

$ php test.php
right: 3
wrong: 4

$ php test.php
right: 2
wrong: 5

Despite the incorrect order of max/min it actually worked just fine. It had done so at least since PHP 4.3 (circa 2003) as far as I’m aware.

In PHP 5.3.4:

$ php test.php
right: 2
PHP Warning:  mt_rand(): max(1) is smaller than min(5) in /test/test.php on line 4
wrong: 

As a result, this while(){} never terminated until the timeout was reached.

The solution is obviously trivial once you actually trace this bug back:

function random($a, $b){
   
    // If a is greater, flip order
    if($a > $b){
        $tmp = $a;
        $a = $b;
        $b = $tmp;
   }
       
   if(MT_RAND){
       return mt_rand($a, $b);
   }
   return rand($a, $b);
}

This resulted in several GB’s worth of warnings in my error log in a matter of hours. You can also see how it (the brown area) dropped off once the fix was deployed as measured by % of wall clock time:

Transaction %

It’s the little things sometimes that cause all the trouble.

Categories
Programming

Getting A Random Row In MySQL

This is a great page on RAND() in MySQL. Very nice breakdown of how to gain performance with one of the biggest “it should be simple but it isn’t” problems in DBMS’s.

Categories
Software

Random Desktop Fun

Interesting question came today, and I thought I would hand code this one.

Want to display a random desktop on startup (Windows).

I decided on a Free, Open Source, simple, and HTML 4.01 Strict valid. It also has an option to reload on a defined interval, or just when loaded (boot time).

It’s released under typical MPL 1.1/GPL 2.0/LGPL 2.1 Tri License (FREE).

If you don’t like anything free, click here, and I will adjust it for you. 😉

Download Now (2 KB)