¿Cómo se pueden borrar los datos escritos en un archivo realmente con Java/sincronizado con el dispositivo de bloques?Realmente fuerza la sincronización/enrasado de archivos en Java
yo probamos este código con NIO:.
FileOutputStream s = new FileOutputStream(filename)
Channel c = s.getChannel()
while(xyz)
c.write(buffer)
c.force(true)
s.getFD().sync()
c.close()
supone que c.force (verdadero) togehter de la s.getFD() sync() debe ser suficiente debido a que el documento de force estados
Obliga a cualquier actualización del archivo de este canal a escribirse en el dispositivo de almacenamiento que lo contiene. Si el archivo de este canal reside en un dispositivo de almacenamiento local, cuando este método retorne, se garantiza que todos los cambios realizados en el archivo desde que se creó este canal o desde que se invocó por última vez, se habrán escrito en ese dispositivo. Esto es útil para garantizar que la información crítica no se pierda en el caso de un bloqueo del sistema.
La documentación a sync estados:
Fuerza de todos los buffers del sistema para sincronizar con el dispositivo subyacente. Este método retorna después de que todos los datos y atributos modificados de este FileDescriptor se hayan escrito en los dispositivos correspondientes. En particular, si este FileDescriptor se refiere a un medio de almacenamiento físico, como un archivo en un sistema de archivos, la sincronización no regresará hasta que todas las copias modificadas en memoria de los búferes asociados con este FileDesecriptor se hayan escrito en el medio físico. la sincronización está destinada a ser utilizada por código que requiere almacenamiento físico (como un archivo) para estar en un estado conocido.
Estas dos llamadas deberían ser suficientes. ¿Lo es? Supongo que no lo son.
Antecedentes: hago una pequeña comparación de rendimiento (2 GB, escritura secuencial) usando C/Java y la versión de Java es dos veces más rápida que la versión C y probablemente más rápida que el hardware (120 MB/s en una sola HD) También traté de ejecutar la sincronización de la herramienta de línea de comandos con Runtime.getRuntime() .exec ("sincronización") pero eso no ha cambiado el comportamiento.
El código C que resulta en 70 MB/s es (utilizando las API de bajo nivel (abrir, escribir, cerrar) no cambia mucho):
FILE* fp = fopen(filename, "w");
while(xyz) {
fwrite(buffer, 1, BLOCK_SIZE, fp);
}
fflush(fp);
fclose(fp);
sync();
Sin el último momento para sincronizar; Obtuve valores poco realistas (más de 1 GB, también conocido como rendimiento de la memoria principal).
¿Por qué hay una gran diferencia entre C y Java? Hay dos posibilidades: no sincronizo los datos correctamente en Java o el código C es subóptimo por alguna razón.
Actualización: He hecho carreras de poca altura con "strace -cfT cmd". Aquí están los resultados:
C (API de bajo nivel): MB/s 67,389782
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 87.21 0.200012 200012 1 fdatasync 11.05 0.025345 1 32772 write 1.74 0.004000 4000 1 sync
C (API de alto nivel): MB/s 61,796458
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 73.19 0.144009 144009 1 sync 26.81 0.052739 1 65539 write
Java (1.6 SUN JRE, API java.io): MB/s 128.6755466197537
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 80.07 105.387609 3215 32776 write 2.58 3.390060 3201 1059 read 0.62 0.815251 815251 1 fsync
de Java (JRE SUN 1.6, API java.nio): MB/s 127,45830221558376
5.52 0.980061 490031 2 fsync 1.60 0.284752 9 32774 write 0.00 0.000000 0 80 close
El tiempo de los valores parecen ser sólo la hora del sistema y por lo tanto son bastante sentido.
Actualización 2: Cambié a otro servidor, reinicié mi funcionamiento y utilizo un ext3 formateado nuevo. Ahora obtengo solo un 4% de diferencias entre Java y C. Simplemente no sé qué salió mal. A veces las cosas son extrañas. Debería haber intentado la medición con otro sistema antes de escribir esta pregunta. Lo siento.
Actualización 3: Para resumir las respuestas:.
- Uso c.force (verdadero), seguido de s.getFD() sync() para Java NIO y s.flush() y s.getFD() .sync() para la API de transmisión de Java. Para la API de alto nivel en C, no te olvides de sincronizar. A fflush envió los datos al sistema operativo, pero no trae sus datos al dispositivo de bloque.
- Utilice strace para analizar las llamadas realizadas por un comando
- Revise los resultados antes de publicar una pregunta.
Actualización 4: Tenga en cuenta lo siguiente seguimiento question.
Realmente me gustaría ver el rendimiento utilizando solo las funciones de la sección 2. –
¿Qué estás usando para BLOCK_SIZE? ¿Es del mismo tamaño que tu buffer en Java? 512 va a ser muy inferior al óptimo en estos días. Probablemente quieras al menos 4096 (tamaño de página en x86) o posiblemente más alto. He visto mejoras mensurables de hasta 32k en algunas máquinas. Ah, y por supuesto si su buffer está alineado con la página, le dará más espacio para la optimización. – aij
Otro posible problema es que el código que publicaste no utiliza las "API de bajo nivel (abrir, escribir, cerrar)". Está utilizando la API stdio portátil de mayor nivel (fopen, fwrite, fclose) que agregará una capa adicional de almacenamiento en memoria intermedia de forma predeterminada. ¿Ha desactivado explícitamente el almacenamiento en búfer en algún lugar fuera del código que publicó? – aij