GaMa a écrit 447 commentaires

  • # Plus simple

    Posté par  (site web personnel) . En réponse au message Avent du Code, jour 10. Évalué à 3.

    J'ai trouvé ce jour assez facile.
    J'ai pas modélisé un CPU complet comme Tanguy, c'est un peu l'enclume pour écraser la mouche.
    L'astuce pour rester simple, c'est de remplacer une instruction add (sur deux cycles) par une instruction noop et une instruction add (sur un cycle). Après ça roule tout seul.

    #!/usr/bin/python3
    
    def yield_input():
        import sys
        with open(sys.argv[1]) as f:
            for l in f:
                l = l.strip()
                yield l
    
    def yield_command():
        for line in yield_input():
            if line == "noop":
                yield None
            if line.startswith("addx"):
                v = int(line[5:])
                yield None
                yield v
    
    def round_1():
        X = 1
        result = 0
        for cycle, command in enumerate(yield_command(), 1):
            if cycle in (20, 60, 100, 140, 180, 220):
                result += cycle*X
            if command is not None:
                X += command
    
        print("Round 1 :", result)
    
    def round_2():
        X = 1
        result = 0
        for cycle, command in enumerate(yield_command()):
            current_pos = cycle%40
            char = "#" if abs(current_pos-X) <= 1 else " "
            end = "\n" if current_pos == 39 else ""
            print(char, end=end)
            if command is not None:
                X += command
    
    round_1()
    round_2()

    Matthieu Gautier|irc:starmad

  • # Ma solution

    Posté par  (site web personnel) . En réponse au message Avent du Code, jour 9. Évalué à 3.

    Et voici ma solution. Et sans énumérer tous les cas de mouvement de suivi<

    #!/usr/bin/python3
    
    def yield_input():
        import sys
        with open(sys.argv[1]) as f:
            for l in f:
                l = l.strip()
                yield l
    
    class Coord:
        def __init__(self):
            self.x = 0
            self.y = 0
    
        def up(self):
            self.x += 1
    
        def down(self):
            self.x -= 1
    
        def right(self):
            self.y += 1
    
        def left(self):
            self.y -= 1
    
        def follow(self, other):
            x_dist = abs(self.x-other.x)
            y_dist = abs(self.y-other.y)
            if x_dist <= 1 and y_dist <= 1:
                return
            if x_dist == 0:
                self.y += 1 if other.y>self.y else -1
            elif y_dist == 0:
                self.x += 1 if other.x>self.x else -1
            else:
                self.y += 1 if other.y>self.y else -1
                self.x += 1 if other.x>self.x else -1
    
        def as_tuple(self):
            return (self.x, self.y)
    
    class Rope:
        def __init__(self, length):
            self.tails_positions = set()
            self.knots = []
            for _ in range(length):
                self.knots.append(Coord())
            self.tails_positions.add(self.knots[-1].as_tuple())
    
        def up(self):
            self.knots[0].up()
            self.follow()
    
        def down(self):
            self.knots[0].down()
            self.follow()
    
        def right(self):
            self.knots[0].right()
            self.follow()
    
        def left(self):
            self.knots[0].left()
            self.follow()
    
        def follow(self):
            for i, knot in enumerate(self.knots[1:]):
                knot.follow(self.knots[i])
            self.tails_positions.add(self.knots[-1].as_tuple())
    
    command_map = {
        'U': "up",
        'D': "down",
        'R': "right",
        'L': "left",
    }
    
    def main():
        rope1 = Rope(2)
        rope2 = Rope(10)
    
        for command in yield_input():
            direction, number = command.split()
            for _ in range(int(number)):
                getattr(rope1, command_map[direction])()
                getattr(rope2, command_map[direction])()
    
        print("Round 1 :", len(rope1.tails_positions))
        print("Round 2 :", len(rope2.tails_positions))
    
    
    if __name__ == "__main__":
        main()

    Matthieu Gautier|irc:starmad

  • [^] # Re: Utilisateur fidèle

    Posté par  (site web personnel) . En réponse à la dépêche Fedora Linux 37 est sortie. Évalué à 6.

    C'est probablement du à la suppression de la taille 67% pour les icônes dans nautilus. https://discourse.gnome.org/t/icon-view-sizes-in-nautilus-43/11240/58

    Tu devais utiliser la taille 67% qui était suffisamment zoomée pour afficher 2 infos et pas trop pour la taille des icônes.

    Matthieu Gautier|irc:starmad

  • [^] # Re: cotar

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 6.

    Je connaissait pas. Mais ça répond à un besoin différent.

    Le but de cotar, c'est de payer moins chez amazon S3 qui facture (entre autres) au nombre de fichiers.
    Le but est de tout mettre dans un tar (et pas un tar.gz) et d'avoir effectivement un table de hash en local (ou téléchargée sur le moment) pour savoir dans quel range il faut lire le fichier dans le tar.

    Mais ça marche que sur des tar non compressé. Et t'as pas de "discovery", la table de hash ne contient pas le path des fichiers.

    C'est utile pour gruger un peu amazon S3, mais ça a peu d'utilité en local où tu veux compresser tes données.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Une base de données ?

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 3.

    Est-ce normal que le service mette plus de deux jours pour me répondre…?

    De manière surprenante, on a eu plein de requêtes depuis que j'ai mis le lien ici :)
    On avait un grosse centaine de tâches en attente alors que d'habitude on est à moins de 10.
    Et comme on a un seul worker, faut prendre son mal en patience.

    Ça devrait être un peu plus normal maintenant.

    Matthieu Gautier|irc:starmad

  • [^] # Re: memforget et fuite mémoire

    Posté par  (site web personnel) . En réponse au journal cTypes + Rust = approfondir une relation d'amour et d'eau (fraîche) . Évalué à 3.

    Premier cas :

    struct MonObjet {
      champ: UnAutreObjet // possession "stricte"
    }

    MonObjet est propriétaire de champ. Donc à la destruction de MonObject, champ sera détruit aussi.
    Et rust garantie qui rien de pointera dessus parce qu'il n'autorise pas de références qui vivent plus longtemps que MonObjet. Sauf si tu fais du unsafe (ce qui est le cas ici), rust ne sait pas. C'est à toi de savoir comment python et rust fonctionne pour rien casser

    Pour

    struct MonObjet {
        champ: &UnAutreObjet // multiples emprunts non-mutables possibles 
    }

    Déjà, c'est faux. C'est :

    struct MonObjet<'lifetime_autreobject> {
         champ: &'lifetime_autreobject UnAutreObjet
    }

    Et ça veut dire que MonObjet, qui emprunte (a une référence vers) UnAutreObjet, ne peut pas vivre plus longtemps que UnAutreObjet. (Même règle que plus haut, mais dans l'autre sens).
    Si python garde un pointeur sur UnAutreObjet, le problème n'arrivera pas quand MonObjet est détruit mais quand UnAutreObjet (ou son propriétaire) sera détruit.

    Dans l'exemple, ma compréhension du phénomène est la suivante : le passage dans liberer_valeurretour supprime le tableau car j'ai déclaré côté Rust, la pleine possession de celui-ci.

    Tout à fait.

    pub struct ValeurRetour {
        pub a: c_int,
        pub contenu: Vec<c_int>
    }

    Tu déclare une structure qui est propriétaire du vecteur qui est propriétaire des entiers.

    Avec let valeur_retour = Box::new(ValeurRetour{...}); tu crées une ValeurRetour dans une box et valeur_retour est propriétaire de la box (et donc ValeurRetour)
    Avec Box::into_raw( valeur_retour ), tu quittes la propriété (au profit de personne), ta box est vidé et tu récupère le pointeur sur valeur_retour.
    Avec Box::from_raw(ptr), tu reprends la propriété. À la destruction de la box, le valeur est détruite (ainsi que le contenu).

    Entre temps, niveau python tu as deux options :

    class ValeurRetour(Structure): 
        _fields_ = [ 
          ( "a", c_int ),
          ( "contenu", POINTER(c_int) )
        ] 
    malib.test_array_retour_complexe.restype = POINTER( ValeurRetour )
    
    # Premier cas (le bon)
    def good():
        tableau_de_rust = malib.test_array_retour_complexe(5) 
        a = r3.contents.a 
        v = r3.contents.contenu  # Un pointeur vers la mémoire interne de `vec`
        print( "[PYTHON] ===>", a, [ v[i] for i in range(0,a) ] )
        # À la destruction de `tableau_de_rust`, on va appeler `__del__` qui va désallouer
        # la mémoire dans rust. On a certes encore v qui pointe vers quelque chose, mais on
        # peut plus l'utiliser, donc osef.
    
    # Le mauvais cas
    def bad():
        tableau_de_rust = malib.test_array_retour_complexe(5) 
        a = r3.contents.a 
        v = r3.contents.contenu  # Un pointeur vers la mémoire interne de `vec`
        print( "[PYTHON] ===>", a, [ v[i] for i in range(0,a) ] )
        return v
        # À la destruction de `tableau_de_rust`, on va appeler `__del__` qui va désallouer
        # la mémoire dans rust.
        # Par contre on a v qui pointe encore vers la mémoire interne désallouée et ça va merder quand on va l'utiliser

    Matthieu Gautier|irc:starmad

  • [^] # Re: Zim

    Posté par  (site web personnel) . En réponse au message Est-ce faisable en .epub ? ou dans un autre format ?. Évalué à 4. Dernière modification le 12 novembre 2022 à 16:26.

    Il est vrai qu'on a pas vraiment de logiciel simple pour lire un zim, on est plutôt sur des logiciels qui permettent de gérer une collection de zims.

    Ça n'est pas possible d'avoir simplement un lecteur type evince ou okular? le serveur http pourrait être démarré en arrière-plan, automatiquement sans que l'utilisateur s'en préoccupe.

    Ça devrait pas être compliqué à faire. Un logiciel avec une webview et un serveur interne ultra simpliste. Yapluska :)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Zim

    Posté par  (site web personnel) . En réponse au message Est-ce faisable en .epub ? ou dans un autre format ?. Évalué à 4.

    Les service workers (SW) c'est une spec du web pour que les sites puissent mettre en place un pseudo proxy dans le browser.

    Pour que le SW fonctionne il faut que le site soit en https, sauf si tu accèdes au serveur en local (c'est considéré comme du debug).

    Ton adresse 192.168.122.1 c'est ton adresse "publique" (dans ton réseau privé) donc il te dis qu'il faut https.
    Si tu passes par 'localhost' (ou 127.0.0.1) ça devrait être bon.
    (Pas besoin de changer la commande kiwix-serve, juste l'adresse dans le navigateur)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Zim

    Posté par  (site web personnel) . En réponse au message Est-ce faisable en .epub ? ou dans un autre format ?. Évalué à 2.

    Bon, ton wav fait 44,89 Mo à lui tout seul. Donc non, c'est pas trop gros 45Mo finalement.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Zim

    Posté par  (site web personnel) . En réponse au message Est-ce faisable en .epub ? ou dans un autre format ?. Évalué à 3.

    J'ai fait un zim de ta page avec youzim.it. Tu peux le télécharger ici : https://youzim.it/53cb3ba90e63be3a92367636
    Il pèse 45Mo (ce qui est bien trop à mon sens mais c'est un autre problème)

    Il est basé sur une solution qui nécessite un service worker, donc il ne fonctionne pas dans kiwix-desktop. Mais tu peux lancer un serveur local (soit directement avec kiwix-serve soit à partir de kiwix-desktop) et le lire avec ton browser. Ça a l'air de bien fonctionner.

    (Les service workers nécessitent soit d'être sur un localhost soit sur du https, c'est pas nous, c'est les specs. À voir comment tu déploies)

    Matthieu Gautier|irc:starmad

  • [^] # Re: memforget et fuite mémoire

    Posté par  (site web personnel) . En réponse au journal cTypes + Rust = approfondir une relation d'amour et d'eau (fraîche) . Évalué à 4.

    Ça me semble mieux :)

    J'émets cependant une réserve sur le __del__. Ça peut poser quelques soucis avec le garbage collecteur de python (https://stackoverflow.com/questions/1481488/what-is-the-del-method-and-how-do-i-call-it)

    En l’occurrence, ça peut bloquer le gc pour chercher des cycles à détruire. Et en fait, tu n'as aucune garantie que __del__ soit appelé par python (il y a de fortes chances que oui, mais c'est pas garantie).

    Si je devais faire la même chose, je partirais plus sur un wrapper (EnveloppeValeurRetourLibDistante) écrite en c++ avec un destructeur en c++ et qui serait wrappé en python (et tout ça probablement avec cython). Mais on sort un peu du sujet d'origine (utiliser ctypes). [*]

    Et une autre réserve. Ça marche parce que tu copies les valeurs du tableau rust dans un tableau python. (D’ailleurs, tu pourrais libérer la mémoire juste après ça). Mais dans un cas plus complexe (par exemple une structure qui à des pointers sur d'autres zone mémoire) il faut faire attention à ne pas garder un pointer vers une de ces zones et libérer la structure en même temps. Sinon, rust risque de libérer la mémoire alors que python continue de pointer dessus.

    En fait, si je devais faire la même chose, je ne le ferais probablement pas et j'utiliserais des libs déjà existantes faites pour ça. La gestion mémoire est un sujet complexe (c'est pas pour rien qu'on a inventer des langages haut niveau qui la gère pour nous) et la gérer correctement dans une couche glue entre deux langages qui n'ont pas les mêmes logiques de gestion mémoire n'est pas une mince affaire.


    [*] Peut être qu'un jour je m'y amuserais, vous aurez droit à un journal si c'est le cas.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Ressemble beaucoup à Frost

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 5.

    je ne sais pas en Rust comment faire

    Rust lui-même ne sait pas faire :)
    Il faut initialiser la structure sur la stack et ensuite la déplacer dans le heap (ou ailleur). Rust évolue dans ce sens mais c'est pas encore ça. (https://github.com/rust-lang/rust/issues/63291)

    Évidemment, le prix à payer, c'est la portabilité, c'est à dire que sur les machines big endian (est-ce que ça existe encore ces choses ?) ne peuvent pas lire une archive LE, car il faut swapper les entiers avant de les utiliser. Mais pour une solution de backup, vu que tu restaures l'archive sur la même machine que tu sauvegardes, l'endianness ne change pas, ce n'est pas un problème.

    Il y a effectivement peu de machines big endian. Mais je ne suis pas près à parier que ça sera toujours le cas. En tous cas, pas pour un format de conteneur qui se veut portable et durable. Apple à déjà changer l'endianness de ses machines et les processeurs arm peuvent fonctionner dans les deux modes. On est pas à l’abri d'un changement d'endianness pour l'iphone 42

    Du coup, jubako "charge" des octets en mémoire (avec du mmap) et parse ces octets pour en récupérer des valeurs et reconstruire mes structures (et inversement à l'écriture). C'est un peu moins efficace car je dois parser chaque valeur individuellement (même si ça se résume à un byteswap) plutôt que directement charger ma structure.
    Mais ça me permet de gérer l'endianness et de me passer du padding au passage.

    J'ai également une fonction de purge qui élimine les révisions les plus anciennes (probablement la fonction la plus dure à coder pour un système de backup qui déduplique)

    J'imagine bien. J'ai pas hâte de me pencher sur la question :)


    En tous cas, ton approche avec Frost est super intéressante.
    Au lieu de faire des backups "incrémentales" immuables d'un coté et gérer les différents backups (suppression des anciens fichiers) d'un autre, tu as un seul format mutable qui intègres l’ensemble des N révisions.

    Je suis partagé entre "c'est une super idée, il faut effectivement avoir un système cohérent" et mon approche vieille école "c'est n'importe quoi, on ne modifie pas un backup une fois créé".

    Matthieu Gautier|irc:starmad

  • [^] # Re: Ressemble beaucoup à Frost

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 8.

    il faut absolument regarder du côté des structures mmapables (le gain de performance est délirant)

    C'est quoi que tu appelles structures mmapables ? Jubako mmap déjà pas mal de chose. Est-ce que c'est des structures avec des particularités (et lesquelles) ou c'est "juste" que l'implémentation doit faire du mmap plutôt que du read dans le fichier ?

    Je me répond à moi même. J'ai vu que dans ton code, tu mmap des régions de ton fichier et tu construit directement (avec un inplace new) tes structures sur les régions mmappées (donc directement dans le fichier).

    Du coup, j'ai une autre question : Comment tu gères l'endianness et la portabilité entre différentes plateformes  ?

    Matthieu Gautier|irc:starmad

  • [^] # Re: Ressemble beaucoup à Frost

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 4.

    Trop bien ! Je savais que j'avais pas trouvé tout les formats d'archivage, j'en ai un de plus à analyser :)

    Tu as l'air d'avoir déjà fait pas mal de choses qui sont dans ma todo list (déduplication, chiffrement, parité, …) Je vais regarder ce que tu as fait, voir te piquer des idées (l'épaule des géants, tout ça)

    il faut absolument regarder du côté des structures mmapables (le gain de performance est délirant)

    C'est quoi que tu appelles structures mmapables ? Jubako mmap déjà pas mal de chose. Est-ce que c'est des structures avec des particularités (et lesquelles) ou c'est "juste" que l'implémentation doit faire du mmap plutôt que du read dans le fichier ?

    du stockage de différences (je détecte les différences via un rolling checksum à points de division fixe, ce qui permet de s'adapter à de nombreux formats, comme le texte ou les formats binaires). Ainsi, tu peux découper tes content pack en fonction du contenu (et en virant donc tous ce qui se déduplique facilement).

    Oui, c'est quelque chose que j'avais déjà identifié en travaillant sur les diff entre les zims. C'est dans ma todo pour faire des diffs efficaces.

    Dans mon cas, je recalcule toujours la différence entre la version actuelle et la dernière version et je modifie la dernière version pour arriver à la version actuelle, ce qui est beaucoup plus efficace que le contraire.

    Je suis pas sur de comprendre. Tu fais un diff "inversé" comme dans les packs git (si tu connais) ? La version "pleine" est toujours la dernière version (la plus couramment lue), et le diff permet de retrouver les anciennes versions.

    Si c'est le cas, ça veut dire que tes backups passés sont modifiés en fonction des données actuelles ?

    Matthieu Gautier|irc:starmad

  • [^] # Re: memforget et fuite mémoire

    Posté par  (site web personnel) . En réponse au journal cTypes + Rust = approfondir une relation d'amour et d'eau (fraîche) . Évalué à 4. Dernière modification le 07 novembre 2022 à 14:39.

    Si j'en crois la doc, Python récupère le pointeur et créé via cTypes, tout le nécessaire pour gérer son cycle de vie. Donc non, il n'y a pas de risque.

    C'est quelle doc ?

    Python n'a aucun moyen de savoir comment il doit désallouer la mémoire, ni même si il doit la désallouer.

    Si tu wrap du code c++ et que tu retournes un pointeur sur un class, il faut appeler le
    destructeur. Python ne le connais pas. Pareil au niveau de Rust, il y a peut-être des drop à appeler.
    Voir même, il ne faut pas détruire la donnée. Image que ta box est dans un stockage de ta lib rust et que tu veux juste retourner un pointer sur cette valeur tout en gardant sa gestion mémoire dans rust : tu peux en récupérer un pointer en "coerçant" la référence (https://doc.rust-lang.org/std/primitive.pointer.html#common-ways-to-create-raw-pointers)
    mais python ne doit pas supprimer la mémoire. Donc Python ne doit pas le faire par défaut.

    Si tu veux que le code python supprime la mémoire, il faut repasser le pointer à rust pour qu'il le supprime comme il faut, probablement avec une fonction de ce type (si tu as utiliser Box::into_raw, à adapter aux cas d'usages) :

    #[no_mangle]
    #[allow(improper_ctypes_definitions)]
    pub unsafe extern "C" fn free_box( ptr: *mut c_int ) {
        drop(Box::from_raw(ptr));
    } 

    Tu peux lancer ton programme avec valgrind pour voir si il y a des fuites mémoire.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Zim

    Posté par  (site web personnel) . En réponse au message Est-ce faisable en .epub ? ou dans un autre format ?. Évalué à 2.

    Tu peux essayé de transformer ton site php en site statique
    (en gros en mettant les réponses aux appel XHR dans des fichiers et en changeant les requêtes pour faire des appels sur les fichiers plutôt que du XHR sur le serveur).

    youzim.it fait globalement ça pour toi, mais ça nécessite un service worker dans le navigateur pour changer les urls au "runtime". (service worker inclus dans le zim, mais tu es potentiellement limité à un navigateur/environnement qui support les services worker)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Une base de données ?

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 6. Dernière modification le 07 novembre 2022 à 13:25.

    Mais j’ai vite déchanté : mon premier problème concerne la difficulté de créer la dite archive. Impossible de trouver un outil à la ligne de commande facilement installable, donc j’ai finis par me rabattre, à contre-cœur, sur un site « Zim It » (dont je ne retrouve plus l’adresse…) qui m’a permis, étant donné l’URL, de télécharger l’archive Zim correspondante.

    Ce n'est pas évident du tout de refaire des sites locaux à partir de site "en-ligne". On a des outils spécialisés pour les gros sites qu'on fourni (mwoffliner pour tout les mediawiki, sotoki pour stackoverflow, …). Mais ils sont vraiment spécifique au format du site.
    Et ils ne sont pas forcement sobre en ressources et en temps.

    Le service zimit est là : https://youzim.it/

    Qu’est-ce que j’ai raté pour créer l’archive facilement, en tant que commun des mortel·le·s ?

    Pas vraiment, non. Mais si t'es content·e de la version offline créée avec wget -R, tu peux la mettre dans un zim avec zimwriterfs.

    Est-ce que la taille de l’archive est dû au site utilisé, ou bien est-ce un « problème » connu ? (pour référence, le site c’est https://www.libraryofjuggling.com)

    Non, c'est pas connu, et c'est surprenant. Si t'as le temps, tu peux créer une issue sur libzim avec toute les infos, ça nous aiderait beaucoup.

    Après, on stocke une base de données xapian dans le zim pour faire de la recherche fulltext, c'est peut-être elle qui gonfle l'archive.

    Suis-je vraiment le type d’utilisateur·ice envisagé par Zim ?

    Oui :)
    On est plus orienté utilisateurs finaux qui vont juste consulté les archives mais c'est principalement du à la difficulté de scrapper des sites de manière générique (d'où la création de youzim.it). Dans l'idée on s'adresse aussi au gens qui veulent créer leurs archives.

    Si oui, comment peut-on améliorer cette première expérience avec Zim ?

    Déjà, en remontant l'information. Ça nous permettra au moins de savoir où il faut s'améliorer.
    Ensuite, c'est un projet libre. Nous sommes grandement ouvert aux contributions, n'hésitez pas à venir nous parler et à corriger les problèmes.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Dar

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 2.

    Je connaissais pas du tout dar. Je vais regarder.

    À première vue, Dar est quand même bien orienté FS. Jubako se veut plus généraliste.
    J'ai encore des comparaisons à faire :)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Bravo !

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 3. Dernière modification le 07 novembre 2022 à 12:14.

    Jubako n'est pas un système de fichier. Certes il y a Arx qui implémente une archive de fichiers et donc ressemble un peu à un FS readonly, mais ce n'est qu'un cas d'usage de Jubako parmi d'autres.

    • Pour un stockage style kiwix, tu as besoins de l'url de la ressource web et son mimetype, sans système d’arborescence.
    • Pour un fichier d'archive, il faut une arborescence et le stockage de toutes les métadonnées d'un fs.
    • Pour un outils de backup, tu as potentiellement moins d'info à stocker (les dates de création/modification ?) ou plus (un checksum du contenu).
    • Pour un outils d'archivage, tu es probablement peu intéressé par les droits du fs, l'owner/group… mais tu veux d'autres info (catégorisation, …)
    • Pour un distribution de logiciel type rpm/deb, tu te fous des métadonnées, tu veux savoir où installer des fichiers. Par contre tu veux des métadonnées de plus haut niveau (description, version, dépendances, …)
    • Un système comme textbundle n'a pas à être obligatoirement structuré avec un zip.
    • J'ai entendu parlé d'usage où on diffusait des mise à jour de programme télé aux décodeurs des particuliers avec des bdd sqlites. Jubako pourrait être utilisé dans ce cas (je sais pas si ça serait plus adapté ou non, mais c'est un cas d'usage qui sort du classique archive de fichiers)

    UnionFs, SquashFS, le système de Docker ou Knoppix sont orientés FS. C'est assez générique et tout le monde y est habitué ("tout est fichier" de Unix) mais Jubako sort de ce paradigme et te permet de faire autrement. Arx nous ramène à ça mais je l'ai juste implémenté en premier parce que c'était assez facile et avec des résultats facilement comparables à l'existant. Un avantage de Jubako c'est sa modularité.

    Une autre différences, c'est de découplage entre la partie "index" (directory dans la terminologie Jubako) et le contenu. Par exemple pour un système de backup, tu pourrais envoyer tout le contenu sur un serveur distant et garder en local que le directory. Lors des sauvegarde incrémentale, tu as accès, en local, à la liste des fichiers déjà sauvegarder et leur checksums. Tu pourrais faire ton backup totalement en offline, sans avoir toute les sauvegarder en local (et leur occupation disque) et quand même faire de l'incrémental. Tu peux bien sûr faire la même chose avec un json que tu gardes en local, mais Jubako te fournit tout de base.


    J'ai évité d'implémenter un équivalent à zim en premier cas d'usage justement pour pas être comparé seulement à zim et limité jubako à un successeur du format zim. Ne comparez pas que Arx avec l'existant :)


    J'ai quand même fait un comparatif avec squashfs, ça manque effectivement à la dépêche. J'ai refait les mêmes tests que dans la dépêche (linux complet) avec squasfs. Par défaut squasfs utilise les 16 cœurs de ma machine mais arx est monothreadé. Donc il y a deux séries de tests, un avec squashfs 16 cœurs (pour voir des performances "optimales") et 1 cœur (pour comparer correctement)

    Taille Création Extraction Listing Dump Dump / entry Mount diff
    Source 1326 MB 880ms
    squashfs 177 MB 1m16s 0s730ms 30ms 1m02s 2ms 2,8
    squashfs monothread 177 MB 4m38s 1s070ms 30ms 1m02s 2ms 2,8
    Arx 140 MB 4m45s 1s47ms 45ms 1m28s 4ms 4s2

    Globalement :
    - arx compresse mieux
    - Est plus lent que squashfs mais reste dans des ordres de grandeurs comparables.

    Et il faut se souvenir que squashfs est implémenté dans le kernel (Je sais pas quelle partie est réellement dans le kernel et dans l'userpace pour le listing des fichiers mais pour ce qui est du mount, c'est totalement dans le kernel). Ça m'aurait surpris que arx soit plus rapide qu'un module kernel.

    C'est aussi une différence de Jubako avec les autres systèmes. Jubako c'est un lib, elle se veut indépendante de l'OS. À terme, Jubako sera disponible sous Windows et Mac aussi (voir même dans le web en compilant jubako en wasm). Squashfs, t'es limité à linux.

    Matthieu Gautier|irc:starmad

  • # memforget et fuite mémoire

    Posté par  (site web personnel) . En réponse au journal cTypes + Rust = approfondir une relation d'amour et d'eau (fraîche) . Évalué à 3.

    // au regard de Rust, 's' est ma chaîne c_char et 'p' est le pointeur
    // si "je n'oublie pas" 's' avant de quitter la fonction, Rust va désallouer la mémoire
    // le pointeur 'p' renvoyé serait donc invalide
    // 'std::mem::forget' nous permet de forcer cet "oubli de désallocation" lors de la compilation
    std::mem::forget(s);

    N'y a-t-il pas une fuite mémoire là ?
    Certes tu es obligé de dire à rust de ne pas desalouer la variable pour la passer à python, mais il faut bien la libérer à un moment. Sur un cas de test comme ça c'est pas bien grave, mais comment tu gères ça en vrai sur un programme réel ?

    Matthieu Gautier|irc:starmad

  • [^] # Re: Une base de données ?

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 4. Dernière modification le 06 novembre 2022 à 19:33.

    J'ai pas trop regarder du coté de sqlite. Mais à première vue je dirais déjà que c'est pas fait pour la même chose. Sqlite est plutôt orienté pour du stockage de "petites" données (métadonnées), même si il sait stocker des grosses données. Jubako est plutôt orienté "grosses" donnée (contenu de fichier par exemple, même si il sait stocker des métadonnées aussi.
    De la même manière sqlite est orienté pour faire des requêtes complexes. C'est pas le cas de Jubako.

    Après il y a aussi la question de la compression. Compresser un base de donnée sqlite revient au même problème que tar, il faut tout décompresser pour accéder à la base. Ou alors
    il faut stocker le contenu de chaque "fichier" compressé individuellement mais là on serait dans le cas de zip et donc avec des taux de compression moindre.
    Jubako (comme zim) est au niveau intermédiaire et compresse les données par "cluster", ce qui permet d'avoir un meilleur taux de compression que zip mais un accès plus "random" que tar.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Bravo !

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 4.

    C'est à vous que je pensais ;)

    Matthieu Gautier|irc:starmad

  • [^] # Re: Bravo !

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 3.

    Tout à fait. Et aussi à unionfs et overlayfs et …

    Dans l'idée, tu pourrais réimplémenter docker en utilisant une solution basé sur Jubako
    (Je dis pas que c'est une bonne idée par contre).

    Matthieu Gautier|irc:starmad

  • [^] # Re: Bravo !

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 4.

    Merci. Il faut aussi remercier les relecteur·trice·s qui ont grandement amélioré ma première version.

    Matthieu Gautier|irc:starmad

  • [^] # Re: Bravo !

    Posté par  (site web personnel) . En réponse à la dépêche Jubako et Arx, un conteneur universel et son format d’archive. Évalué à 7.

    Est-ce que cette limitation est d'ordre technique sur le format de fichier choisi ? ou une contrainte choisie pour optimiser ?

    Si tu parles de Jubako quand tu dis format de fichier, c'est moi qui l'ai créé, donc on peut pas vraiment parler de contrainte :)

    En fait ce n'est pas facile de créer des formats de fichier modifiables. Quand t'y pense, même un simple fichier texte est rarement modifier. En général il est recréer. Et c'est compréhensible, si tu rajoutes un caractère en plein milieu, ça veut dire que tu dois décaler la deuxième partie du fichier, donc réécrire la moitié du fichier. C'est bien plus simple de considéré le fichier comme "recréable" plutôt que comme modifiable.

    De même au niveau de l'implémentation. Si tu considères ton conteneur comme non modifiable ça simplifie grandement le code. Tu peux mettre en place du cache ou du multithreading bien plus facilement que si tu dois gérer des potentielles modifications concurrentes.
    Pareil pour la création, c'est plus simple d'implémenté un créateur qui prend du contenu et l'écrit dans un fichier sans se poser la question de fournir un accès en lecture performant sur ce même contenu.

    Mais Jubako permettrait de créer des conteneurs facilement recréable grâce au concept de Pack. Si tu as une archive avec N contentPacks, tu peux créer un N+1ieme pack qui contient ton contenu à rajouter et tu refais seulement le directoryPack pour rajouter un entrée qui pointe vers ton nouveau contenu. (Ou tu fais pointer une entrée existante)
    On peut même aller un peu plus en considérant que le N+1 pack est celui qui contient les modifications et qu'on recrée ce pack à chaque fois.

    J'envisage même de potentiellement créer un "sous-format" de type "Overlay" pour standardiser ça.

    J'imaginais aussi pouvoir faire packager un projet musical, tout en ayant la possibilité d'aller le modifier une fois monté. L'essentiel des accès sont en lecture, mais quelques modification pourraient encore être faites niveau métadonnées par exemple.

    Dans ton cas tu pourrais stocker les métadonnées soit sous la forme de propriétés des entrées soit comme deuxième contenu associé aux entrées (mais stocker dans un pack différent que tes données). Quand tu modifies les métadonnées, tu ne modifie que le directoryPack (dans le premier cas) ou que le pack de métadonnées (et si tu te débrouille bien, tu n'as pas à recréer le directoryPack).

    Mais niveau implémentation, on est encore loin de tout ça. C'est que le début :)

    Matthieu Gautier|irc:starmad