From d1ca476c4fa6eae88236cbd0af1634c917d129af Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Wed, 26 Nov 2025 10:35:45 +0100 Subject: [PATCH] des debug --- pmocache/src/cache.rs | 24 ++++++++++++++++++-- pmocache/src/db.rs | 42 +++++++++++++++++++++++++++++++++++ pmocache/tests/test_db.rs | 46 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) diff --git a/pmocache/src/cache.rs b/pmocache/src/cache.rs index b7e33f50..8db3bc15 100755 --- a/pmocache/src/cache.rs +++ b/pmocache/src/cache.rs @@ -377,8 +377,28 @@ impl Cache { /// Deux URLs différentes pointant vers le même contenu auront le même pk, /// permettant une déduplication automatique. pub async fn add_from_url(&self, url: &str, collection: Option<&str>) -> Result { - // 1. Télécharger les 512 premiers octets pour calculer le pk - let header = crate::download::peek_header(url, 512) + // 0. Vérifier d'abord si cette URL est déjà en cache (optimisation réseau) + if let Ok(Some(existing_pk)) = self.db.get_pk_by_origin_url(url) { + // Vérifier que le fichier est toujours complet et valide + if self.check_cached_and_complete(&existing_pk).await? { + tracing::debug!( + "URL {} already in cache with pk {}, skipping download", + url, + existing_pk + ); + self.db.update_hit(&existing_pk)?; + return Ok(existing_pk); + } else { + tracing::debug!( + "URL {} found in DB with pk {} but file is incomplete, re-downloading", + url, + existing_pk + ); + } + } + + // 1. Télécharger les 2048 premiers octets pour calculer le pk + let header = crate::download::peek_header(url, 2048) .await .map_err(|e| anyhow!("Failed to peek header: {}", e))?; diff --git a/pmocache/src/db.rs b/pmocache/src/db.rs index b292102d..21aa485e 100644 --- a/pmocache/src/db.rs +++ b/pmocache/src/db.rs @@ -372,7 +372,25 @@ impl DB { } /// Enregistre l'URL d'origine liée à un élément du cache. + /// + /// Cette méthode détecte automatiquement les collisions de pk : + /// si le pk existe déjà avec une URL différente, un log d'erreur est émis. pub fn set_origin_url(&self, pk: &str, origin_url: &str) -> rusqlite::Result<()> { + // Vérifier si ce pk a déjà une URL d'origine différente (détection de collision) + if let Ok(Some(existing_url)) = self.get_origin_url(pk) { + if existing_url != origin_url { + tracing::error!( + "🚨 COLLISION DE PK DÉTECTÉE: pk='{}' existe déjà avec origin_url='{}' mais tentative d'enregistrement avec origin_url='{}'", + pk, + existing_url, + origin_url + ); + tracing::error!( + " Cela indique que deux fichiers différents ont généré le même pk. Considérez augmenter la taille du header pour le calcul du pk." + ); + } + } + self.set_a_metadata(pk, "origin_url", Value::String(origin_url.to_owned())) } @@ -389,6 +407,30 @@ impl DB { } } + /// Recherche un pk par son URL d'origine. + /// + /// Cette méthode permet de vérifier si un fichier avec une URL donnée + /// est déjà en cache avant de lancer un téléchargement. + /// + /// # Arguments + /// + /// * `origin_url` - L'URL d'origine à rechercher + /// + /// # Returns + /// + /// * `Ok(Some(pk))` - Le pk du fichier en cache avec cette URL + /// * `Ok(None)` - Aucun fichier avec cette URL n'est en cache + pub fn get_pk_by_origin_url(&self, origin_url: &str) -> rusqlite::Result> { + let conn = self.lock_conn("get_pk_by_origin_url"); + + conn.query_row( + "SELECT pk FROM metadata WHERE key = 'origin_url' AND value = ?", + [origin_url], + |row| row.get(0), + ) + .optional() + } + /// Récupère uniquement les métadonnées JSON d'une entrée /// /// # Arguments diff --git a/pmocache/tests/test_db.rs b/pmocache/tests/test_db.rs index 0a42c844..c60f7249 100644 --- a/pmocache/tests/test_db.rs +++ b/pmocache/tests/test_db.rs @@ -227,6 +227,52 @@ fn test_origin_url() { assert_eq!(retrieved_url, Some(url.to_string())); } +#[test] +fn test_pk_collision_detection() { + let (_temp_dir, db) = create_test_db(); + + let pk = "collision_pk_123"; + let url1 = "https://example.com/file1.jpg"; + let url2 = "https://example.com/file2.jpg"; + + // Ajouter le premier fichier avec le pk + db.add(pk, None, None).unwrap(); + db.set_origin_url(pk, url1).unwrap(); + + // Vérifier que l'URL est bien enregistrée + let retrieved_url = db.get_origin_url(pk).unwrap(); + assert_eq!(retrieved_url, Some(url1.to_string())); + + // Tenter d'enregistrer une URL différente pour le même pk + // Ceci devrait logger une erreur mais ne devrait pas échouer + let result = db.set_origin_url(pk, url2); + assert!(result.is_ok()); + + // L'URL devrait être écrasée par la nouvelle (comportement actuel) + let retrieved_url = db.get_origin_url(pk).unwrap(); + assert_eq!(retrieved_url, Some(url2.to_string())); +} + +#[test] +fn test_get_pk_by_origin_url() { + let (_temp_dir, db) = create_test_db(); + + let pk = "test_pk_456"; + let url = "https://example.com/cover.webp"; + + // Ajouter une entrée avec URL + db.add(pk, None, None).unwrap(); + db.set_origin_url(pk, url).unwrap(); + + // Rechercher le pk par URL + let found_pk = db.get_pk_by_origin_url(url).unwrap(); + assert_eq!(found_pk, Some(pk.to_string())); + + // Rechercher une URL qui n'existe pas + let not_found = db.get_pk_by_origin_url("https://example.com/notfound.jpg").unwrap(); + assert_eq!(not_found, None); +} + #[test] fn test_get_from_id() { let (_temp_dir, db) = create_test_db();