Libelektra: mmapstorage não funciona com exportação kdb

Criado em 15 fev. 2019  ·  22Comentários  ·  Fonte: ElektraInitiative/libelektra

Etapas para reproduzir o problema

kdb set user/tests/hello world
#> Create a new key user/tests/hello with string "world"

kdb export user/tests/hello mmapstorage > test.mmap

resultado esperado

É criado um arquivo chamado test.mmap , que pode ser reimportado com kdb import .

Resultado atual

Um arquivo vazio chamado test.mmap é criado e a seguinte mensagem é impressa (inclui logs de ENABLE_LOGGER ):

src/plugins/mmapstorage/mmapstorage.c:944:libelektra_mmapstorage_LTX_elektraPluginset: could not unlink
src/plugins/mmapstorage/mmapstorage.c:1003:libelektra_mmapstorage_LTX_elektraPluginset: strerror: Permission denied
Sorry, the error (#9) occurred ;(
Description: Insufficient permissions to open configuration file for writing. You might want to retry as root.
Reason: Permission denied
Ingroup: kdb
Module: 
At: /home/klemens/data/bsc/libelektra/src/plugins/mmapstorage/mmapstorage.c:1004
Mountpoint: user
Configfile: /dev/stdout

Informação do sistema

  • Versão Elektra: mestre

Outras informações

~ Funciona quando kdb export é chamado de root. ~ (EDITAR: veja o comentário abaixo) kdb export user/tests/hello mmapstorage test.mmap também funciona, mas é um recurso totalmente não documentado de kdb export . Portanto, uma mensagem de erro melhor e uma documentação atualizada podem ser tudo de que precisamos.

bug

Comentários muito úteis

Obrigado por sua resposta!

As mensagens de erro do mmap podem ser enganosas.

Por favor, melhore as mensagens de erro.

Pelo que sei, não funcionará no stdout. Também não funciona com tubos

Adicione essa informação às mensagens de erro.

As soluções acima não mudam muito a lógica do mmapstorage.

Como seu plugin é atualmente o único afetado, faz sentido que você faça o stat e copie tudo se necessário. Então poderíamos fechar este problema sem grandes mudanças na estrutura.

Todos 22 comentários

Obrigado por tentar isso e por este relatório detalhado!

Portanto, uma mensagem de erro melhor e uma documentação atualizada podem ser tudo de que precisamos.

Sim, concordo plenamente.

Talvez devêssemos até mesmo ter um serializable em infos / status # 666 e falhar explicitamente se o arquivo for / dev / stdout? ( @mpranj Ou há uma maneira de detectar se um arquivo não é mmapable? É realmente idêntico a uma permissão negada?)

Olhando para o código (e a mensagem de erro), acho que o problema atual é que não podemos chamar unlink em stdout sem acesso root. Além disso, open provavelmente falhará também, porque stdout já está aberto. E se stdout ser mapeado ou não depende de onde stdout está conectado, eu acho.
Usar fstat(fileno(stdout), &stat) para verificar se é um arquivo normal pode funcionar. Talvez isatty(3) também funcione.

Em qualquer caso, poderíamos simplesmente verificar se o arquivo de saída é /dev/stdout (ou CON para _WIN32 ) e criar um arquivo temporário para uso com mmap e depois simplesmente copiá-lo para stdout . Claro que seria mais lento, mas manteríamos a possibilidade de canalizar a saída de kdb export .

Talvez devêssemos até ter serializable em infos / status # 666 e falhar explicitamente se o arquivo for / dev / stdout?

Se qualquer coisa, eu teria um status humanreadable e me recusaria a exportar para um stdout tty, se o formato não fosse legível por humanos.

Funciona quando kdb export é chamado de root.

Retiro o que disse ... NÃO TENTE ISSO! Chamar kdb export <something> mmapstorage como usuário root (mesmo se stdout for redirecionado) destrói /dev/stdout . Usar /dev/stdout (por exemplo, via fopen ) não funcionará em seu sistema até que você recrie o link simbólico padrão com sudo rm /dev/stdout && sudo ln -s /dev/stdout /proc/self/fd/1 .

Acho que a melhor solução é que kdb export e kdb import sempre funcionam em arquivos temporários. Então kdb export será mais semelhante ao que o KDB faz. Isso resolveria o problema de desvinculação (que é necessário para arquivos mmaped). A desvantagem é apenas a perda de desempenho (é necessária uma cópia de todo o conteúdo), mas a importação / exportação funcionará com todos os plug-ins de armazenamento, o que é muito mais importante.

Acho que a melhor solução é que kdb export e kdb import sempre funcionam em arquivos temporários.

Acho que os próprios plug-ins devem criar o arquivo temporário, se necessário. Dessa forma, evitamos as penalidades de desempenho para plug-ins que podem produzir diretamente para TTYs. AFAIK mmapstorage é atualmente o único plugin que não funciona com TTYs. Também poderíamos adicionar um teste de shell simples que garante que todos os plug-ins de armazenamento possam ser chamados por meio de kdb export /some/key plugin > export.file . A lógica também é mais autocontida, porque na verdade é responsabilidade do plug-in saber como produzir a saída esperada.

Também para kdb import os arquivos temporários são desnecessários porque a leitura de um arquivo sempre deve funcionar, mesmo para TTYs (se você tiver as permissões corretas).

Acho que os próprios plug-ins devem criar o arquivo temporário, se necessário.

Então, os plug-ins (ou mais especificamente o mmap) precisam saber se ele é usado no KDB ou kdb export .

@mpranj Qual é a sua opinião? Isso pode ser corrigido dentro do plugin mmap?

Dessa forma, evitamos as penalidades de desempenho para plug-ins que podem produzir diretamente para TTYs.

Em quais casos essa penalidade de desempenho é um problema? Talvez no backup / restauração para cada caso de teste?

AFAIK mmapstorage é atualmente o único plugin que não funciona com TTYs.

Para exportação sim. Mas para importação tivemos vários plugins que não funcionam. Se um plugin usa fseek ou similar, obviamente não funciona, por exemplo, csvstorage ou mozprefs. (o despejo agora deve ser corrigido)

Também poderíamos adicionar um teste de shell simples que garante que todos os plug-ins de armazenamento possam ser chamados via kdb export / some / key plugin> export.file.

Você quer dizer tests / shell / check_export.sh linha 46?

Em quais casos essa penalidade de desempenho é um problema?

Na verdade, provavelmente nunca. Contanto que você use as versões de 3 argumentos de export / import em vez de piping. Veja a proposta abaixo.

Você quer dizer tests / shell / check_export.sh linha 46?

Sim, mas está quebrado, porque is_not_rw_storage não funciona. Nem mesmo dump é reconhecido como um plugin de armazenamento.


Acho que para resolver isso de forma rápida e fácil, devemos fazer o seguinte:

  1. Corrija is_not_rw_storage em include_common.sh.in tests/shell/check_export.sh para que possamos detectar problemas como este no futuro.
  2. Em kdb export crie um arquivo temporário, somente se nenhum terceiro argumento for fornecido. Use este arquivo nas chamadas kdbSet e depois copie e imprima seu conteúdo para stdout (não deve ter mais de uma ou duas linhas em C ++).
  3. Da mesma forma, para kdb import crie um arquivo temporário se stdin for usado. Copie todo o stdin para o arquivo temporário e use este arquivo para chamar kdbGet .
  4. Atualize a documentação de kdb import e kdb export para afirmar que o terceiro argumento existe. Afirme também que, se a versão de dois argumentos for usada, criaremos um arquivo temporário.

PS. Isso pode ser good first issue

Obrigado por relatar que is_not_rw_storage está quebrado, abri # 2423

Desculpe , fiquei fora por uma semana, então não pude investigar.

As mensagens de erro do mmap podem ser enganosas. mmap() falha com EACCES ao tentar mapear arquivos não regulares. Pelo que sei, não funcionará no stdout. Também não funciona com canos, conforme discutido em # 2209.

De POSIX:

A função mmap () deve ser suportada para os seguintes objetos de memória:

  • Arquivos normais
  • [SHM] Objetos de memória compartilhada
  • [TYM] Objetos de memória digitados

Quanto às soluções dentro do mmapstorage, podemos verificar se é um arquivo normal com stat e então:

  • escrever em um arquivo regular temporário, como sugerido acima
  • escrever em um local de memória temporário (simplesmente malloc em vez de mmap) e, em seguida, copiar para o arquivo não regular (pipe, stdout, ..)

Estou aberto a outras soluções também. As soluções acima não mudam muito a lógica do mmapstorage. Retrabalhar o mmapstorage para trabalhar com tubos ou stdout diretamente não faz muito sentido para mim.

Obrigado por sua resposta!

As mensagens de erro do mmap podem ser enganosas.

Por favor, melhore as mensagens de erro.

Pelo que sei, não funcionará no stdout. Também não funciona com tubos

Adicione essa informação às mensagens de erro.

As soluções acima não mudam muito a lógica do mmapstorage.

Como seu plugin é atualmente o único afetado, faz sentido que você faça o stat e copie tudo se necessário. Então poderíamos fechar este problema sem grandes mudanças na estrutura.

Então poderíamos fechar este problema sem grandes mudanças na estrutura.

Também devemos atualizar as páginas de manual de kdb import e kdb export . Atualmente eles não mencionam as 3 versões do argumento que não dependem de stdin / stdout.

Obrigado por relatar o problema e por sua contribuição!

Infelizmente, strerror imprime essas mensagens de erro enganosas. Posso adicionar uma dica nesse caso.

Farei as alterações solicitadas em um PR esta semana.

Devemos também atualizar as páginas de manual para importação e exportação de kdb. Atualmente eles não mencionam as 3 versões do argumento que não dependem de stdin / stdout.

Talvez não precisemos do argumento para especificar o arquivo? O argumento entraria em conflito quando kdb import/export oferecer suporte a vários plug-ins.

Farei as alterações solicitadas em um PR esta semana.

Obrigado!

Talvez não precisemos do argumento para especificar o arquivo?

Então temos que suportar stdin e stdout (redirecionado para um arquivo normal) em todos os plug-ins. Caso contrário, eles nunca poderiam ser usados ​​com kdb import/export . Isso faz sentido para mmapstorage porque não é portátil, mas outros plug-ins que são portáveis ​​(talvez até mesmo legíveis) podem precisar de um arquivo regular também (por exemplo, se eles usarem fseek ).

O argumento entraria em conflito quando kdb import/export oferecer suporte a vários plug-ins.

Poderíamos facilmente passar a usar as opções -i FILE, --input=FILE , -o FILE, --ouput=FILE quando passarmos a usar elektraGetOpts .

Sim, podemos adicionar as opções -i, -o. Mas consertar os plug-ins (ou a estrutura de importação / exportação) para que stdin / stdout funcione seria bom em qualquer caso.

Para corrigir este problema com kdb export , é suficiente implementar a solução alternativa na função plugin-> kdbSet (). Já implementei isso, PR logo virá.

Isso funciona agora: kdb import user/tests/ mmapstorage < test.mmap ,
mas isso não: cat test.mmap | kdb import user/tests/ mmapstorage , já que novamente o mmap não pode lidar com isso.

Para tornar a solução consistente (portanto, totalmente compatível com arquivos não regulares), seria necessário resolvê-la também para a função kdbGet (). Existem aproximadamente três soluções para isso:

  1. escreva para um arquivo temporário e desvincule-o (uma solução um tanto feia, mas simples)
  2. retrabalho metade do meu trabalho de mmap (feio e muito trabalho)
  3. faça muitas cópias e reimplemente o ksDeepDup para fazer cópias de meta-conjuntos de chaves também (realmente feio, código semi-simples)

Algo disso é desejável ou nós o ignoramos?

Acho que podemos ignorar por enquanto, pois já temos o quickdump. Basta documentar como não sendo adequado para serialização. Agora iremos retrabalhar a estrutura de importação / exportação de qualquer maneira, então encontraremos uma solução adequada. @mpranj Eu

Na verdade, talvez seja melhor se # 2639 fechar este problema e @mpranj você criar um novo para o problema cat ... .

2639 fecha todos os problemas aqui. Funciona bem no Linux, eu só preciso consertar um bug para que funcione nos BSDs também.

Tive uma solução muito boa (usando realpath e stat ) que infelizmente não funcionará em BSDs. Não faz sentido investir muito mais tempo nisso.

Decidi jogá-lo fora, tornando o mmapstorage completamente compatível com arquivos não regulares. Só funcionará com importação / exportação de kdb. A nova solução irá simplesmente verificar se a importação / exportação kdb é usada, verificando se o arquivo é " /dev/stdin " ou " /dev/stdout ". É feito de forma semelhante em quickdump .

Tive uma solução muito boa (usando realpath e stat) que infelizmente não funcionará em BSDs.

Esta é a solução comentada?

Não faz sentido investir muito mais tempo nisso.

Você está certo, a estrutura deve lidar com isso. Eu criei # 2640.

só funcionará com importação / exportação kdb

Também com a variante cat | kdb import ?

É feito de forma semelhante no quickdump.

Onde estão as diferenças?

Este código pode ser movido para a estrutura de importação / exportação?

Esta é a solução comentada?

Eu deixei no histórico, mas removi as linhas depois. A melhor solução imho foi até https://github.com/ElektraInitiative/libelektra/pull/2639/commits/a523f9b38b56687d532f5101c7ef44c078e2308d. Observe que funcionou bem no Linux, mas não no BSD.

Um problema que encontrei é que stdin / stdout não pode ser open () ed em BSDs. A outra é que você realmente precisa usar o realpath para stat () o arquivo e determinar se é um arquivo normal. Caso contrário, o stat resolveu apenas um nível de links simbólicos para mim. Essa abordagem falhou em BSDs para mim, porque realpath resolveu para um arquivo inexistente de alguma forma.

Também com o gato | variante de importação kdb?

Sim!

Onde estão as diferenças?

A parte relevante é a mesma, desculpe a confusão. O que eu quis dizer é que strcmp para / dev / stdin em vez de usar stat para determinar se é um arquivo regular. Isso significa que ainda falhará se usarmos / dev / fd /. Minha outra solução usava stat em vez de strcmp, então funcionava com qualquer caminho.

Editar :

Este código pode ser movido para a estrutura de importação / exportação?

Sim, acho que o código estava quase completamente lá, mas não tive tempo de consertar os problemas do BSD adequadamente.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

dominicjaeger picture dominicjaeger  ·  3Comentários

dmoisej picture dmoisej  ·  3Comentários

markus2330 picture markus2330  ·  3Comentários

markus2330 picture markus2330  ·  4Comentários

sanssecours picture sanssecours  ·  3Comentários