From 860ab08b3afc71ecc759d350d2f070c4faaeea24 Mon Sep 17 00:00:00 2001
From: Fil <fil@rezo.net>
Date: Sat, 19 Nov 2005 01:15:56 +0000
Subject: [PATCH] etre un peu moins bourrin sur la gestion des stats

---
 .gitattributes              |   1 +
 ecrire/inc_cron.php3        |  25 ++++---
 ecrire/inc_popularites.php3 |  74 +++++++++++++++++++
 ecrire/inc_version.php3     |   2 +-
 ecrire/inc_visites.php3     | 138 ++++++++++--------------------------
 5 files changed, 131 insertions(+), 109 deletions(-)
 create mode 100644 ecrire/inc_popularites.php3

diff --git a/.gitattributes b/.gitattributes
index 7faa50c129..576f575d1c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -289,6 +289,7 @@ ecrire/inc_messagerie.php -text
 ecrire/inc_mini_nav.php -text
 ecrire/inc_minipres.php -text
 ecrire/inc_naviguer.php -text
+ecrire/inc_popularites.php3 -text
 ecrire/inc_spip_cal.php -text
 ecrire/inc_spip_image.php -text
 ecrire/inc_statistiques_repartition.php -text
diff --git a/ecrire/inc_cron.php3 b/ecrire/inc_cron.php3
index 59297d7970..07182a515f 100644
--- a/ecrire/inc_cron.php3
+++ b/ecrire/inc_cron.php3
@@ -50,11 +50,11 @@ if (!defined("_ECRIRE_INC_VERSION")) return;
 // le fichier de verrouillage (avec la valeur absolue du code de retour).
 // La fonction executant la tache est un homonyme de prefixe "cron_"
 // Le fichier homonyme de prefixe "inc_" et de suffixe _EXTENSION_PHP
