Cómo tener un archivo de punto de control usando mmap que solo se sincroniza con el disco manualmente

8 minutos de lectura

Necesito la forma más rápida de sincronizar periódicamente el archivo con la memoria.

Lo que creo que me gustaría es tener un archivo mmap’d, que solo se sincroniza con el disco manualmente. No estoy seguro de cómo evitar que ocurra una sincronización automática.

El archivo no se puede modificar excepto en los tiempos que especifique manualmente. El punto es tener un archivo de punto de control que mantenga una instantánea del estado en la memoria. Me gustaría evitar copiar tanto como sea posible, ya que será necesario llamar con bastante frecuencia y la velocidad es importante.

Cualquier cosa que escribas en la memoria dentro de un MAP_SHARED la asignación de un archivo se considera escrita en el archivo en ese momento, como si hubiera utilizado write(). msync() en este sentido es completamente análoga a fsync() – simplemente asegura que los cambios que ha realizado ya está hecho al archivo se envían al almacenamiento permanente. No puedes cambiar esto, es cómo mmap() está definido para trabajar.

En general, la forma segura de hacer esto es escribir una copia coherente completa de los datos en un archivo temporal, sincronizar el archivo temporal y luego renombrarlo atómicamente sobre el archivo de punto de control anterior. Esta es la única forma de asegurarse de que un bloqueo entre los puntos de control no lo deje con un archivo inconsistente. Cualquier solución que haga menos copias requerirá un formato de archivo de estilo de registro de transacciones más complicado y será más intrusivo para el resto de su aplicación (requiriendo que se invoquen ganchos específicos en cada lugar donde se cambia el estado en memoria) .

mmap no se puede utilizar para este propósito. No hay forma de evitar que los datos se escriban en el disco. En la práctica, usando mlock() para hacer que la memoria no se pueda intercambiar puede que tiene el efecto secundario de evitar que se escriba en el disco, excepto cuando solicite que se escriba, pero no hay garantía. Ciertamente, si otro proceso abre el archivo, verá la copia en caché en la memoria (con sus últimos cambios), no la copia en el disco físico. En muchos sentidos, lo que debe hacer depende de si está tratando de sincronizar con otros procesos o simplemente por seguridad en caso de falla o corte de energía.

Si el tamaño de sus datos es pequeño, puede probar otros métodos para la sincronización atómica con el disco. Una forma es almacenar todo el conjunto de datos en un nombre de archivo y crear un archivo vacío con ese nombre, luego eliminar el archivo anterior. Si existen 2 archivos al inicio (debido a un tiempo de bloqueo extremadamente improbable), elimine el anterior y reanude desde el más nuevo. write() mayo también sea atómico si el tamaño de sus datos es más pequeño que un bloque de sistema de archivos, tamaño de página o bloque de disco, pero no conozco ninguna garantía en ese sentido. Tendrías que investigar un poco.

Otro enfoque muy estándar que funciona siempre que sus datos no sean tan grandes que 2 copias no quepan en el disco: simplemente cree una segunda copia con un nombre temporal, luego rename() encima de la anterior. rename() siempre es atómico. Este es probablemente el mejor enfoque a menos que tenga una razón para no hacerlo de esa manera.

  • No hay necesidad de sincronizar procesos. Es más una copia de seguridad. También me gustaría evitar hacer cualquier tipo de copia si es posible. Los datos también tienen al menos 50 MB.

    – arsén

    30 de junio de 2010 a las 4:56

Como tener un archivo de punto de control usando mmap
James Caccese

Tú podrías mmap() el archivo como copia en escritura para que cualquier actualización que haga en la memoria no se vuelva a escribir en el archivo, luego, cuando desee sincronizar, podría:

A) Cree una nueva asignación de memoria que no se copie al escribir y copie solo las páginas que modificó en ella.

O

B) Abra el archivo (archivo normal abierto) con E/S directa (lectura y escritura de tamaño de bloque alineado) y escriba solo las páginas que modificó. La E/S directa sería agradable y rápida porque está escribiendo páginas completas (el tamaño de la página de memoria es un múltiplo del tamaño del bloque del disco) y no hay almacenamiento en búfer. Este método tiene la ventaja de no utilizar el espacio de direcciones en caso de que su mmap() es grande y no hay espacio para mmap() otro archivo enorme.

Después de la sincronización, su copia en escritura mmap() es el mismo que su archivo de disco, pero el núcleo aún tiene las páginas que necesitaba sincronizar marcadas como no compartidas (con el disco). Entonces puede cerrar y volver a crear el mmap() (todavía copiar en escritura) de esa manera, el kernel puede descartar sus páginas si es necesario (en lugar de paginarlas para intercambiar espacio) si hay presión de memoria.

