Daniel Popowich wrote:
The recent discussion of max locks and deadlocking issues with
_apache._global_(un)?lock() are timely for me:
I'm in the middle of writing a caching module for mod_python servlets
so a developer can have the output of a servlet cached, keyed on the
hash of the URI, for future requests. The goal, of course, is to
increase throughput for dynamic pages with long shelf life (e.g.,
content manager updates database once per day, so the HTML only needs
to be generated once per day, not per request).
I need locking. My first gut instinct was to go to the fcntl module
(lockf), but this is only available for unix. My second gut instinct
was: so what? :-)
Wanting a true x-platform tool I then thought of mod_python.Session
needing locks, poked around the code, and saw how it uses
_apache._global_lock(). Further poking around showed me how psp code
caching uses the function. About the time I began worrying about
deadlock issues I found the thread on this list discussing the same
problems.
The solution for Session and psp code caching is to explicitly use lock
id 0. This works as long as a module does not hold the lock for the
whole request, but unlocks immediately after acquiring the needed
resource. Fine.
Just to be clear, sessions use the locks above index 0 for session
locking. The session id is hashed to determine which index is used.
DbmSession uses lock index 0 to lock the dbm file for reading and
writing the persistent session data. This is independent of the session
lock.
So, my question: is this the recommended way for mod_python framework
developers to acquire x-platform global locks? Explicitly use lock
id 0? If so, is this a secret or should it be documented?
I don't know if it's recommended, but I don't see a problem as long as
the lock is held briefly and you make sure you unlock it when you are
done. I suspect it is undocumented because it was never documented as
opposed to some larger conspiracy.
I used another cross platform approach in filesession_cleanup() in
Session.py. I wanted to make sure only one request at a time was running
the cleanup, and used the os.open() call to exclusively open a guard
file. (OK, not a guard file, but my brain just went blank. Hopefully you
get the idea.)
Here is a code snippet:
lockfile = os.path.join(sessdir,'.mp_sess.lck')
try:
lockfp = os.open(lockfile, os.O_CREAT | os.O_EXCL | os.O_WRONLY,
0660)
except:
req.log_error('FileSession cleanup:
another process is already running.'
% (fast_cleanup,verify_cleanup),
apache.APLOG_NOTICE)
return
try:
... more code ...
try:
os.unlink(lockfile)
except:
pass
finally:
os.close(lockfp)
I got this idea from Barry Pearce in a thread from April 2005 on the
mod_python list. You might want to check archives - lots of interesting
stuff.
Regards,
Jim