java - practico - ¿Es una operación de movimiento en Unix atómico?
libro de java pdf 2018 (3)
- mover (renombrar) es atómico si se realiza en el mismo dispositivo. (dispositivo = mismo disco / partición)
- Si
Foo.txt
salidas deFoo.txt
muevenFoo.tmp
aFoo.txt
más probable es que falle. (Pero si primeroFoo.txt
y luego lo mueves, debería funcionar). Lo que sucede es que un archivo no se elimina físicamente hasta que se cierran todos los manejadores de archivos (no hay ningún proceso que use ese archivo). Además, después de permanecerFoo.tmp
enFoo.txt
, tendrá 2 archivos Foo.txt. Una que se elimina pero aún se abre en la memoria (básicamente ese archivo ya no tiene una referencia en el disco) y otra que realmente reside en el disco. - Pero, después de moverte, en el segundo proceso debes reabrir el archivo.
Déjame saber si estamos en la misma página con el # 1.
Supongamos que hay 2 procesos P1 y P2, y acceden a un archivo compartido Foo.txt
.
Supongamos que P2 está leyendo de Foo.txt
. No quiero que P1 escriba a Foo.txt
mientras P2 lo está leyendo.
Así que pensé que podía hacer que P1 escribiera en Foo.tmp
y, como último paso, Foo.tmp
nombre de Foo.tmp
a Foo.txt
. Mi lenguaje de programacion es java
Entonces, mi pregunta es, ¿aseguraría esto que P2 lea los datos correctos de Foo.txt
? ¿Se confirmaría la operación de cambio de nombre una vez que P2 complete la lectura del archivo?
EDITAR
Intenté recrear este escenario de la siguiente manera:
Mi código P1 es algo como esto:
File tempFile = new File(path1);
File realFile = new File(path2);
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
for(int i=0;i<10000;i++)
writer.write("Hello World/n");
writer.flush();
writer.close();
tempFile.renameTo(realFile);
y mi código P2 es:
BufferedReader br = new BufferedReader(new FileReader(file));
String line = null;
while(true) {
while((line=br.readLine())!=null){
System.out.println(line);
Thread.sleep(1000);
}
br.close();
}
Mi archivo compartido de muestra:
Test Input
Test Input
Test Input
Estoy empezando P1 y P2 casi simultáneamente (P2 comienza primero).
Así que, según tengo entendido, a pesar de que P1 ha escrito un nuevo Foo.txt, ya que P2 ya lo está leyendo, debería leer el contenido anterior de Foo.txt hasta que vuelva a abrir un BufferedReader en Foo.txt.
Pero lo que realmente sucede es que P2 lee la Test Input
tres veces, como se espera de la entrada, pero luego lee el nuevo contenido que fue escrito por P1.
Salida de P2:
Test Input
Test Input
Test Input
Hello World
Hello World
Hello World
.
.
.
Así que no funciona como debería. ¿Estoy probando este escenario mal? Siento que hay algo que me estoy perdiendo.
¿Por qué no usar FileChannel.lock
?
Aquí hay un ejemplo:
http://examples.javacodegeeks.com/core-java/nio/filelock/create-shared-file-lock-on-file/
Una operación de rename
UNIX es atómica (vea renombrar (2)). El comando mv
UNIX usa renombrar si la ruta de origen y destino están en el mismo dispositivo físico. Si la ruta de destino está en un dispositivo diferente, el cambio de nombre fallará y mv
copiará el archivo (que no es atómico).
Si la ruta del archivo de destino existe, el rename
lo eliminará automáticamente del sistema de archivos y lo reemplazará con el nuevo archivo. El archivo no se eliminará realmente hasta que su recuento de referencia caiga a cero, por lo que si otro proceso está leyendo el archivo, seguirá leyendo el archivo anterior. Una vez que todos los procesos hayan cerrado el archivo anterior, su recuento de referencia se reducirá a cero y se reclamará el espacio de almacenamiento de archivos.