diff options
Diffstat (limited to '')
-rw-r--r-- | Mailman/Queue/Switchboard.py | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/Mailman/Queue/Switchboard.py b/Mailman/Queue/Switchboard.py index 17046a8c..10bb9393 100644 --- a/Mailman/Queue/Switchboard.py +++ b/Mailman/Queue/Switchboard.py @@ -67,7 +67,7 @@ DELTA = .0001 class Switchboard: - def __init__(self, whichq, slice=None, numslices=1): + def __init__(self, whichq, slice=None, numslices=1, recover=False): self.__whichq = whichq # Create the directory if it doesn't yet exist. # FIXME @@ -86,6 +86,8 @@ class Switchboard: if numslices <> 1: self.__lower = ((shamax+1) * slice) / numslices self.__upper = (((shamax+1) * (slice+1)) / numslices) - 1 + if recover: + self.recover_backup_files() def whichq(self): return self.__whichq @@ -143,9 +145,16 @@ class Switchboard: def dequeue(self, filebase): # Calculate the filename from the given filebase. filename = os.path.join(self.__whichq, filebase + '.pck') + backfile = os.path.join(self.__whichq, filebase + '.bak') # Read the message object and metadata. fp = open(filename) - os.unlink(filename) + # Move the file to the backup file name for processing. If this + # process crashes uncleanly the .bak file will be used to re-instate + # the .pck file in order to try again. XXX what if something caused + # Python to constantly crash? Is it possible that we'd end up mail + # bombing recipients or crushing the archiver? How would we defend + # against that? + os.rename(filename, backfile) try: msg = cPickle.load(fp) data = cPickle.load(fp) @@ -155,26 +164,42 @@ class Switchboard: msg = email.message_from_string(msg, Message.Message) return msg, data - def files(self): + def finish(self, filebase): + bakfile = os.path.join(self.__whichq, filebase + '.bak') + try: + os.unlink(bakfile) + except EnvironmentError, e: + syslog('error', 'Failed to unlink backup file: %s', bakfile) + + def files(self, extension='.pck'): times = {} lower = self.__lower upper = self.__upper for f in os.listdir(self.__whichq): # By ignoring anything that doesn't end in .pck, we ignore # tempfiles and avoid a race condition. - if not f.endswith('.pck'): + filebase, ext = os.path.splitext(f) + if ext <> extension: continue - filebase = os.path.splitext(f)[0] when, digest = filebase.split('+') # Throw out any files which don't match our bitrange. BAW: test # performance and end-cases of this algorithm. MAS: both # comparisons need to be <= to get complete range. if lower is None or (lower <= long(digest, 16) <= upper): key = float(when) - while times.has_key(key): + while key in times.keys(): key += DELTA times[key] = filebase # FIFO sort keys = times.keys() keys.sort() return [times[k] for k in keys] + + def recover_backup_files(self): + # Move all .bak files in our slice to .pck. It's impossible for both + # to exist at the same time, so the move is enough to ensure that our + # normal dequeuing process will handle them. + for filebase in self.files('.bak'): + src = os.path.join(self.__whichq, filebase + '.bak') + dst = os.path.join(self.__whichq, filebase + '.pck') + os.rename(src, dst)
\ No newline at end of file |