[bcn-pm] Aprendiedo a no leakear memoria

Jose Luis Martinez jlmartinez-lists-bcn-pm a capside.com
dll feb 2 13:45:18 PST 2009


Hola a todos,

	Estoy experimentando con POE y la IO asíncrona como prueba de concepto 
para un servidor POP3 experimental (básicamente para comparar los 
beneficios del modelo async vs. el dolor del cambio de paradigma que 
tiene implementar servidores forked / threaded vs asincronos).

Estoy usando IO::AIO y el componente POE::Component::Server::POP3. La 
cosa es que tengo un servidor POP3 medio funcional, pero que leakea 
memoria a un ritmo espantoso. He conseguido trazar el leak hasta el 
evento que lee un mensaje de disco, y lo envia al cliente.

El problema lo tengo especificando la misma función de callback como 
callback de la función aio_read (para seguir leyendo el fichero, y 
enviandolo al cliente por bloques). Dentro de mi deseperación, creé un 
aio_group (que seguramente no es necesario), y sigo igual. Creo que 
tengo problemas en expresar adecuadamente el bucle:
while ($nbytes = READ(FD1, $buffer)){
	WRITE(FD2, $buffer, $nbytes);
}
típico en programación con IO síncrona, y que debido a mi poca 
experiencia con el "estilo asíncrono", estoy cometiendo un fallo tonto.

Nota: Probé con Coro::AIO para ver si podia conservar el estilo 
síncrono, pero el servidor era MUY inestable (no soportaba más de un 
cliente concurrente, y petaba con errores de los más variopintos).

¿Me podéis ayudar a dejar de "leakear"?


POE::Session->create(
       package_states => [
         'main' => [qw(
                       [...]
                       pop3d_cmd_retr
         )],
       ],
);

$poe_kernel->run();
exit 0;

sub pop3d_cmd_retr {
   my ($heap,$id) = @_[HEAP,ARG0];
   my $state = $heap->{clients}->{ $id };

     $state->{'buffer'} = '';
     $heap->{pop3d}->send_to_client($id, '+OK Message follows');

     [...]

     my $i = NUM_DEL_MENSAJE_EN_EL_RETR;
     my $filename = FICHERO_DEL_MENSAJE($i);

     aio_open("$state->{'maildir'}/cur/$filename" , O_RDONLY, 0, sub {
       my $infh = shift;
       if (not $infh){
	$heap->{pop3d}->send_to_client($id, sprintf('-ERR opening message %d', 
$i));
	return;
       }

       my $read_grp;
       $read_grp = aio_group sub {
	  $heap->{pop3d}->send_to_client($id, '');
	  $heap->{pop3d}->send_to_client($id, '.');	
       };
       my $callback;
       $callback = sub {
	my $rbytes = $_[0];
	if ($rbytes > 0){
	  $state->{'buffer'} =~ s/\n/\r\n/;
	  $heap->{pop3d}->send_to_client($id, $state->{'buffer'});

           # COMENTA LA LINEA DE ABAJO PARA PERDER MEMORIA
           $read_grp->add(aio_read($infh, undef, 64*1024, 
$state->{'buffer'}, 0, $callback));
	} elsif ($rbytes == 0) {
	  close $infh;
	} else {
  	  die "read error";
	}
       };
       $read_grp->add(aio_read($infh, undef, 64*1024, 
$state->{'buffer'}, 0, $callback));
     });
     [...]
}

Gracias por adelantado,

Jose Luis Martínez
CAPSiDE
jlmartinez a capside.com


Més informació sobre la llista de correu Barcelona-pm