PHP is not exactly well known for its code quality (and I mean the interpreter, C code, not the canonically bad user-written PHP code). I think working with FreeBSD code spoiled me to expect more :)
One "interesting" side of it is that even now, years after FastCGI has become the way to deploy PHP in production for any non-trivial sites, the most popular opcode / shared memory cache, the APC is broken in the way it handles this situation. Instead of actually sharing memory, it allocates new "shared" memory (sysv shm or mmap) for each process, thus preventing any sharing. And the bug basically has a "wontfix" status during all these years.
Well, I'm hereby declaring I'm officially sick of it and am hereby providing a 100-line patch for the situation.
This (very simple) patch basically forces every instance to mmap the same file to the same address. This will work only if there is one APC shared memory segment (the default situation), with the only inconvenience being finding a memory region to mmap the file to (must be the same for all processes).
On my 64-bit FreeBSD dev machine it works with these settings:
The crucial settings are:
- apc.mmap_address - the new behaviour will be activated only if this value is non-zero. It is a direct memory address to use for mmaping the shared memory region (whose size is configured as shm_size MB). This value I've given is in the middle of FreeBSD user process address space for 64-bit installations - other operating systems might (or might not) use different values. A good value for 32-bit processes might be 1073741823. The actual address here doesn't matter as long as it's unused and page-aligned. This is not an evil hack, the VM system will work around this mmaped region.
- apc.mmap_file_mask - this is the filename of the file to use in mmap(). If mmap_address is non-zero, this will be interpreted as an exact, absolute filename. I've so far tested it with a pre-created file (dd if=/dev/zero of=/var/tmp/apc-mmap bs=1m count=128) but it should also auto-create files.
I am not sure how this will interact with APC's various locking modes. I think that both default modes (sysv semaphores and flock) are safe; I don't know if spinlocks are safe - it depends on if the spinlocks themselves are stored in the shm or somewhere too-clever.
It is also somewhat tricky in case of data corruption. If a PHP or APC bug corrupts the shared memory region, it is not enough to restart the web server (as before), but also to delete the mmaped file before the server (and any php-cgi processes) is started.
The whole thing can be easily modified to support more shm segments but it works for now and we'll see if PHP developers will accept this kind of a patch in the first place (APC conflicts with their commercial Zend Accelerator product).