Hi,
There isn't a lot of talk about sempahores here, but I thought I'd give this a go, just in case someone out there has the answer to the question.
We have a high volume site (130K page views per day) that has, on average, five images for which we wish to track the impressions. Whenever the page is hit, a script is called to log the impression to a database (increments a counter) and then the script redirects to the image. At thisrate, we're getting an average of 7 impressions per second but when you consider that we get 1/2 of our traffic between 12pm and 5pm, our poor database is getting beat up.
So I devised a way to count the impressions to shared memory using semaphores so that things don't collide. Then, once a minute, another process will read from shared memory and write it to the database.
Here's the function that does all the work of writing to shared memory.
function shmem_impression($l_id) {
// $l_id is the id of the image (memory location) that we will be incrementing
// Set some variables
$shmem_addr = 1472; // Arbitrary number for semaphore and shmem address.
$max_acquire = 500; // We have 200+ processes serving webpages now.
// Get the semaphore. This is where we have a problem.
$sem_id = sem_get($shmem_addr, $max_acquire);
// If we have a semaphore ID, continue.
if ($sem_id) {
// acquire the semaphore to "lock" memory accesss.
if (sem_acquire($sem_id)) {
// Do the work. Attach to the shared memory
$shm_id = shm_attach($shmem_addr);
// Get the current number
if (!$var = @shm_get_var($shm_id, $l_id)) {
// Default to 0.
$var = 0;
}
// Increment
$var++;
// Save back to shared memory
shm_put_var($shm_id, $l_id, $var);
// Clean up and release the semaphore.
shm_detach($shm_id);
sem_release($sem_id);
}
}
}
The problem is that I am getting an error on the sem_get() function call, which is the last place I'd expect to see a problem. The error that I get is:
Warning: semop() failed acquiring SYSVSEM_SETVAL for key 0x5c0:
No space left on device in /export/home/www/ami-cms/docs/inc/select_ad.php on line 37
It should be noted that while I was writing this, I never saw this error. The code works perfectly, but when I place it under a high-load situation, the above error starts to appear a lot.
I'm not clear what device is out of space or why. My only guess is that I did not create my shared memory segment big enough to accomodate 200+ processes, but that's not where the script is failing. It's failing while trying to get the semaphore which is even before it tries to acquire the semaphore.
It is worth noting that sometimes the script fails and sometimes it doesn't. So it seems able to accomodate a certain number of processes, but not all of them at once.
Does anyone have any insight on this? I've scoured the web for information and I've even gone into the PHP source code to try to see what exactly is going on and I don't really have any answers at this point.
Implementation of this will, I hope, greatly improve the performance of my site by preventing the database from going to disk all the time.
Thank you for any information you may be able to provide.
--Joel