Les feuilles d’Yggdrasil ne sont plus si inaccessibles pour les braves de la Valhalla. Les “grabbers” auraient pu s’appeler Heidrun mais on se contentera d’un nom plus technique.
Les “grabbers” sont donc enfin supportés dans libvalhalla. Il y a encore du travail avant de pouvoir les utiliser correctement depuis Enna, mais l’essentiel est là. Pour ceux qui n’ont aucune idée de ce qui se cache derrière ce mot barbare “grabber”, on pourrait le définir simplement comme étant une manière de s’accaparer (si on traduit directement du mot anglais) ou alors de récupérer des données depuis des moyens extérieurs.
Par exemple, libvalhalla peut récupérer des méta-données provenant directement des fichiers scannés, à l’aide d’FFmpeg (le parser). Mais si on désire retrouver la couverture CD/DVD il n’était pas possible de le faire jusqu’ici. C’est là qu’intervient le “grabber” tel que celui pour Amazon. On peut imaginer plein d’autres types de “grabbers”, mais celui d’Amazon est le seul porté sous Valhalla au moment où j’écris ce billet et il permet de “rapatrier” les couvertures CD/DVD.
Architecture
L’architecture de la bibliothèque à été profondément changée. Trois nouveaux threads ont fait leur apparition et sont visibles dans l’image ci-dessous en tant que “Dispatcher”, “Grabber” et “Downloader”.
L’image correspond au code, néanmoins elle est un petit peu simplifiée afin d’être suffisamment lisible et compréhensible. Le Dispatcher peut être vu comme un switch réseau. Son but et d’être très réactif (il ne fait donc pas grand chose) et de transmettre les “paquets” au bon endroit en fonction de l’état de celui-ci. Un “paquet” est une analogie au réseau, mais finalement dans le cas de libvalhalla, ce n’est rien de plus qu’une structure qui défini un fichier.
Afin de bien comprendre l’architecture, je vais détailler le chemin effectué par un paquet. Lorsque le scanner trouve un fichier sur le disque, il “l’empacte” et le transmet au DBManager. Le DBManager va interroger la base de donnée pour savoir si ce fichier existe déjà, si oui il vérifie la date de dernière modification et ignore ce paquet si cette date n’a pas changée, autrement (ou si le fichier n’existe pas dans la base), il transmet le paquet au Dispatcher. Un paquet doit suivre 4 étapes avant d’être détruit.
- Étape 0: PARSING
Récupération des méta-données à l’aide d’FFmpeg - Étape 1: GRABBING
Récupération de nouvelles données et (ou) fichiers texts (XML) à l’aide d’un ou de plusieurs grabbers - Étape 2: DOWNLOADING
Téléchargement des fichiers indiqués par le(s) grabber(s) (couvertures CD par exemple) - Étape 3: ENDING
Finalisation et destruction du paquet
Le processus pour un paquet se résume donc en:
Scanner -> DBManager -> Dispatcher -> Parser -> Dispatcher -> Grabber -> Dispatcher -> Downloader -> Dispatcher -> DBManager -> Scanner.
Ce qui est faux en réalité, mais l’idée est correcte. L’intérêt de présenter le processus aussi simplement est uniquement là pour permettre de comprendre par la suite comment valhalla fonctionne. Si un paquet suivrait vraiment le processus ci-dessus, le système serait extrêmement lent (j’exagère peut être sur le mot “extrême”) mais il faut garder en tête que travailler avec des grabbers ça ne peut que ralentir, surtout s’il y a beaucoup de grabbers et s’ils font des accès sur internet.
Comme un pipeline
Si le Dispatcher, le Parser, le Grabber et le Downloader sont sur des threads différents ce n’est pas juste pour pouvoir traiter plusieurs paquets en parallèles, mais aussi pour pouvoir traiter un même paquet à plusieurs endroits en même temps. L’idée est donc de récupérer les données “parsées” et “grabbées” aussi vite que possible dans la base de donnée. Ainsi même si un paquet n’a pas finit de suivre toutes les étapes du processus, il est qu’en même possible d’aller chercher les informations dans la base de données.
Pour ceux qui connaissent un peu les architectures des processeurs, ils connaissent également la représentation en pipeline du cycle d’exécution des instructions. J’ai vais donc expliquer le système par un dessin selon ce principe.
Ce pipeline présente 4 fichiers traités par deux parsers parallélisés. Il y a chaque fois deux grabbers en série pour chaque fichier, avec un downloader à la fin du processus.
Les tâches des threads de Valhalla fonctionnent en tant que FIFO (à ne pas confondre avec l’ordonnanceur du noyau). Le premier arrivé est donc le premier servi. Chaque fichier de ce pipeline peut être séparé en deux lignes. C’est ce qui arrive lorsqu’un grabber est en marche et que des méta-données doivent être sauvées dans la base de donnée. C’est cela qui permet d’avoir un temps de réaction intéressant. Il est inutile d’attendre que le processus soit terminé pour avoir les méta-données. Par exemple avec le “FILE 0”, le Scanner (jaune) transmet le paquet au DBManager (rose pâle), qui va le transmettre au Dispatcher (gris) afin d’être “parsé” (rose). Puis le paquet revient au Dispatcher et se voit transféré dans deux threads, le grabber (vert) et le DBManager. A ce moment là il se passe deux choses, le DBManager va insérer les méta-données du Parser dans la base de donnée et en même temps le grabber va commencer à traiter les nouvelles méta-données. Puis au “grabbing” suivant, c’est les méta-données du grabber précédent qui sont sauvées quand le deuxième grabber s’apprête à traiter les nouvelles méta-données. Au final c’est lors de l’étape du downloading que les dernières méta-données sont sauvées.
En résumé, chaque case DBManager (de demi-hauteur) correspond à une insertion dans la base de donnée. Dans le cadre de cet exemple, il y a donc trois insertions par fichier (le parser + les deux grabbers).
J’ai omis quelques informations sinon cet article serait 5 fois plus long.
Il faut également prendre le diagramme avec des pincettes car il est impossible de prédire la forme exacte pour plusieurs raisons. Les cases “parser”, “grabber” et “downloader” en particulier sont très disproportionnées. Leur temps est une question de plusieurs dizaines de millisecondes à plusieurs secondes. Tout dépend de la taille des fichiers, du demuxer utilisé par FFmpeg, de la vitesse de votre connexion internet, du temps sur les accès aux disque dur, etc, … Le dispatcher se contente de quelques microsecondes, et dans le diagramme il prend autant de temps que le DBManager ce qui est absurde.
Au premier abord on pourrait penser qu’il y a beaucoup de trous dans ce pipeline, mais en réalité les trous sont bien plus grand que ça si vous considérez qu’un parser prend 3 secondes pour un fichier. Néanmoins ce n’est pas du tout un problème (d’ailleurs s’il n’y avait pas de trous alors tous vos CPU seraient constamment à 100%; il ne faut pas oublier non plus que dans certaines étapes il y a des temps morts tel que les accès au disque dur et sur internet).
Si vous regardez bien le diagramme, vous voyez des trous importants après les étapes “parser”. En fait, le scan du disque, le parsing et l’insertion des méta-données des parsers vont se faire très vite. A la même vitesse qu’avant l’ajout des grabbers dans Valhalla. Les grabbers ont aucun impacte sur les parsers car ils sont exécutés après eux. Ce n’est pas plus compliqué que ça.
Il faut également interpréter ce diagramme d’un point de vue plus large. Imaginez le avec plus de 100 lignes (ou plus), ce qui peut arriver sans problème lorsqu’un scanner passe sur un de vos dossiers de musique. Cela donnerait visuellement tous les parsers qui descendraient à gauche en un escalier serré, et les grabbers seraient parsemés (avec des trous importants dans toutes les lignes). Néanmoins il peut y avoir des grabbers non utilisés par certains fichiers, voir même aucun grabber, ce qui complique fortement le diagramme.
Quelques précisions
Il y a de la documentation avec les en-têtes de libvalhalla afin de savoir comment implémenter un grabber, mais je donerais des informations sur ce blog un de ces 4.
L’application test-valhalla permet de tester les grabbers. Il suffit de lire l’aide de la commande.
Valhalla peut être compilé sans le support des grabbers, ainsi les fichiers passent de l’étape 0 PARSING à l’étape 3 ENDING. La bibliothèque réagira exactement comme avant l’ajout des grabbers.
Il manque également des éléments pour une utilisation dans Enna, le fichier TODO vous en dira plus.
Voilà, je n’ai pas la motivation d’en dire plus aujourd’hui, rien que de dessiner le pipeline ça m’a pris pas mal de temps. Je reviendrais donc sur certains aspects dans un prochain billet.
A bientôt,
Mathieu SCHROETER
2 thoughts on “Le support des “grabbers” dans la Valhalla”