I pestered dngor on IRC about this unintelligibly for a while before hacking
out a solution, but I wanted to post my issue anyway in case it is of some
significance. I've posted the code below for reference.
Basically, I was reading from one regular unix file and writing to another
regular unix file. The file being read from varies in size, but is always
nonzero and generally <= 20MB. My SysRW block size is the default of 512
bytes.
Now, if I read a file that is <= 512 bytes, ErrorEvent is immediately
triggered and if I check the value of get_driver_out_octets() it will match
whatever the file size is and it would never get written to my output handle
(when I killed the wheel in the ErrorEvent). With files > 512 bytes
seemingly randomly get_driver_out_octets() would tell me that data still
needed to be flushed when ErrorEvent was called and I killed my wheel, thus
the last few bytes were not being written *ever* if the file was <= 512 bytes
and ocassionally when it was > 512 bytes.
I hacked a 'solution' below which flags EOF and I have my Flushed event check
for it each time the buffer gets flushed, killing the wheel only when there
is actually no data left to be read. I no longer lose data, ever, but I
don't know if this is a 'POEish' way of dealing with this or not.
(This is what I originally thought was being caused by POE Wheel Run, but you
see I later tracked it down to this specifically.)
---
my $write = new IO::File 'writefile',
O_CREAT | O_WRONLY | O_NONBLOCK;
my $read = new IO::File 'readfile',
O_RDONLY | O_NONBLOCK;
$self->copy_file($write, $read);
sub copy_file {
my( $self, $write_fh, $read_fh ) = @_[0..2];
if(defined $write_fh && defined $read_fh ) {
$self->{move} = POE::Wheel::ReadWrite->new(
InputHandle => $read_fh,
OutputHandle => $write_fh,
Driver => POE::Driver::SysRW->new(),
Filter => POE::Filter::Stream->new(),
InputEvent => 'fh_read',
FlushedEvent => 'flush',
ErrorEvent => 'fh_error'
);
}
sub fh_read {
my( $self, $record, $wheel_id ) = @_[ OBJECT, ARG0, ARG1 ];
$self->{move}->put( $record );
}
sub fh_error {
my( $self, $op, $errnum, $errstr, $wheel_id ) =
@_[ OBJECT, ARG0, ARG1, ARG2, ARG3 ];
my $pending_octets = $self->{move}->get_driver_out_octets();
my $pending_messages = $self->{move}->get_driver_out_messages();
warn both those, $errnum, and $errstr;
# The flush event can finally delete the wheel
$self->{EOF} = 'true';
}
sub flush {
my( $self, $wheel_id ) = @_[ OBJECT, ARG0 ];
if( $self->{EOF} eq 'true' and defined $self->{move} ) {
delete $self->{move};
}
# The data was flushed -- nothing special needs to happen
}