[SP-pm] "leak" no DBIx::Class?

Eden Cardim edencardim at gmail.com
Sat Nov 12 05:23:24 PST 2011


>>>>> "Stanislaw" == Stanislaw Pusep <creaktive em gmail.com> writes:

    Stanislaw> Trazendo pra cá a conversa com @edenc no Twitter :)

Exceto que no twitter você não foi tão educado :P

    Stanislaw> ... (bastante simples) ...

Deviam banir esse adjetivo do contexto de discussões técnicas.

    Stanislaw> Consegui isolar o seguinte trecho porcalhão:

    Stanislaw> my $images = $schema->resultset('Image');
    Stanislaw> ...;
    Stanislaw> while (my $url = <>) {
    Stanislaw>     ...;
    Stanislaw>     $images->find_or_create(
    Stanislaw>         {
    Stanislaw>             sampler_uid => $obj->uid,
    Stanislaw>             url         => $url,
    Stanislaw>         },
    Stanislaw>         { key => 'images_url_idx' }
    Stanislaw>     );
    Stanislaw> }

    Stanislaw> Curiosamente, posso substituir find_or_create() por apenas find() e o resultado é o mesmo: acréscimo de
    Stanislaw> alguns KB no processo para cada operação.
    Stanislaw> Como tenho meio milhão de registros, deu no que deu.

,----[ test.pl ]
| use strictures 1;
| 
| use lib 'lib';
| 
| use MyApp::Schema;
| use Devel::Cycle;
| 
| my $s = MyApp::Schema->connect('dbi:SQLite:database=test.db');
| 
| my $images = $s->resultset('Foo');
| for ( 0 .. 500000 ) {
|   $images->find_or_create(
|     { bar => qq{baz$_}  },
|   );
| }
| 
| find_cycle($images);
`----

Rodei o trecho acima com um schema deduzido (já que você não forneceu o
seu) gerado pelo dbicdump e não consegui reproduzir o "leak". Já tive
problemas de leak com o DBIC há muito tempo atrás e eu mesmo ajudei a
depurar. Mas com o DBIC mais recente (0.08195) e perl 5.14.2, o processo
roda feliz da vida com 15MB, a equipe de core devs do DBIC é bastante
responsiva e trabalha arduamente pra evitar e resolver problemas como
isso. Tudo isso indica que há uma chance do leak ser em alguma
customização sua, pode ser no DBIC também mas sem ver o seu schema na
íntegra não tem como saber o que deu errado.

A propósito, também testei na cópia de uma base de dados de produção com
cerca de 200M registros ontem, acordei hoje e ainda estava rodando, mas
o processo ainda ocupando cerca de 20MB de memória.

    Stanislaw> Antes disso, suspeitei que tivesse algo a ver com AutoCommit e encapsulei com txn_do() a cada 100
    Stanislaw> registros; deu na mesma.
    Stanislaw> Também suspeitei do prepare_cached(), porém isso não faz o menor sentido, pois o statement é o mesmo para
    Stanislaw> todas as queries.
    Stanislaw> Anyway, tentei limpar $schema->storage->dbh->{CachedKids} periodicamente e também não
    Stanislaw> adiantou.

Nada disso faz sentido, e tudo isso que você mencionou acontece

    Stanislaw> Por fim, tentei ver o que acontece xeretando através do Devel::Size. De fato, o objeto do ResultSet cresce
    Stanislaw> indefinidamente. Porém todas as minhas tentativas de serializar o mesmo e descobrir o que está acontecendo
    Stanislaw> via diff foram frustradas :(

Verificar o tamanho do objeto não é o suficiente pra assertar um "leak"
e como o objeto resultset nunca sai do escopo, não dá pra chamar isso de
"leak". Leak é quando você para de usar um trecho de memória (no caso do
perl, implicitamente, através da destrução de referências) e essa
memória não volta a ficar disponível pro sistema. Uma das coisas que
pode estar acontecendo é você ter configurado caching pros resultsets em
algum outro lugar, nesse caso, é natural que o consumo de memória
aumente sempre que você executar uma query, já que o resultado da query
é armazenado em memória pra evitar uma segunda consulta.

    Stanislaw> Any ideas?

Sim, usa o trecho de código acima pra localizar o ciclo dentro do
resultset, se for mesmo um leak, provavelmente vai apontar pra alguma
customização sua.

-- 
Eden Cardim
Software Engineer
http://bit.ly/edencardim
http://twitter.com/#!/edenc
+55 73 9986-3963


More information about the SaoPaulo-pm mailing list