Libelektra: mmapstorage no funciona con la exportación de kdb

Creado en 15 feb. 2019  ·  22Comentarios  ·  Fuente: ElektraInitiative/libelektra

Pasos para reproducir el 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

Se crea un archivo llamado test.mmap , que se puede volver a importar con kdb import .

Resultado actual

Se crea un archivo vacío llamado test.mmap y se imprime el siguiente mensaje (incluye registros 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

Información del sistema

  • Versión de Elektra: maestro

Más información

~ Funciona cuando se llama a kdb export como root. ~ (EDITAR: ver comentario a continuación) kdb export user/tests/hello mmapstorage test.mmap también funciona, pero es una característica completamente indocumentada de kdb export . Entonces, un mejor mensaje de error y documentación actualizada podría ser todo lo que necesitamos.

bug

Comentario más útil

¡Gracias por su respuesta!

Los mensajes de error de mmap pueden ser engañosos.

Mejore los mensajes de error.

Que yo sepa, no funcionará en stdout. Tampoco funciona con tuberías.

Agregue esa información a los mensajes de error.

Las soluciones anteriores no cambian mucho la lógica de mmapstorage.

Como su complemento es actualmente el único afectado, tiene sentido que haga la estadística y copie todo si es necesario. Entonces podríamos cerrar este problema sin mayores cambios en el marco.

Todos 22 comentarios

¡Gracias por probar esto y por este informe detallado!

Entonces, un mejor mensaje de error y documentación actualizada podría ser todo lo que necesitamos.

Sí, estoy totalmente de acuerdo.

¿Quizás incluso deberíamos tener un serializable en infos / status # 666 y fallar explícitamente si el archivo es / dev / stdout? ( @mpranj ¿ O hay alguna manera de detectar si un archivo no es mmapable? ¿Es realmente idéntico a un permiso denegado?)

Mirando el código (y el mensaje de error), creo que el problema actual es que no podemos llamar a unlink en stdout sin acceso de root. Además, open probablemente también fallará, porque stdout ya está abierto. Y si stdout es mmapable o no depende de lo que stdout esté conectado, creo.
Usar fstat(fileno(stdout), &stat) para verificar si es un archivo normal podría funcionar. Quizás isatty(3) también funcione.

En cualquier caso, podríamos simplemente verificar si el archivo de salida es /dev/stdout (o CON por _WIN32 ) y crear un archivo temporal para usar con mmap y luego simplemente copiarlo en stdout . Por supuesto, sería más lento pero mantendríamos la posibilidad de canalizar la salida de kdb export .

¿Quizás incluso deberíamos tener un serializable en infos / status # 666 y fallar explícitamente si el archivo es / dev / stdout?

En todo caso, tendría un estado humanreadable y me negaría a exportar a un stdout tty, si el formato no es legible por humanos.

Funciona cuando se llama a kdb export como root.

Retiro eso ... ¡NO INTENTE ESO! Llamar a kdb export <something> mmapstorage como usuario root (incluso si se redirige stdout) destruye /dev/stdout . El uso de /dev/stdout (por ejemplo, a través de fopen ) no funcionará en su sistema hasta que vuelva a crear el enlace simbólico predeterminado con sudo rm /dev/stdout && sudo ln -s /dev/stdout /proc/self/fd/1 .

Creo que la mejor solución es que kdb export y kdb import siempre funcionan en archivos temporales. Entonces kdb export será más similar a lo que hace KDB. Esto resolvería el problema de desvinculación (que es necesario para archivos mmaped). La desventaja es solo la pérdida de rendimiento (se necesita una copia de todo el contenido), pero luego la importación / exportación funcionará con todos los complementos de almacenamiento, lo cual es en mi humilde opinión mucho más importante.

Creo que la mejor solución es que kdb export y kdb import siempre funcionan en archivos temporales.

Creo que los complementos deberían crear el archivo temporal ellos mismos, si es necesario. De esa forma, evitamos las penalizaciones de rendimiento de los complementos que pueden enviar directamente a TTY. AFAIK mmapstorage es actualmente el único complemento que no funciona con TTY. También podríamos agregar una prueba de shell simple que garantice que todos los complementos de almacenamiento se puedan llamar a través de kdb export /some/key plugin > export.file . La lógica también es más autónoma, porque realmente es responsabilidad de los complementos saber cómo producir el resultado esperado.

Además, para kdb import los archivos temporales son innecesarios porque leer un archivo siempre debería funcionar, incluso para TTY (si tiene los permisos correctos).

Creo que los complementos deberían crear el archivo temporal ellos mismos, si es necesario.

Entonces los complementos (o más específicamente mmap) necesitarían saber si se usa dentro de KDB o kdb export .

@mpranj ¿Cuál es tu opinión? ¿Se puede solucionar esto dentro del complemento mmap?

De esa forma, evitamos las penalizaciones de rendimiento de los complementos que pueden enviar directamente a TTY.

¿En qué casos es un problema esta penalización por desempeño? ¿Quizás en la copia de seguridad / restauración para cada caso de prueba?

AFAIK mmapstorage es actualmente el único complemento que no funciona con TTY.

Para exportar si. Pero para la importación teníamos varios complementos que no funcionan. Si un complemento usa fseek o similar, obviamente no puede funcionar, por ejemplo, csvstorage o mozprefs. (el volcado ahora debería estar arreglado)

También podríamos agregar una prueba de shell simple que garantice que todos los complementos de almacenamiento se puedan llamar a través de kdb export / some / key plugin> export.file.

¿Te refieres a tests / shell / check_export.sh línea 46?

¿En qué casos es un problema esta penalización por desempeño?

De hecho, probablemente nunca. Siempre que utilice las versiones de 3 argumentos de exportación / importación en lugar de canalizar. Vea la propuesta a continuación.

¿Te refieres a tests / shell / check_export.sh línea 46?

Sí, pero eso está roto, porque is_not_rw_storage no funciona. Ni siquiera dump se reconoce como un complemento de almacenamiento.


Creo que para solucionar esto rápida y fácilmente deberíamos hacer lo siguiente:

  1. Arregle is_not_rw_storage en include_common.sh.in tests/shell/check_export.sh para que detectemos problemas como este en el futuro.
  2. En kdb export cree un archivo temporal, solo si no se proporciona un tercer argumento. Utilice este archivo en las llamadas kdbSet y luego copie, imprima su contenido en la salida estándar (no debe tener más de una o dos líneas en C ++).
  3. De manera similar, para kdb import cree un archivo temporal si se usa stdin. Copie todo stdin en el archivo temporal y use este archivo para llamar a kdbGet .
  4. Actualice la documentación de kdb import y kdb export para indicar que existe el tercer argumento. Indique también que si se usa la versión de dos argumentos, creamos un archivo temporal.

PD. Esto podría ser good first issue

Gracias por informar que is_not_rw_storage está roto, abrí # 2423

Lo siento , estuve fuera una semana, así que no pude investigarlo.

Los mensajes de error de mmap pueden ser engañosos. mmap() falla con EACCES al intentar mapear archivos no regulares. Que yo sepa, no funcionará en stdout. Tampoco funciona con tuberías, como se explica en el n. ° 2209.

Desde POSIX:

La función mmap () será compatible con los siguientes objetos de memoria:

  • Archivos regulares
  • [SHM] Objetos de memoria compartida
  • [TYM] Objetos de memoria escritos

En cuanto a las soluciones dentro de mmapstorage, podemos verificar si es un archivo normal con stat y luego:

  • escribir en un archivo regular temporal, como se sugirió anteriormente
  • escriba en una ubicación de memoria temporal (simplemente malloc en lugar de mmap) y luego copie al archivo no regular (pipe, stdout, ..)

También estoy abierto a otras soluciones. Las soluciones anteriores no cambian mucho la lógica de mmapstorage. Reelaborar mmapstorage para trabajar con tuberías o stdout directamente no tiene mucho sentido para mí.

¡Gracias por su respuesta!

Los mensajes de error de mmap pueden ser engañosos.

Mejore los mensajes de error.

Que yo sepa, no funcionará en stdout. Tampoco funciona con tuberías.

Agregue esa información a los mensajes de error.

Las soluciones anteriores no cambian mucho la lógica de mmapstorage.

Como su complemento es actualmente el único afectado, tiene sentido que haga la estadística y copie todo si es necesario. Entonces podríamos cerrar este problema sin mayores cambios en el marco.

Entonces podríamos cerrar este problema sin mayores cambios en el marco.

También deberíamos actualizar las páginas de manual para kdb import y kdb export . Actualmente no mencionan las 3 versiones de argumentos que no se basan en stdin / stdout.

¡Gracias por informar del problema y por los comentarios!

Desafortunadamente, strerror imprime estos mensajes de error engañosos. Puedo agregar una pista en ese caso.

Haré los cambios solicitados en un PR esta semana.

También deberíamos actualizar las páginas man para kdb import y kdb export. Actualmente no mencionan las 3 versiones de argumentos que no se basan en stdin / stdout.

¿Quizás no necesitamos el argumento para especificar el archivo? El argumento entraría en conflicto una vez que kdb import/export admita múltiples complementos.

Haré los cambios solicitados en un PR esta semana.

¡Gracias!

¿Quizás no necesitamos el argumento para especificar el archivo?

Luego, tenemos que admitir stdin y stdout (redirigidos a un archivo normal) en todos los complementos. De lo contrario, nunca podrían usarse con kdb import/export . Eso tiene sentido para mmapstorage porque no es portátil, pero otros complementos que son portátiles (tal vez incluso legibles por humanos) también pueden necesitar un archivo normal (por ejemplo, si usan fseek ).

El argumento entraría en conflicto una vez que kdb import/export admita múltiples complementos.

Podríamos pasar fácilmente a usar las opciones -i FILE, --input=FILE , -o FILE, --ouput=FILE cuando cambiemos a usar elektraGetOpts .

Sí, podemos agregar las opciones -i, -o. Pero arreglar los complementos (o el marco de importación / exportación) para que también funcione stdin / stdout sería bueno en cualquier caso.

Para solucionar este problema con kdb export es suficiente implementar la solución en la función plugin-> kdbSet (). Ya he implementado esto, PR pronto vendrá.

Esto funciona ahora: kdb import user/tests/ mmapstorage < test.mmap ,
pero esto no: cat test.mmap | kdb import user/tests/ mmapstorage , ya que nuevamente mmap no puede manejarlo.

Para que la solución sea consistente (por lo tanto, completamente compatible con archivos no regulares) también sería necesario resolverla para la función kdbGet (). Hay aproximadamente tres soluciones para esto:

  1. escribir en un archivo temporal y desvincularlo (solución algo fea, pero simple)
  2. reelaborar la mitad de mi trabajo de mmap (feo y mucho trabajo)
  3. haga muchas copias y vuelva a implementar ksDeepDup para hacer copias de meta-conjuntos de claves también (código realmente feo, semi-simple)

¿Es algo de esto deseable o lo ignoramos?

Creo que podemos ignorarlo por ahora, ya que tenemos quickdump. Simplemente documente que no es adecuado para la serialización. Ahora volveremos a trabajar el marco de importación / exportación de todos modos, luego encontraremos una solución adecuada. @mpranj Te

En realidad, quizás sea mejor si # 2639 cierra este problema y @mpranj crea uno nuevo para el problema cat ... .

2639 cierra todos los problemas aquí. Funciona bien en Linux, solo necesito corregir un error para que también funcione en los BSD.

Tuve una solución realmente agradable (usando realpath y stat ) que desafortunadamente no funcionará en BSD. No tiene sentido invertir mucho más tiempo en ello.

He decidido tirarlo, por lo que mmapstorage no es completamente compatible con archivos no regulares. Solo funcionará con kdb import / export. La nueva solución simplemente comprobará si se utiliza kdb import / export, comprobando si el archivo es " /dev/stdin " o " /dev/stdout ". Se hace de manera similar en quickdump .

Tuve una solución realmente buena (usando realpath y stat) que desafortunadamente no funcionará en BSD.

¿Esta es la solución comentada?

No tiene sentido invertir mucho más tiempo en ello.

Tienes razón, el marco debería manejar esto. Creé el # 2640.

solo funcionará con kdb import / export

¿También con la variante cat | kdb import ?

Se hace de manera similar en quickdump.

¿Dónde están las diferencias?

¿Se puede mover este código al marco de importación / exportación?

¿Esta es la solución comentada?

Lo dejé en la historia pero eliminé las líneas más tarde. La mejor solución en mi humilde opinión fue hasta https://github.com/ElektraInitiative/libelektra/pull/2639/commits/a523f9b38b56687d532f5101c7ef44c078e2308d. Tenga en cuenta que funcionó bien en Linux pero no en BSD.

Un problema que encontré es que stdin / stdout no se puede abrir () ed en BSD. La otra es que realmente tienes que usar la ruta real para stat () el archivo y determinar si es un archivo normal. De lo contrario, las estadísticas solo resolvieron un nivel de enlaces simbólicos para mí. Este enfoque falló en los BSD para mí, porque realpath se resolvió de alguna manera en un archivo inexistente.

También con el gato | variante de importación kdb?

¡Sí!

¿Dónde están las diferencias?

La parte relevante es la misma, perdón por la confusión. Lo que quise decir es que strcmp para / dev / stdin en lugar de usar stat para determinar si es un archivo normal. Eso significa que aún fallará si usamos / dev / fd /. Mi otra solución usó stat en lugar de strcmp, por lo que funcionó con cualquier ruta.

Editar :

¿Se puede mover este código al marco de importación / exportación?

Sí, creo que el código estaba casi por completo, pero no tuve tiempo de solucionar los problemas de BSD correctamente.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

sanssecours picture sanssecours  ·  4Comentarios

markus2330 picture markus2330  ·  4Comentarios

mpranj picture mpranj  ·  3Comentarios

mpranj picture mpranj  ·  3Comentarios

markus2330 picture markus2330  ·  3Comentarios