saber readable que not know how file_exists existe exist comprobar como check archivo php linux share mount cifs

readable - php file_exists url http



PHP file_exists a veces devuelve false para un archivo en un recurso compartido de CIFS (2)

Puede intentar usar la opción directio para evitar hacer caché de datos de inodo en archivos abiertos en este montaje:

//10.1.2.3/Share /Share cifs credentials=/root/.smbcredentials/share_user,user=share_user,dirmode=0770,filemode=0660,uid=4000,gid=5000,forceuid,forcegid,noserverino,cache=none,directio 0 0

Tengo un recurso compartido CIFS de Windows Server 2012 R2 montado en Ubuntu 14.04.2 LTS (kernel 3.13.0-61-generic) como este

/ etc / fstab

//10.1.2.3/Share /Share cifs credentials=/root/.smbcredentials/share_user,user=share_user,dirmode=0770,filemode=0660,uid=4000,gid=5000,forceuid,forcegid,noserverino,cache=none 0 0

El gid=5000 corresponde al grupo www-data que ejecuta un proceso PHP.

Los archivos se montan correctamente cuando verifico a través de la consola que inició sesión como usuario de www-data ; son legibles y extraíbles (las operaciones que usa el script PHP).

El script PHP está procesando alrededor de 50-70 000 archivos por día. Los archivos se crean en la máquina host de Windows y, algún tiempo después, se notifica al script PHP que se ejecuta en la máquina con Linux sobre un nuevo archivo, comprueba si el archivo existe ( file_exists ), lo lee y lo elimina. Por lo general, todo funciona bien, pero a veces (de unos pocos cientos a 1-2 000 por día), el script PHP genera un error que indica que el archivo no existe. Ese nunca debería ser el caso, ya que solo se notifica de los archivos realmente existentes.

Cuando verifico manualmente los archivos reportados como no existentes, se puede acceder a ellos correctamente en la máquina de Ubuntu y tienen una fecha de creación desde antes de que el script PHP verificara su existencia.

Luego, desencadeno el script PHP manualmente para recoger ese archivo y se recoge sin problemas.

Lo que ya probé

Hay varias preguntas similares, pero parece que he agotado todos los consejos:

  • clearstatcache() antes de verificar file_exists($f)
  • Los permisos de archivo y directorio son correctos (exactamente el mismo archivo se selecciona correctamente más adelante)
  • La ruta utilizada para verificar file_exists($f) es una ruta absoluta sin caracteres especiales; las rutas de los archivos siempre tienen el formato /Share/11/222/333.zip (con varios dígitos)
  • noserverino parámetro noserverino share mount
  • Utilicé cache=none compartir el parámetro de montaje

/proc/fs/cifs/Stats/ displays como se muestra a continuación, pero no sé si hay algo sospechoso aquí. La acción en cuestión es 2) //10.1.2.3/Share

Resources in use CIFS Session: 1 Share (unique mount targets): 2 SMB Request/Response Buffer: 1 Pool size: 5 SMB Small Req/Resp Buffer: 1 Pool size: 30 Operations (MIDs): 0 6 session 2 share reconnects Total vfs operations: 133925492 maximum at one time: 11 1) //10.1.2.3/Share_Archive SMBs: 53824700 Oplocks breaks: 12 Reads: 699 Bytes: 42507881 Writes: 49175075 Bytes: 801182924574 Flushes: 0 Locks: 12 HardLinks: 0 Symlinks: 0 Opens: 539845 Closes: 539844 Deletes: 156848 Posix Opens: 0 Posix Mkdirs: 0 Mkdirs: 133 Rmdirs: 0 Renames: 0 T2 Renames 0 FindFirst: 21 FNext 28 FClose 0 2) //10.1.2.3/Share SMBs: 50466376 Oplocks breaks: 1082284 Reads: 39430299 Bytes: 2255596161939 Writes: 2602 Bytes: 42507782 Flushes: 0 Locks: 1082284 HardLinks: 0 Symlinks: 0 Opens: 2705841 Closes: 2705841 Deletes: 539832 Posix Opens: 0 Posix Mkdirs: 0 Mkdirs: 0 Rmdirs: 0 Renames: 0 T2 Renames 0 FindFirst: 227401 FNext 1422 FClose 0

