Comunicando do bash com shell grunhido

5

Estou cansado do tempo de inicialização lento de hadoop fs apenas para consultar o HDFS. Isso não é um problema com o próprio HDFS, porque o uso de comandos do sistema de arquivos HDFS dentro do "shell grunt" do Pig é bem rápido. Mas é impraticável sempre iniciar o shell grunhido quando eu quero apenas emitir alguns comandos do HDFS. Então eu escrevi este script para iniciar uma instância de shell grunhido em segundo plano para mim e mantê-lo aberto para chamadas sucessivas:

#!/bin/bash

in=/tmp/grunt_in
out=/tmp/grunt_out
err=/tmp/grunt_err

if [ ! -p $in ]
then
    mkfifo $in
    mkfifo $out
    ( pig <>$in >$out 2>$err; rm $in $out ) &
    disown
fi

>$err # Truncate errors
echo "fs $*" >$in
echo >$in
echo "-- end" >$in
sed -n '/^grunt> -- end/q;/^grunt>/d;p' $out
cat $err >&2

É claro que não apenas a entrada deve ser enviada para o script, mas também a saída do script deve ser redirecionada para a minha sessão bash atual. Eu uso os /tmp/grunt_in e /tmp/grunt_out FIFOs aqui para conseguir isso. Para descobrir quando pig processou o comando, enviei um comentário "-- end" e detectei que no comando sed , que está escutando na saída, ele é encerrado quando encontra o token end e só exibe a peça relevante ignorando todos os prompts de grunt> .

Note que eu tenho que anexar o FIFO de entrada com <>$in , mesmo que eu redirecione a saída para $out para evitar que o porco seja encerrado após o primeiro comando. Eu não sei exatamente o porquê, mas achei que funciona assim.

Isso realmente funciona bem legal. Por exemplo,

$ time hadoop fs -ls
Found 38 items
[ skipped output ]

real    0m1.828s
user    0m3.160s
sys 0m0.137s

$ time dfs -ls

[apollo@dc1-had03-clusterutil01 reporting-APO-5394]$ time dfs -ls
Found 38 items
[ skipped output ]

real    0m0.149s
user    0m0.003s
sys 0m0.006s

(Eu chamei meu script dfs aqui.) Há apenas dois problemas que não consigo descobrir atualmente:

  1. Quando eu chamo o script pela primeira vez (que é quando o fifo /tmp/grunt_in ainda não existe e a instância do porco é iniciada em segundo plano), as configurações do meu terminal estão de alguma forma bagunçadas. Eu não recebo mais o eco da minha entrada, então eu tenho que digitar um reset cegamente para recuperar um terminal sã. O sucesso das chamadas funciona bem.
  2. Quando tento exibir o conteúdo do arquivo no HDFS com -cat ou -text , a saída é arbitrariamente truncada. Por exemplo:

    $ hadoop fs -text some-medium-size.gz|wc -l
    3606
    $ dfs -text some-medium-size.gz|wc -l
    text: Unable to write to output stream.
    9
    

    Observe a mensagem de erro text: Unable to write to output stream. aqui, que não é proveniente de pig , mas do comando fs -text de hadoop . Às vezes é truncado nas primeiras 9 ou 10 linhas como aqui ou às vezes em algum lugar no meio. É muito estranho. Também tentei enviar o comando manualmente para /tmp/grunt_in e ler /tmp/grunt_out com cat , com o mesmo resultado, mas isso confirma que minha análise com sed não pode ser o problema aqui. Isto também não parece ser um problema com grandes resultados em geral, e. para listagens longas de diretórios, tudo funciona bem:

    $ dfs -ls -R|wc -l
    10686
    

(que dá o mesmo resultado que hadoop fs -ls -R|wc -l )

Talvez o último problema seja um problema com hadoop fs -text e hadoop fs -cat em si? Ou algo de errado com meu uso de pipes nomeados?

    
por David Ongaro 13.07.2014 / 01:35

1 resposta

1

Eu agora mais menos resolvido nesta versão:

#!/bin/bash

in=/tmp/grunt_in
out=/tmp/grunt_out
err=/tmp/grunt_err

if [ ! -p $in ]
then
    mkfifo $in
    mkfifo $out
    mkfifo $err
    { script -q -c "pig 1>$out 2>$err" <>$in; rm $in $out $err; } &
fi

{
    echo "fs $*"
    echo
    echo "-- end"
} >$in
cat $err >&2 &
catpid=$!
sed -n -u '/^grunt> -- end/q;/^grunt>/d;p' <$out
kill $catpid

Portanto, eu simplesmente redireciono o stderr para dentro do comando script . Eu também substituí as chaves redondas por chaves e removi o disown porque não vi nenhuma vantagem em fazer isso. Eu também substituí o $err por um FIFO para poder gerar uma saída antecipada, mas isso também adiciona algumas complicações para matar o cat .

Isso funciona muito bem até agora exceto que quando eu truncar a saída pelo piping através de head eu recebo uma saída truncada ou extra no próximo comando. Aparentemente, eu preciso de uma maneira de liberar corretamente os pipes nomeados. Eu ficaria feliz se alguém tiver alguma dica.

    
por 16.07.2014 / 01:14