Por supuesto, tendría que hacer un seguimiento de las páginas que usted mismo modificó porque no puedo pensar en cómo obtendría acceso a dónde el sistema operativo guarda esa información. (¿No sería útil syscall()?)

— editar —

En realidad, consulte ¿Se puede encontrar la suciedad de las páginas de un mmap desde el espacio de usuario? para obtener ideas sobre cómo ver qué páginas están sucias.

  • Su respuesta clavó mis pensamientos sobre esto hasta ahora. El factor decisivo es el marcador de página sucia. ¿Cómo saber cuándo está sucio?

    – Matt Carpintero

    8 de diciembre de 2011 a las 9:49

1646971148 416 Como tener un archivo de punto de control usando mmap
llasram

Como han sugerido los otros encuestados, no creo que haya una forma portátil de hacer lo que quieras sin copiar. Si está buscando hacer esto en un entorno de propósito especial donde puede controlar el sistema operativo, etc., puede hacerlo en Linux con el sistema de archivos btrfs.

btrfs admite un nuevo reflink() operación que es esencialmente una copia del sistema de archivos de copia en escritura. Tú podrías reflink() su archivo a un temporal en el inicio, mmap() lo temporal, entonces msync() y reflink() el temporal de vuelta al original al punto de control.

Como tener un archivo de punto de control usando mmap
ganso nate

Sospecho que ningún sistema operativo puede aprovechar eso, pero sería posible que un sistema operativo notara optimizaciones para:

int fd = open("file", O_RDWR | O_SYNC | O_DIRECT);

size_t length = get_lenght(fd);

uint8_t * map_addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);

...

// This represents all of the changes that could possibly happen before you
// want to update the on disk file.
change_various_data(map_addr);

if (is_time_to_update()) {
   write(fd, map_addr, length);
   lseek(fd, 0, SEEK_SET);
   // you could have just used pwrite here and not seeked
}

Las razones por las que un sistema operativo pudo posiblemente aproveche esto es que hasta que escriba en una página en particular (y nadie más lo hizo), el sistema operativo probablemente solo use la página del archivo real en esa ubicación como intercambio para esa página.

Luego, cuando escribiste en algún conjunto de esas páginas, el sistema operativo Dupdo En Escribe esas páginas para su proceso, pero mantenga las páginas no escritas respaldadas por el archivo original.

Entonces, al llamar write el sistema operativo pudo notar que la escritura estaba alineada en bloques tanto en la memoria como en el disco, y luego pudo notar que algunas de las páginas de la memoria de origen ya estaban sincronizadas con las páginas exactas del sistema de archivos en las que se estaban escribiendo y solo escribieron el páginas que habían cambiado.

Habiendo dicho todo eso, no me sorprendería si ningún sistema operativo realiza esta optimización, y este tipo de código termina siendo muy lento y causa mucha escritura en el disco cuando llama ‘escribir’. Sería genial si se aprovechara.

  • @Matt Joiner: ¿De qué se trata tu ‘wtf’? Esto es esencialmente lo mismo que la sección B de la respuesta de James Caccese que dijo que clavó sus pensamientos, excepto que permite que el kernel del sistema operativo, que tiene acceso a los bits sucios, tome la decisión de escribir o no escribir cada página. Excepto por la parte en la que no sé si algún *nix realmente hace esto. Aunque es la misma idea.

    – ganso nate

    8 de diciembre de 2011 a las 14:58

  • @nategoose, ¿ha realizado alguna prueba para demostrar que cualquier sistema operativo puede aprovechar el hecho de que la región mmap privada es la misma que el archivo subyacente después de su pwrite, de modo que solo conserva una copia de memoria para mmap privado y caché de archivos? ? No creo que el sistema operativo actual pueda hacer esta optimización.

    – Kan Li

    23 mayo 2012 a las 12:40

  • @Matt Joiner: ¿De qué se trata tu ‘wtf’? Esto es esencialmente lo mismo que la sección B de la respuesta de James Caccese que dijo que clavó sus pensamientos, excepto que permite que el kernel del sistema operativo, que tiene acceso a los bits sucios, tome la decisión de escribir o no escribir cada página. Excepto por la parte en la que no sé si algún *nix realmente hace esto. Aunque es la misma idea.

    – ganso nate

    8 de diciembre de 2011 a las 14:58

  • @nategoose, ¿ha realizado alguna prueba para demostrar que cualquier sistema operativo puede aprovechar el hecho de que la región mmap privada es la misma que el archivo subyacente después de su pwrite, de modo que solo conserva una copia de memoria para mmap privado y caché de archivos? ? No creo que el sistema operativo actual pueda hacer esta optimización.

    – Kan Li

    23 mayo 2012 a las 12:40

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad