Skip Menu |

This queue is for tickets about the Mail-Box CPAN distribution.

Report information
The Basics
Id: 31197
Status: resolved
Priority: 0/
Queue: Mail-Box

People
Owner: Nobody in particular
Requestors: jik [...] kamens.brookline.ma.us
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 2.078
Fixed in: (no value)



Subject: Mail::Box::File::_write_replace fails on Windows
Mail::Box::File::_write_replace has this line of code in it, right before it tries to rename the new file on top of the old one: unlink $filename if $windows; The idea here is that since Windows doesn't allow a rename on top of an existing file, we need to delete the existing file right before we try to do the rename. The problem with this is that Mail::Box::Parser still has the file open when this line of code runs, which means that the unlink doesn't fully succeed. When you delete an open file in Windows, the delete "succeeds", but the file stays there until everybody who has it open closes it. As a result, the subsequent line of code: unless(move $tmpnew, $filename) fails. The best way I could come up with to fix this problem was to modify Mail::Box::Parser to support a delayed restart, i.e., close the file now but don't reopen it until I tell you to. I've attached the necessary patches to implement this change. I don't know if this is the Right Way to fix this or the way you want to do it, but it seems to work for me.
Subject: diff
--- /usr/lib/perl5/site_perl/5.8/Mail/Box/Parser.pm~ 2007-11-28 04:47:08.000000000 -0500 +++ /usr/lib/perl5/site_perl/5.8/Mail/Box/Parser.pm 2007-12-04 10:36:38.966250000 -0500 @@ -67,21 +67,35 @@ $self->closeFile; } +sub delayed_restart() +{ my $self = shift; + my $delayed_filename = $self->{delayed_restart_filename}; + + if ($delayed_filename) { + $self->openFile( {filename => $delayed_filename, + mode => $self->{MBP_mode}} ) + or return; -sub restart() -{ my $self = shift; - my $filename = $self->filename; + $self->takeFileInfo; + $self->log(NOTICE => "Restarted parser for file $delayed_filename"); + } + else { + my $filename = $self->filename; - $self->closeFile or return; + $self->{delayed_restart_filename} = $filename; - $self->openFile( {filename => $filename, mode => $self->{MBP_mode}} ) - or return; + $self->closeFile or return; + $self->log(NOTICE => "Closed parser for file $filename preparing to restart"); + } - $self->takeFileInfo; - $self->log(NOTICE => "Restarted parser for file $filename"); $self; } +sub restart() +{ my $self = shift; + $self->delayed_restart && $self->delayed_restart; +} + sub fileChanged() { my $self = shift; --- /usr/lib/perl5/site_perl/5.8/Mail/Box/File.pm~ 2007-11-28 04:47:07.000000000 -0500 +++ /usr/lib/perl5/site_perl/5.8/Mail/Box/File.pm 2007-12-04 10:33:23.841250000 -0500 @@ -346,6 +346,8 @@ my $policy = exists $args->{policy} ? $args->{policy} : $self->{MBF_policy}; $policy ||= ''; + $self->parser->delayed_restart; + my $success = ! -e $filename ? $self->_write_new($args) : $policy eq 'INPLACE' ? $self->_write_inplace($args) @@ -358,7 +360,7 @@ return; } - $self->parser->restart; + $self->parser->delayed_restart; $self; }
Subject: Re: [rt.cpan.org #31197] Mail::Box::File::_write_replace fails on Windows
Date: Wed, 5 Dec 2007 11:33:23 +0100
To: Jonathan Kamens via RT <bug-Mail-Box [...] rt.cpan.org>
From: Mark Overmeer <mark [...] overmeer.net>
* Jonathan Kamens via RT (bug-Mail-Box@rt.cpan.org) [071204 15:43]: Show quoted text
> > +sub restart() > +{ my $self = shift; > + $self->delayed_restart && $self->delayed_restart; > +}
This patch is very welcome, because for a long time people are complaining that this does not work on Windows, but no-one ever wanted to fix it. And I never use Windows, so had no chance either. I think that the patch still has some rough edges. For instance, why are you calling delayer_restart twice??? -- Regards, MarkOv ------------------------------------------------------------------------ Mark Overmeer MSc MARKOV Solutions Mark@Overmeer.net solutions@overmeer.net http://Mark.Overmeer.net http://solutions.overmeer.net
Subject: Re: [rt.cpan.org #31197] Mail::Box::File::_write_replace fails on Windows
Date: Wed, 05 Dec 2007 05:45:22 -0500
To: bug-Mail-Box [...] rt.cpan.org
From: Jonathan Kamens <jik [...] kamens.brookline.ma.us>
The point of the delayed_restart functionality that I implemented is to divide the restart process into two phases, so that the mbox file can be replaced in the meantime. The first call to delayed_restart closes the file, the second reopens it.
Subject: Re: [rt.cpan.org #31197] Mail::Box::File::_write_replace fails on Windows
Date: Wed, 5 Dec 2007 11:50:39 +0100
To: Jonathan Kamens via RT <bug-Mail-Box [...] rt.cpan.org>
From: Mark Overmeer <mark [...] overmeer.net>
* Jonathan Kamens via RT (bug-Mail-Box@rt.cpan.org) [071205 10:47]: Show quoted text
> The point of the delayed_restart functionality that I implemented is to > divide the restart process into two phases, so that the mbox file can be > replaced in the meantime. The first call to delayed_restart closes the > file, the second reopens it.
Why not simply create two seperate methods for two different actions? -- Regards, MarkOv ------------------------------------------------------------------------ Mark Overmeer MSc MARKOV Solutions Mark@Overmeer.net solutions@overmeer.net http://Mark.Overmeer.net http://solutions.overmeer.net
Subject: Re: [rt.cpan.org #31197] Mail::Box::File::_write_replace fails on Windows
Date: Wed, 05 Dec 2007 05:56:23 -0500
To: bug-Mail-Box [...] rt.cpan.org
From: Jonathan Kamens <jik [...] kamens.brookline.ma.us>
I moved the restart functionality out of restart and into delayed_restart because I needed a way to split up the restart action into two separate method calls. I then modified restart to call delayed_restart, rather than leaving the same code in restart, because I don't believe in implementing the same functionality in two places. If you want to make delayed_restart two different functions, e.g., restart_begin and restart_end, rather than requiring two calls to delayed_restart, I've got no problem with that. It's a minor API question that has no bearing on the functionality. As far as I'm concerned either API would be fine, as long as the required functionality, i.e., being able to do something in between the close and the open of the restart, is present. jik
Subject: Re: [rt.cpan.org #31197] Mail::Box::File::_write_replace fails on Windows
Date: Mon, 31 Dec 2007 09:09:41 +0100
To: Jonathan Kamens via RT <bug-Mail-Box [...] rt.cpan.org>
From: Mark Overmeer <mark [...] overmeer.net>
* Jonathan Kamens via RT (bug-Mail-Box@rt.cpan.org) [071204 15:43]: Show quoted text
> Tue Dec 04 10:42:57 2007: Request 31197 was acted upon. > Transaction: Ticket created by JIK > Queue: Mail-Box > Subject: Mail::Box::File::_write_replace fails on Windows > Broken in: 2.078 > Severity: (no value) > Owner: Nobody > Requestors: jik@kamens.brookline.ma.us > Status: new > Ticket <URL: http://rt.cpan.org/Ticket/Display.html?id=31197 >
The more I think about it, the simpler the solution gets. One big disadvantage is the loss of lock... it is not a safe operation anymore. However, that's part of the particular OS you chose. Isn't this sufficient: diff -r /tmp/Mail-Box.old/lib/Mail/Box/File.pm /tmp/Mail-Box/lib/Mail/Box/File.pm 432c432,439 < unlink $filename if $windows; --- Show quoted text
> if($windows) > { # Windows does not like to move to existing filenames > unlink $filename; > > # Windows cannot move to files which are opened. > $self->parser->closeFile; > }
diff -r /tmp/Mail-Box.old/lib/Mail/Box/Parser.pm /tmp/Mail-Box/lib/Mail/Box/Parser.pm 75,76c75 < $self->closeFile or return; < --- Show quoted text
> $self->closeFile;
-- Regards, MarkOv ------------------------------------------------------------------------ Mark Overmeer MSc MARKOV Solutions Mark@Overmeer.net solutions@overmeer.net http://Mark.Overmeer.net http://solutions.overmeer.net
probably resolved in 2.080