[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