Un patrón que creo que veo es que el error se genera solo si el archivo en cuestión ya ha sido procesado (leído y eliminado) anteriormente por el script PHP. Hay muchos archivos que se han procesado correctamente y luego se han procesado de nuevo más tarde, pero nunca he visto ese error para un archivo que se procesa por primera vez. El tiempo entre el re-procesamiento varía de 1 a aproximadamente 20 días. Para volver a procesar, el archivo simplemente se vuelve a crear en la misma ruta en el host de Windows con contenido actualizado.

¿Cual puede ser el problema? ¿Cómo puedo investigar mejor? ¿Cómo puedo determinar si el problema está en el lado de PHP o del sistema operativo?

Actualizar

He movido el software que produce los archivos a una máquina virtual de Ubuntu que monta los mismos recursos compartidos de la misma manera. Este componente está codificado en Java. No veo ningún problema al leer / escribir en los archivos.

Actualización - Detalles de PHP

El código PHP exacto es:

$strFile = zipPath($intApplicationNumber); clearstatcache(); if(!file_exists($strFile)){ return responseInternalError(''ZIP file does not exist'', $strFile); }

El intApplicationNumber es un parámetro de solicitud (por ejemplo, 12345678 ) que simplemente se transforma en una ruta mediante la función zipPath() (por ejemplo, /Share/12/345/678.zip - siempre una ruta completa).

El script puede invocarse simultáneamente con diferentes números de aplicación, pero no se invocará simultáneamente con el mismo número de aplicación.

Si la secuencia de comandos falla (devuelve el error ''ZIP file does not exist'' ), se volverá a llamar un minuto después. Si eso falla, será marcado permanentemente como fallido. Luego, generalmente más de una hora después, puedo llamar al script manualmente con la misma invocación (solicitud GET) que se realizó en la producción y funciona bien, el archivo se encuentra y se envía en la respuesta:

public static function ResponseRaw($strFile){ ob_end_clean(); self::ReadFileChunked($strFile, false); exit; } protected static function ReadFileChunked($strFile, $blnReturnBytes=true) { $intChunkSize = 1048576; // 1M $strBuffer = ''''; $intCount = 0; $fh = fopen($strFile, ''rb''); if($fh === false){ return false; } while(!feof($fh)){ $strBuffer = fread($fh, $intChunkSize); echo $strBuffer; if($blnReturnBytes){ $intCount += strlen($strBuffer); } } $blnStatus = fclose($fh); if($blnReturnBytes && $blnStatus){ return $intCount; } return $blnStatus; }

Después de que el cliente recibe el archivo, notifica al servidor de PHP que el archivo se puede mover a una ubicación de archivo (mediante copy() y unlink() ). Esa parte funciona bien.

Resultado STRACE

Después de varios días sin errores, el error volvió a aparecer. Corrí strace y reporta

access("/Share/11/222/333.zip", F_OK) = -1 ENOENT (No such file or directory)

para algunos archivos que existen cuando ejecuto ls /Share/11/222/333.zip desde la línea de comandos. Por lo tanto, el problema está en el nivel del sistema operativo, no se debe culpar a PHP.

Los errores comenzaron a aparecer cuando la carga en el disco en el host aumentó (debido a otros procesos), por lo que la sugerencia de @ risyasin parece más probable: es una cuestión de recursos / tiempos de espera ocupados.

Intentaré el consejo de @miguel-svq de saltarse la prueba de existencia y simplemente ir por fopen() inmediato y luego manejar el error. Voy a ver si cambia algo.


Esto no es una respuesta definitiva a mi problema, más bien un resumen de lo que descubrí y con lo que resolví.

En la parte inferior del problema se encuentra que es el sistema operativo el que informa que el archivo no existe. Ejecutando strace muestra de vez en cuando

access("/Share/11/222/333.zip", F_OK) = -1 ENOENT (No such file or directory)

para los archivos que existen (y aparecen cuando están listados con ls ).

El host de Windows compartido estaba a veces bajo una gran carga de disco Lo que hice es mover una de las acciones a un host diferente para que la carga se distribuya ahora entre las dos. Además, la carga general en el sistema es un poco más ligera últimamente. Cada vez que recibo el error sobre el archivo que no existe, reintento la solicitud un tiempo después y ya no existe.