es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

“Sistema de archivos de solo lectura ‘Just in time’ utilizando mkfifo e inotifywait”

Estoy escribiendo un middleware bastante básico, básicamente tengo código antiguo que necesita abrir 100.000 archivos solo para lectura, esperando que todos estén en una carpeta. Nunca escribe. Es multiproceso, por lo que puede intentar abrir ~30 archivos al mismo tiempo. De la forma antigua, tendría que copiar los archivos en esa carpeta (o usar enlaces, NFS, etc.). Vale la pena mencionar que no tengo la capacidad de cambiar este código antiguo, es solo un binario.

Tengo un código nuevo y sofisticado que puede recuperar un archivo casi instantáneamente. Quiero unir estas cosas, para que cuando el código antiguo intente abrir el archivo, en realidad, en tiempo real, se ejecute el nuevo código.

Entonces pensé en utilizar mkfifo e inotifywait. En lugar de una carpeta con 100.000 archivos, puedo crear una carpeta con 100.000 tuberías con nombre. Hasta aquí todo bien. El código heredado intenta abrir los archivos, sin saber que en realidad son tuberías con nombre. El problema es que no sé en qué orden el código heredado va a abrir los archivos (genial, ¿no?). Así que me gustaría DISPARAR la ESCRITURA en la tubería con nombre (desde mi nuevo código sofisticado) cuando el código heredado intente leer. No puedo generar 100.000 escrituras y hacer que todas se bloqueen. Así que pensé, hey, tiene sentido usar inotifywait. Cada vez que el código heredado intenta abrir la tubería, se desencadena un evento de lectura que luego se puede usar para generar la escritura de la tubería en segundo plano. El problema es… ¡inotifywait no desencadena el evento de lectura hasta DESPUÉS de haber generado el escritor!

¿Alguna idea de cómo resolver esto? Básicamente, quiero interceptar una apertura de archivo, bloquearme durante unos cientos de ms mientras recupero el contenido del archivo y luego devolver ese contenido. Idealmente no quiero crear un sistema de archivos FUSE personalizado para hacer esto… es solo una apertura de archivo de solo lectura. El problema es que esto debe ejecutarse rápido y en paralelo… y no sé en qué orden se abrirán los archivos. ¡Tiene que haber una manera rápida y sencilla!

Gracias de antemano por el tiempo de todos.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una posible solución a este problema podría ser utilizar la biblioteca FUSE (Filesystem in Userspace). Con FUSE, puedes crear un sistema de archivos virtual que intercepta operaciones de archivo como abrir, leer y escribir, y proporciona implementaciones personalizadas para ellas. De esta manera, puedes interceptar la operación de apertura de archivos, bloquearte por un corto tiempo mientras recuperas el contenido del archivo desde tu nuevo código y devolver el contenido al código heredado.

    Para implementar esto, primero necesitarías crear un sistema de archivos FUSE utilizando la biblioteca FUSE. En tu implementación del sistema de archivos, proporcionarías implementaciones personalizadas para las operaciones de apertura y lectura. Cuando el código heredado abre un archivo en tu sistema de archivos virtual, tu implementación de apertura interceptaría la operación, llamaría a tu nuevo código para recuperar el contenido del archivo y devolvería un descriptor de archivo al código heredado. Cuando el código heredado realiza una operación de lectura en el descriptor de archivo, tu implementación de lectura interceptaría la operación y devolvería el contenido del archivo que recuperaste desde tu nuevo código.

    Con este enfoque, no necesitas crear 100.000 pipes nombrados ni usar inotifywait. En cambio, creas un sistema de archivos virtual con una implementación personalizada que intercepta las operaciones de archivo a medida que se realizan por el código heredado. El inconveniente de este enfoque es que necesitas crear un sistema de archivos FUSE personalizado, lo cual puede ser más trabajo del que deseas hacer. Sin embargo, si esperas encontrar problemas similares en el futuro, este enfoque podría ser una buena inversión.

    Otra posible solución es utilizar una técnica llamada “truco LD_PRELOAD”. LD_PRELOAD es una variable de entorno que se puede utilizar para especificar una biblioteca compartida que debe cargarse antes que otras bibliotecas. Al crear una biblioteca compartida que intercepte la operación de apertura de archivos, puedes reemplazar la llamada de apertura del código heredado con tu propia implementación personalizada que recupera el contenido del archivo desde tu nuevo código. De esta manera, puedes interceptar la operación de apertura de archivos sin necesidad de crear un sistema de archivos personalizado.

    Para implementar esto, primero crearías una biblioteca compartida que intercepte la operación de apertura de archivos, llame a tu nuevo código para recuperar el contenido del archivo y luego devuelva el contenido a la función llamante. Luego, establecerías la variable de entorno LD_PRELOAD con la ruta de tu biblioteca compartida y ejecutarías el código heredado normalmente. Cuando el código heredado llama a la función de apertura para abrir un archivo, tu biblioteca compartida intercepta la llamada, recupera el contenido del archivo desde tu nuevo código y lo devuelve al código heredado. De esta manera, puedes interceptar la operación de apertura de archivos sin cambiar el código heredado.

    Cabe señalar que el uso de LD_PRELOAD puede ser complicado, ya que requiere que entiendas los detalles internos del código heredado y las bibliotecas que utiliza. Además, LD_PRELOAD puede causar problemas de compatibilidad con otras bibliotecas que utiliza el código heredado. Sin embargo, si se hace correctamente, puede ser una solución rápida y efectiva para este problema.

Comments are closed.