bonjour
je suis encore assez etonné de voir comment fonctionne les fichiers caches
de SPIP. Je m'y suis intéressé un peu plus suite au message d'un utilisateur
qui m'a envoyé un message personnel me faisant part de ses difficultés similaires.
Du coup je me suis amusé avec les fonctions de lock. Il y a bien sur flock,
mais aussi dans SPIP un mécanisme de lock par requette en BD. Je suppose que
ce mecanisme fonctionne ; je n'ai pas pris la peine de verifier.
Voici la fonction qui permet de générer les fichiers en cache. Il semble
que tout soit OK ; voila pour le coté écriture des fichiers.
function ecrire_fichier_cache($fichier, $contenu) {
global $flag_flock;
$fichier_tmp = $fichier.'_tmp';
$fichier_new = $fichier.'.NEW';
// Essayer de poser un verrou pour proteger l'ecriture du fichier
if (!spip_get_lock($fichier_tmp, 1)) return $fichier_new;
$ok = true;
$f = fopen($fichier_tmp, "wb");
if (!$f) $ok = false;
else {
$r = fwrite($f, $contenu);
if ($r != strlen($contenu)) $ok = false;
if (!fclose($f)) $ok = false;
}
// En cas d'erreur d'ecriture, renvoyer le fichier existant
if (!$ok) {
spip_release_lock($fichier_tmp);
clearstatcache();
return @file_exists($fichier_new) ? $fichier_new : $fichier;
}
// Finaliser
@unlink($fichier_new);
rename($fichier_tmp, $fichier_new);
@unlink($fichier);
spip_release_lock($fichier_tmp);
if ($GLOBALS['flag_apc']) {
apc_rm($fichier_new);
apc_rm($fichier);
}
return $fichier_new;
}
passons maintenant a la lecture des fichiers ; je vois :
# inc-public.php3
<?php
if (!defined("_INC_PUBLIC")) {
define("_INC_PUBLIC", "1");
include("inc-public-global.php3");
}
else {
$cache_inclus = inclure_fichier($fond, $delais, $contexte_inclus);
if (!$delais) $cache_supprimes[] = $cache_inclus; // message pour suppression
include($cache_inclus);
}
?>
la fonction inclure_fichier prend en charge la generation des fichiers de cache.
on pourrait au moins tester qu'apres cette generation le fichier existe bien :
if(file_exists($cache_inclus))
include($cache_inclus);
il se trouve que je tombe dans le cas ou le fichier n'existe pas ; en effet, il s'agit
d'un article et sur la meme page un forum associé. j'ai le sentiment que le forum dont
la valeur delais=0 empeche le cache de s'activer est tout de suite effacé. Du coup
y'a plus de fichier cache quand je fais l'include.
Seulement, en environnement concurentiel, entre un if() et la suite des instructions
il peut se passer plein de choses donc :
if(file_exists($cache_inclus))
include($cache_inclus);
est une suite d'instruction qui marche quand on a de la chance, mais si de nombreux
prossessus apache s'executent en paralelle, il est fort probable qu'un jour ou
l'autre le fil d'execution soit interrompu. Il serait souhaitable de mettre un verrou
tant pour l'écriture que la lecture des fichiers en cache :
allons-y pour quelque chose comme ca (non testé) :
$lock = "ce que vous voulez"; # un nom de fichier ou un nom de section
// debut de section avec un verrou
if (!spip_get_lock($lock, 1)) {
# traiter l'erreur ...
}
if(file_exists($cache_inclus))
include($cache_inclus);
// fin de section verrouillée.
spip_release_lock($lock);
voila quelques idées a creuser.