Folks, I've just released Mailman 2.0.5 which fixes a problem with stale lock files that can occur under certain situations when the user hits the `Stop' button on their browser. These stale lock files can cause mailing lists to be inaccessible for long periods of time (until the stale lock file times out or is manually removed). As usual, I'm releasing this as both a complete tarball and as a patch against Mailman 2.0.4. You /must/ update your source to 2.0.4 before applying the 2.0.5 patch. Since the patch is small, I'm including it in this message. To apply, cd into your 2.0.5 source tree and apply it like so: % patch -p0 < mailman-2.0.4-2.0.5.txt Currently both http://mailman.sourceforge.net and http://www.list.org are updated, and I expect the gnu.org site to be updated soon as well. The release information on SF is at http://sourceforge.net/project/shownotes.php?release_id=31693 See also http://www.gnu.org/software/mailman http://www.list.org http://mailman.sourceforge.net My thanks to those of you who gave the 2.0.5 pre-release a try! Enjoy, -Barry Index: NEWS =================================================================== RCS file: /cvsroot/mailman/mailman/NEWS,v retrieving revision 1.25.2.5 retrieving revision 1.25.2.6 diff -u -r1.25.2.5 -r1.25.2.6 --- NEWS 2001/04/18 10:45:54 1.25.2.5 +++ NEWS 2001/05/03 21:06:56 1.25.2.6 @@ -4,6 +4,13 @@ Here is a history of user visible changes to Mailman. +2.0.5 (04-May-2001) + + Fix a lock stagnation problem that can result when the user hits + the `stop' button on their browser during a write operation that + can take a long time (e.g. hitting the membership management admin + page). + 2.0.4 (18-Apr-2001) Python 2.1 compatibility release. There were a few questionable Index: Mailman/Version.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Version.py,v retrieving revision 1.20.2.4 retrieving revision 1.20.2.5 diff -u -r1.20.2.4 -r1.20.2.5 --- Mailman/Version.py 2001/04/18 04:43:29 1.20.2.4 +++ Mailman/Version.py 2001/05/03 20:58:19 1.20.2.5 @@ -15,7 +15,7 @@ # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Mailman version -VERSION = "2.0.4" +VERSION = "2.0.5" # And as a hex number in the manner of PY_VERSION_HEX ALPHA = 0xa @@ -27,7 +27,7 @@ MAJOR_REV = 2 MINOR_REV = 0 -MICRO_REV = 4 +MICRO_REV = 5 REL_LEVEL = FINAL # at most 15 beta releases! REL_SERIAL = 0 Index: Mailman/Cgi/admin.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Cgi/admin.py,v retrieving revision 1.82.2.2 retrieving revision 1.82.2.3 diff -u -r1.82.2.2 -r1.82.2.3 --- Mailman/Cgi/admin.py 2001/01/03 16:47:47 1.82.2.2 +++ Mailman/Cgi/admin.py 2001/05/03 21:03:48 1.82.2.3 @@ -18,11 +18,13 @@ """ +import sys import os import cgi import string import types import rfc822 +import signal from Mailman import Utils from Mailman import MailList @@ -63,53 +65,86 @@ # get the list object listname = string.lower(parts[0]) try: - mlist = MailList.MailList(listname) + mlist = MailList.MailList(listname, lock=0) except Errors.MMListError, e: FormatAdminOverview('No such list <em>%s</em>' % listname) syslog('error', 'Someone tried to access the admin interface for a ' 'non-existent list: %s' % listname) return + + if len(parts) == 1: + category = 'general' + category_suffix = '' + else: + category = parts[1] + category_suffix = category + + # If the user is not authenticated, we're done. + cgidata = cgi.FieldStorage(keep_blank_values=1) try: - if len(parts) == 1: - category = 'general' - category_suffix = '' - else: - category = parts[1] - category_suffix = category - - # If the user is not authenticated, we're done. - cgidata = cgi.FieldStorage(keep_blank_values=1) - try: - Auth.authenticate(mlist, cgidata) - except Auth.NotLoggedInError, e: - Auth.loginpage(mlist, 'admin', e.message) - return - - # Is this a log-out request? - if category == 'logout': - print mlist.ZapCookie('admin') - Auth.loginpage(mlist, 'admin', frontpage=1) - return - - if category not in map(lambda x: x[0], CATEGORIES): - category = 'general' - - # is the request for variable details? - varhelp = None - if cgidata.has_key('VARHELP'): - varhelp = cgidata['VARHELP'].value - elif cgidata.has_key('request_login') and \ - os.environ.get('QUERY_STRING'): - # POST methods, even if their actions have a query string, don't - # get put into FieldStorage's keys :-( - qs = cgi.parse_qs(os.environ['QUERY_STRING']).get('VARHELP') - if qs and type(qs) == types.ListType: - varhelp = qs[0] - if varhelp: - FormatOptionHelp(doc, varhelp, mlist) - print doc.Format(bgcolor="#ffffff") - return + Auth.authenticate(mlist, cgidata) + except Auth.NotLoggedInError, e: + Auth.loginpage(mlist, 'admin', e.message) + return + + # Is this a log-out request? + if category == 'logout': + print mlist.ZapCookie('admin') + Auth.loginpage(mlist, 'admin', frontpage=1) + return + + if category not in map(lambda x: x[0], CATEGORIES): + category = 'general' + # is the request for variable details? + varhelp = None + if cgidata.has_key('VARHELP'): + varhelp = cgidata['VARHELP'].value + elif cgidata.has_key('request_login') and \ + os.environ.get('QUERY_STRING'): + # POST methods, even if their actions have a query string, don't + # get put into FieldStorage's keys :-( + qs = cgi.parse_qs(os.environ['QUERY_STRING']).get('VARHELP') + if qs and type(qs) == types.ListType: + varhelp = qs[0] + if varhelp: + FormatOptionHelp(doc, varhelp, mlist) + print doc.Format(bgcolor="#ffffff") + return + + # From this point on, the MailList object must be locked. However, we + # must release the lock no matter how we exit. try/finally isn't + # enough, because of this scenario: user hits the admin page which may + # take a long time to render; user gets bored and hits the browser's + # STOP button; browser shuts down socket; server tries to write to + # broken socket and gets a SIGPIPE. Under Apache 1.3/mod_cgi, Apache + # catches this SIGPIPE (I presume it is buffering output from the cgi + # script), then turns around and SIGTERMs the cgi process. Apache + # waits three seconds and then SIGKILLs the cgi process. We /must/ + # catch the SIGTERM and do the most reasonable thing we can in as + # short a time period as possible. If we get the SIGKILL we're + # screwed (because its uncatchable and we'll have no opportunity to + # clean up after ourselves). + # + # This signal handler catches the SIGTERM and unlocks the list. The + # effect of this is that the changes made to the MailList object will + # be aborted, which seems like the only sensible semantics. + # + # BAW: This may not be portable to other web servers or cgi execution + # models. + def sigterm_handler(signum, frame, mlist=mlist): + # Make sure the list gets unlocked... + mlist.Unlock() + # ...and ensure we exit, otherwise race conditions could cause us to + # enter MailList.Save() while we're in the unlocked state, and that + # could be bad! + sys.exit(0) + + mlist.Lock() + try: + # Install the emergency shutdown signal handler + signal.signal(signal.SIGTERM, sigterm_handler) + if cgidata.has_key('bounce_matching_headers'): pairs = mlist.parse_matching_header_opt() @@ -135,8 +170,12 @@ FormatConfiguration(doc, mlist, category, category_suffix, cgidata) print doc.Format(bgcolor="#ffffff") - finally: mlist.Save() + finally: + # Now be sure to unlock the list. It's okay if we get a signal here + # because essentially, the signal handler will do the same thing. And + # unlocking is unconditional, so it's not an error if we unlock while + # we're already unlocked. mlist.Unlock() Index: Mailman/Cgi/admindb.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Cgi/admindb.py,v retrieving revision 1.36.2.1 retrieving revision 1.36.2.4 diff -u -r1.36.2.1 -r1.36.2.4 --- Mailman/Cgi/admindb.py 2001/03/03 06:02:01 1.36.2.1 +++ Mailman/Cgi/admindb.py 2001/05/04 15:54:23 1.36.2.4 @@ -16,10 +16,12 @@ """Produce and process the pending-approval items for a list.""" +import sys import os import string import types import cgi +import signal from errno import ENOENT from Mailman import mm_cfg @@ -62,7 +64,7 @@ return # now that we have the list name, create the list object try: - mlist = MailList.MailList(listname) + mlist = MailList.MailList(listname, lock=0) except Errors.MMListError, e: handle_no_list(doc, 'No such list <em>%s</em><p>' % listname) syslog('error', 'No such list "%s": %s\n' % (listname, e)) @@ -71,14 +73,34 @@ # now we must authorize the user to view this page, and if they are, to # handle both the printing of the current outstanding requests, and the # selected actions + cgidata = cgi.FieldStorage() try: - cgidata = cgi.FieldStorage() - try: - Auth.authenticate(mlist, cgidata) - except Auth.NotLoggedInError, e: - Auth.loginpage(mlist, 'admindb', e.message) - return + Auth.authenticate(mlist, cgidata) + except Auth.NotLoggedInError, e: + Auth.loginpage(mlist, 'admindb', e.message) + return + + # We need a signal handler to catch the SIGTERM that can come from Apache + # when the user hits the browser's STOP button. See the comment in + # admin.py for details. + # + # BAW: Strictly speaking, the list should not need to be locked just to + # read the request database. However the request database asserts that + # the list is locked in order to load it and it's not worth complicating + # that logic. + def sigterm_handler(signum, frame, mlist=mlist): + # Make sure the list gets unlocked... + mlist.Unlock() + # ...and ensure we exit, otherwise race conditions could cause us to + # enter MailList.Save() while we're in the unlocked state, and that + # could be bad! + sys.exit(0) + mlist.Lock() + try: + # Install the emergency shutdown signal handler + signal.signal(signal.SIGTERM, sigterm_handler) + # If this is a form submission, then we'll process the requests and # print the results. otherwise (there are no keys in the form), we'll # print out the list of pending requests @@ -91,8 +113,8 @@ PrintRequests(mlist, doc) text = doc.Format(bgcolor="#ffffff") print text - finally: mlist.Save() + finally: mlist.Unlock() Index: Mailman/Cgi/handle_opts.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Cgi/handle_opts.py,v retrieving revision 1.30 retrieving revision 1.30.2.2 diff -u -r1.30 -r1.30.2.2 --- Mailman/Cgi/handle_opts.py 2000/11/09 16:19:03 1.30 +++ Mailman/Cgi/handle_opts.py 2001/05/03 21:05:06 1.30.2.2 @@ -1,4 +1,4 @@ -# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc. +# Copyright (C) 1998,1999,2000,2001 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -20,6 +20,7 @@ import os import string import cgi +import signal from Mailman import mm_cfg from Mailman import Utils @@ -61,7 +62,7 @@ user = parts[1] try: - mlist = MailList.MailList(listname) + mlist = MailList.MailList(listname, lock=0) except Errors.MMListError, e: doc.AddItem(Header(2, "Error")) doc.AddItem(Bold('No such list <em>%s</em>' % listname)) @@ -69,10 +70,30 @@ syslog('error', 'No such list "%s": %s\n' % (listname, e)) return + # We need a signal handler to catch the SIGTERM that can come from Apache + # when the user hits the browser's STOP button. See the comment in + # admin.py for details. + # + # BAW: Strictly speaking, the list should not need to be locked just to + # read the request database. However the request database asserts that + # the list is locked in order to load it and it's not worth complicating + # that logic. + def sigterm_handler(signum, frame, mlist=mlist): + # Make sure the list gets unlocked... + mlist.Unlock() + # ...and ensure we exit, otherwise race conditions could cause us to + # enter MailList.Save() while we're in the unlocked state, and that + # could be bad! + sys.exit(0) + + mlist.Lock() try: + # Install the emergency shutdown signal handler + signal.signal(signal.SIGTERM, sigterm_handler) + process_form(mlist, user, doc) - finally: mlist.Save() + finally: mlist.Unlock() Index: Mailman/Cgi/subscribe.py =================================================================== RCS file: /cvsroot/mailman/mailman/Mailman/Cgi/subscribe.py,v retrieving revision 1.29 retrieving revision 1.29.2.1 diff -u -r1.29 -r1.29.2.1 --- Mailman/Cgi/subscribe.py 2000/09/29 00:05:05 1.29 +++ Mailman/Cgi/subscribe.py 2001/05/03 21:05:43 1.29.2.1 @@ -1,4 +1,4 @@ -# Copyright (C) 1998,1999,2000 by the Free Software Foundation, Inc. +# Copyright (C) 1998,1999,2000,2001 by the Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -20,6 +20,7 @@ import os import string import cgi +import signal from Mailman import Utils from Mailman import MailList @@ -41,18 +42,38 @@ listname = string.lower(parts[0]) try: - mlist = MailList.MailList(listname) - mlist.IsListInitialized() + mlist = MailList.MailList(listname, lock=0) except Errors.MMListError, e: doc.AddItem(Header(2, "Error")) doc.AddItem(Bold('No such list <em>%s</em>' % listname)) print doc.Format(bgcolor="#ffffff") syslog('error', 'No such list "%s": %s\n' % (listname, e)) return + + # We need a signal handler to catch the SIGTERM that can come from Apache + # when the user hits the browser's STOP button. See the comment in + # admin.py for details. + # + # BAW: Strictly speaking, the list should not need to be locked just to + # read the request database. However the request database asserts that + # the list is locked in order to load it and it's not worth complicating + # that logic. + def sigterm_handler(signum, frame, mlist=mlist): + # Make sure the list gets unlocked... + mlist.Unlock() + # ...and ensure we exit, otherwise race conditions could cause us to + # enter MailList.Save() while we're in the unlocked state, and that + # could be bad! + sys.exit(0) + + mlist.Lock() try: + # Install the emergency shutdown signal handler + signal.signal(signal.SIGTERM, sigterm_handler) + process_form(mlist, doc) - finally: mlist.Save() + finally: mlist.Unlock() Index: admin/www/download.ht =================================================================== RCS file: /cvsroot/mailman/mailman/admin/www/download.ht,v retrieving revision 1.5.2.5 retrieving revision 1.5.2.6 diff -u -r1.5.2.5 -r1.5.2.6 --- admin/www/download.ht 2001/04/18 10:44:14 1.5.2.5 +++ admin/www/download.ht 2001/05/03 21:09:36 1.5.2.6 @@ -65,9 +65,9 @@ <h3>Downloading</h3> <p>Version -(<!-VERSION--->2.0.4<!-VERSION--->, +(<!-VERSION--->2.0.5<!-VERSION--->, released on -<!-DATE--->Apr 18 2001<!-DATE--->) +<!-DATE--->May 4 2001<!-DATE--->) is the current GNU release. It is available from the following mirror sites: <ul> Index: admin/www/download.html =================================================================== RCS file: /cvsroot/mailman/mailman/admin/www/download.html,v retrieving revision 1.6.2.7 retrieving revision 1.6.2.8 diff -u -r1.6.2.7 -r1.6.2.8 --- admin/www/download.html 2001/04/18 10:44:14 1.6.2.7 +++ admin/www/download.html 2001/05/03 21:09:36 1.6.2.8 @@ -1,6 +1,6 @@ <HTML> <!-- THIS PAGE IS AUTOMATICALLY GENERATED. DO NOT EDIT. --> -<!-- Wed Apr 18 06:43:32 2001 --> +<!-- Thu May 3 17:09:03 2001 --> <!-- USING HT2HTML 1.1 --> <!-- SEE http://www.wooz.org/barry/software/pyware.html --> <!-- User-specified headers: @@ -237,9 +237,9 @@ <h3>Downloading</h3> <p>Version -(<!-VERSION--->2.0.4<!-VERSION--->, +(<!-VERSION--->2.0.5<!-VERSION--->, released on -<!-DATE--->Apr 18 2001<!-DATE--->) +<!-DATE--->May 4 2001<!-DATE--->) is the current GNU release. It is available from the following mirror sites: <ul>
participants (1)
-
barry@digicool.com