-// est automatiquement charge et est supposee la definir si ce n'est fait ici.
+// est automatiquement charge si besoin, et est supposee la definir si ce
+// n'est fait ici.
 
 function spip_cron($taches = array()) {
 	$t = time();
-
 	if (@file_exists(_FILE_MYSQL_OUT)
 	AND ($t - @filemtime(_FILE_MYSQL_OUT) < 300))
 		return;
@@ -71,7 +71,6 @@ function spip_cron($taches = array()) {
 	foreach ($taches as $nom => $periode) {
 		$lock = _DIR_SESSIONS . $nom . '.lock';
 		$date_lock = @filemtime($lock);
-
 		if ($date_lock + $periode < $tmin) {
 			$tmin = $date_lock + $periode;
 			$tache = $nom;
@@ -84,7 +83,6 @@ function spip_cron($taches = array()) {
 		// pour si peu)
 		else if ($date_lock > $t + 3600)
 			spip_log("Erreur de date du fichier $lock : $date_lock > $t !");
-
 	}
 	if (!$tache) return;
 
@@ -160,8 +158,10 @@ function taches_generales() {
 		$taches_generales['mail']= 3600 * 24 * $GLOBALS['meta']['jours_neuf'];
 
 	// stats : toutes les 5 minutes on peut vider un panier de visites
-	if ($GLOBALS['meta']["activer_statistiques"] == "oui")
+	if ($GLOBALS['meta']["activer_statistiques"] == "oui") {
 		$taches_generales['visites'] = 300; 
+		$taches_generales['popularites'] = 7200; # calcul lourd
+	}
 
 	// syndication
 	if ($GLOBALS['meta']["activer_syndic"] == "oui") 
@@ -222,12 +222,19 @@ function cron_visites($t) {
 	// pour etre prioritaire lors du cron suivant
 	if ($encore)
 		return (0 - $t);
-	else {
-		calculer_popularites();
-		return 1;
-	}
+
+	return 1;
 }
 
+//
+// Applique la regle de decroissance des popularites
+//
+function cron_popularites($t) {
+	calculer_popularites();
+	return 1;
+}
+
+
 //
 // Mail des nouveautes
 //
diff --git a/ecrire/inc_popularites.php3 b/ecrire/inc_popularites.php3
new file mode 100644
index 0000000000..e3393e7bbe
--- /dev/null
+++ b/ecrire/inc_popularites.php3
@@ -0,0 +1,74 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2005                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+//
+// Popularite, modele logarithmique
+//
+
+function calculer_popularites() {
+
+	// Si c'est le premier appel, ne pas calculer
+	$t = $GLOBALS['meta']['date_popularites'];
+	ecrire_meta('date_popularites', time());
+	ecrire_metas();
+	if (!$t)
+		return;
+
+	$duree = time() - $t;
+	// duree de demi-vie d'une visite dans le calcul de la popularite (en jours)
+	$demivie = 1;
+	// periode de reference en jours
+	$periode = 1;
+	// $a est le coefficient d'amortissement depuis la derniere mesure
+	$a = pow(2, - $duree / ($demivie * 24 * 3600));
+	// $b est la constante multiplicative permettant d'avoir
+	// une visite par jour (periode de reference) = un point de popularite
+	// (en regime stationnaire)
+	// or, magie des maths, ca vaut log(2) * duree journee/demi-vie
+	// si la demi-vie n'est pas trop proche de la seconde ;)
+	$b = log(2) * $periode / $demivie;
+
+	// oublier un peu le passe
+	spip_query("UPDATE spip_articles SET maj=maj,
+		popularite = popularite * $a");
+
+	// enregistrer les metas...
+	list($maxpop, $totalpop) = spip_fetch_array(spip_query(
+	"SELECT MAX(popularite), SUM(popularite) FROM spip_articles"
+	));
+	ecrire_meta("popularite_max", $maxpop);
+	ecrire_meta("popularite_total", $totalpop);
+
+
+	// Une fois par jour purger les referers du jour ; qui deviennent
+	// donc ceux de la veille ; au passage on stocke une date_statistiques
+	// dans spip_meta - cela permet au code d'etre "reentrant", ie ce cron
+	// peut etre appele par deux bases SPIP ne partageant pas le meme
+	// _DIR_SESSIONS, sans tout casser...
+	$aujourdhui = date("Y-m-d");
+	if ($date = $GLOBALS['meta']['date_statistiques']
+	AND $date != $aujourdhui)
+		spip_query("UPDATE spip_referers
+		SET visites_veille=visites_jour, visites_jour=0");
+	ecrire_meta('date_statistiques', $aujourdhui);
+
+	// et c'est fini pour cette fois-ci
+	ecrire_metas();
+	return 1;
+
+}
+
+?>
diff --git a/ecrire/inc_version.php3 b/ecrire/inc_version.php3
index 4086776948..c601601cf8 100644
--- a/ecrire/inc_version.php3
+++ b/ecrire/inc_version.php3
@@ -936,7 +936,7 @@ function cron($gourmand = false) {
 
 		// Faut-il travailler ? Pas tous en meme temps svp
 		// Au passage si on travaille on bloque les autres
-		if (spip_touch(_FILE_CRON_LOCK, 1)) {
+		if (spip_touch(_FILE_CRON_LOCK, 2)) {
 			include_ecrire('inc_cron.php3');
 			spip_cron();
 		}
diff --git a/ecrire/inc_visites.php3 b/ecrire/inc_visites.php3
index 5f7b0f037c..cd12087ec5 100644
--- a/ecrire/inc_visites.php3
+++ b/ecrire/inc_visites.php3
@@ -13,8 +13,6 @@
 
 if (!defined("_ECRIRE_INC_VERSION")) return;
 
-
-
 ### Pour se dęš«arrasser du md5, comment faire ? Un index sur 'referer' ?
 ### ou alors la meme notion, mais sans passer par des fonctions HEX ?
 
@@ -76,29 +74,33 @@ function calculer_visites($t) {
 	}
 	closedir($dir);
 
-	// 2. Manger 1000 fichiers de ces paniers (sans ordre particulier)
-	$compteur = 1000;
+	// 2. Manger 100 fichiers de ces paniers (sans ordre particulier)
+	$compteur = 100;
 	$pasfini = false;
 	foreach ($paniers as $panier) {
+		spip_log("traite le panier $panier");
 		$dir = opendir(_DIR_SESSIONS.$panier);
 		while (($item = readdir($dir)) !== false) {
+			if ($compteur-- < 0) {
+				$pasfini = true;
+				break;
+			}
 			if (is_file($f = _DIR_SESSIONS.$panier.'/'.$item)) {
 				compte_fichier_visite($f,
 					$visites, $visites_a, $referers, $referers_a, $articles);
 				@unlink($f);
 			}
-			if (-- $compteur <= 0) {
-				$pasfini = true;
-				break;
-			}
 		}
 		// effacer le panier, sauf si on a atteint la limite de fichiers vus
 		closedir($dir);
-		if (!$pasfini)
+		if ($pasfini)
+			break;
+		else
 			@rmdir(_DIR_SESSIONS.$panier);
 	}
 
 	if (!$visites) return;
+	spip_log("analyse $visites visites");
 
 	// Maintenant on dispose de plusieurs tableaux qu'il faut ventiler dans
 	// les tables spip_visites, spip_visites_articles, spip_referers
@@ -112,9 +114,6 @@ function calculer_visites($t) {
 	spip_query("UPDATE spip_visites SET visites = visites+$visites
 	WHERE date='$date'");
 
-	// pour calcul_mysql_in
-	include_ecrire('inc_db_mysql.php3');
-
 	// 2. les visites des articles (en deux passes pour minimiser
 	// le nombre de requetes)
 	if ($articles) {
@@ -126,19 +125,34 @@ function calculer_visites($t) {
 		. ")");
 
 		// enregistrer les visites dans les deux tables
-		$ar = array(); # tableau num -> liste des articles ayant num visites
-		foreach($visites_a as $id_article => $num)
+		$ar = array();	# tableau num -> liste des articles ayant num visites
+		$tous = array();# liste des articles ayant des visites
+		foreach($visites_a as $id_article => $num) {
 			$ar[$num][] = $id_article;
-		foreach ($ar as $num => $liste) {
-			$in = calcul_mysql_in('id_article', join(',',$liste));
-			spip_query("UPDATE spip_visites_articles
-			SET visites = visites+$num
-			WHERE date='$date' AND $in");
-			spip_query("UPDATE spip_articles
-			SET visites = visites+$num, maj = maj
-			WHERE $in");
-			## Ajouter un JOIN sur le statut de l'article ?
+			$tous[] = $id_article;
 		}
+		$tous = calcul_mysql_in('id_article', join(',', $tous));
+		$sum = '';
+		$in = array();
+		foreach ($ar as $num => $liste)
+			$sum .= ' + '.$num.'*'
+				. calcul_mysql_in('id_article', join(',',$liste));
+
+		# pour les popularites ajouter 1 point par referer
+		$sumref = '';
+		if ($referers_a)
+			$sumref = ' + '.calcul_mysql_in('id_article',
+			join(',',array_keys($referers_a)));
+
+		spip_query("UPDATE spip_visites_articles
+			SET visites = visites $sum
+			WHERE date='$date' AND $tous");
+		spip_query("UPDATE spip_articles
+			SET visites = visites $sum$sumref,
+			popularite = popularite $sum,
+			maj = maj
+			WHERE $tous");
+			## Ajouter un JOIN sur le statut de l'article ?
 	}
 
 	// 3. Les referers du site
@@ -158,8 +172,8 @@ function calculer_visites($t) {
 		// ajouter les visites
 		foreach ($ar as $num => $liste) {
 			spip_query("UPDATE spip_referers
-			SET visites = visites+$num, visites_jour = visites_jour+$num
-			WHERE ".calcul_mysql_in('referer_md5',join(',',$liste)));
+				SET visites = visites+$num, visites_jour = visites_jour+$num
+				WHERE ".calcul_mysql_in('referer_md5',join(',',$liste)));
 		}
 	}
 	
@@ -188,82 +202,8 @@ function calculer_visites($t) {
 		}
 	}
 
-	// 5. Calculer les popularites ; ici c'est presque comme les visites,
-	// sauf qu'on ajoute 1 point par referer
-	if ($visites_a) {
-		$points = array();
-		foreach ($visites_a as $id_article => $v) {
-			// ajouter un point aux articles ayant un referer
-			if ($r = $referers_a[$id_article])
-				$v += 1; // ou array_pop($r);
-			$points[$v][] = $id_article;
-		}
-		foreach ($points as $num => $liste) {
-			spip_query("UPDATE spip_articles
-			SET popularite = popularite + $num, maj = maj
-			WHERE ".calcul_mysql_in('id_article', join(',',$liste)));
-		}
-	}
-
 	// S'il reste des fichiers a manger, le signaler pour reexecution rapide
 	return $pasfini;
 }
 
-
-
-//
-// Popularite, modele logarithmique
-//
-
-function calculer_popularites() {
-	include_ecrire('inc_meta.php3');
-
-	// Si c'est le premier appel, ne pas calculer
-	$t = $GLOBALS['meta']['date_popularites'];
-	ecrire_meta('date_popularites', time());
-	ecrire_metas();
-	if (!$t)
-		return;
-
-	$duree = time() - $t;
-	// duree de demi-vie d'une visite dans le calcul de la popularite (en jours)
-	$demivie = 1;
-	// periode de reference en jours
-	$periode = 1;
-	// $a est le coefficient d'amortissement depuis la derniere mesure
-	$a = pow(2, - $duree / ($demivie * 24 * 3600));
-	// $b est la constante multiplicative permettant d'avoir
-	// une visite par jour (periode de reference) = un point de popularite
-	// (en regime stationnaire)
-	// or, magie des maths, ca vaut log(2) * duree journee/demi-vie
-	// si la demi-vie n'est pas trop proche de la seconde ;)
-	$b = log(2) * $periode / $demivie;
-
-	// oublier un peu le passe
-	spip_query("UPDATE spip_articles SET maj=maj, popularite = popularite * $a");
-
-	// enregistrer les metas...
-	list($maxpop, $totalpop) = spip_fetch_array(spip_query("SELECT MAX(popularite), SUM(popularite) FROM spip_articles"));
-	ecrire_meta("popularite_max", $maxpop);
-	ecrire_meta("popularite_total", $totalpop);
-
-
-	// Une fois par jour purger les referers du jour ; qui deviennent
-	// donc ceux de la veille ; au passage on stocke une date_statistiques
-	// dans spip_meta - cela permet au code d'etre "reentrant", ie ce cron
-	// peut etre appele par deux bases SPIP ne partageant pas le meme
-	// _DIR_SESSIONS, sans tout casser...
-	$aujourdhui = date("Y-m-d");
-	if ($date = $GLOBALS['meta']['date_statistiques']
-	AND $date != $aujourdhui) {
-		spip_query("UPDATE spip_referers SET visites_veille=visites_jour, visites_jour=0");
-	}
-	ecrire_meta('date_statistiques', $aujourdhui);
-
-	// et c'est fini pour cette fois-ci
-	ecrire_metas();
-	return 1;
-
-}
-
 ?>
-- 
GitLab