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
}

Reply via email to