Tengo algunos archivos muy grandes (> 4 GB) que contienen (millones de) registros binarios de longitud fija. Quiero (eficientemente) unirlos a registros en otros archivos escribiendo punteros (es decir, números de registro de 64 bits) en esos registros en desplazamientos específicos.¿La forma más rápida de hacer muchas escrituras pequeñas, ciegas en un archivo enorme (en C++)?
Para elaborar, tengo un par de listas de tuplas (clave, número de registro) ordenadas por clave para cada unión que quiero realizar en un par de archivos dado, por ejemplo, A y B. iteración a través de un par de lista y Al hacer coincidir las teclas, se obtiene una lista de tuplas (clave, número de registro A, número de registro B) que representan los registros combinados (suponiendo una asignación de 1: 1 para simplificar). Para completar la unión, conceptualmente necesito buscar cada registro A en la lista y escribir el número de registro B correspondiente en el desplazamiento apropiado, y viceversa. Mi pregunta es ¿cuál es la forma más rápida de hacer esto?
Dado que la lista de registros unidos se ordena por clave, los números de registro asociados son esencialmente aleatorios. Suponiendo que el archivo es mucho más grande que la memoria caché de disco del sistema operativo, hacer muchas búsquedas y escrituras aleatorias parece extremadamente ineficiente. Intenté clasificar parcialmente los números de registro colocando las asignaciones A-> B y B-> A en una matriz dispersa, y vaciando los grupos más densos de entradas en el disco cada vez que me quedo sin memoria. Esto tiene el beneficio de aumentar en gran medida las posibilidades de que los registros apropiados se almacenen en caché para un clúster después de actualizar su primer puntero. Sin embargo, incluso en este punto, ¿es generalmente mejor hacer un montón de búsquedas y escrituras ocultas, o leer fragmentos del archivo manualmente, actualizar los punteros apropiados y volver a escribir los fragmentos? Si bien el método anterior es mucho más simple y el sistema operativo lo puede optimizar para hacer el mínimo de lecturas del sector (dado que conoce el tamaño del sector) y las copias (puede evitar copias leyendo directamente en búferes alineados correctamente), parece que incurrirá en una sobrecarga de syscall extremadamente alta.
Si bien me encantaría una solución portátil (incluso si implica una dependencia de una biblioteca ampliamente utilizada, como Boost), Windows y Linux modernos son los únicos imprescindibles, así que puedo hacer uso de sistemas operativos específicos API (por ejemplo, sugerencias de CreateFile o scatter/gather I/O). Sin embargo, esto puede implicar mucho trabajo incluso para probar, por lo que me pregunto si alguien me puede decir si merece la pena el esfuerzo.
¿Se han corregido los archivos o se actualizarán? – Steve314
Si está bien monopolizar la caché de disco, intente con CreateFile: FILE_ATTRIBUTE_TEMPORARY (y asigne el archivo a su espacio de direcciones). Sin embargo, es específico de la plataforma. –
@ Steve314: los archivos se combinan en una base de datos de solo lectura después de completar las uniones. @jdv: actualmente estoy usando FILE_ATTRIBUTE_TEMPORARY en Windows. Dado que los archivos tienden a ser más grandes que la memoria, los accesos aleatorios probablemente no pegan en la memoria caché del disco muchas veces. La clasificación parcial debería abordar eso, pero las escrituras individuales todavía parecen realmente lentas. Quizás el mapeo de memoria es el ingrediente final. –