Au début du mois de Janvier, Facebook a publié "Scaling Mercurial at Facebook" sur son blog technique. expliquant la façon dont ils ont modifié Mercurial pour le rendre plus rapide répondant ainsi aux besoins de leur dépôt.
Facebook conserve tout son code source dans un référentiel unique, dont il y a deux ans était basé sur Subversion. Au lieu d'avoir des référentiels séparés pour les projets indépendants (et le partage à l'aide d'un référentiel binaire), l'ensemble du code de base est dans un seul grand espace de stockage.
Malheureusement pour Facebook, ni Git ni Mercurial n'ont été conçus pour soutenir un seul dépôt énorme de tous les projets. Puisque le but d'un système de contrôle de version distribué est de stocker tout l'historique, si tous les projets de l'entreprise sont stockés dans un référentiel unique, alors la taille du dépôt avec son historique peut être prohibitivement grande. En comparaison, les systèmes centralisés de gestion de sources comme CVS et Subversion sont capables de gérer des référentiels uniques pour plusieurs projets, car les clients peuvent consulter simplement la dernière version ou juste un sous-ensemble du référentiel.
Bien que l'équipe Facebook ait étudié la modification de Git pour subvenir à leurs besoins, leur conclusion fut que Mercurial avait une API de programmation plus appropriée qui pouvait être modifiée afin de soutenir leurs besoins. (Git a une structure d'objet bien définie qui est interprétée par les outils, par opposition à Mercurial qui a une API bas niveau) Beaucoup de changements ont été contribués en retour au projet Mercurial, y compris de nouveaux algorithmes de graphes et la réécriture du code en c.
Deux changements spécifiques ont permis à Facebook d'utiliser Mercurial pour leur taille de référentiel; modifier les mises à jour de statut pour les fichiers pour vérifier les modifications de fichiers spécifiques, par opposition aux modifications de contenu (en utilisant les fonctionnalités natives des systèmes d'exploitation pour connaître la liste des fichiers modifiés) et la modification du checkout pour récupérer un clone superficiel plus léger, sans avoir besoin de récupérer l'historique complet.
Normalement, un système de contrôle de version distribué génère des hashs basés sur le contenu des données, plutôt qu'un horodatage. En conséquence, savoir si un dépôt a des changements implique souvent de regarder chaque fichier et pour chaque fichier calculer le hash pour déterminer si le contenu du fichier est différent. En limitant l'ensemble de fichiers à vérifier avec ceux que le système d'exploitation a signalé comme ayant changé depuis la dernière analyse, la vitesse est proportionnelle au nombre de fichiers dont le timestamp a changé, au lieu de tous les fichiers de l'espace de travail courant. Git tente de réduire cela en exécutant lstat pour déterminer les informations de fichier spécifique, mais doit encore parcourir tous les fichiers dans le référentiel afin de déterminer s'ils sont modifiés. En demandant au système d'exploitation de fournir l'information, le référentiel peut être optimisé pour analyser uniquement les fichiers que l'OS rapporte comme ayant changé.
L'autre problème que Facebook a essayé de résoudre est de minimiser la quantité de données nécessaires pour une opération, soit de pull, soit de clone. En stockant tous les projets dans le même référentiel, la taille du dépôt est proportionnelle à l'historique complet du tout, ce qui conduit finalement à des problèmes de passage à l'échelle. Étant donné que le dépôt n'a pas pu être partitionné de façon efficace, la solution a été de ne télécharger que la dernière version des fichiers, ainsi que le journal des commits.
Cela permet aux développeurs d'obtenir rapidement l'ensemble actuel des fichiers (de la même façon que Subversion et CVS le faisaient) ainsi que l'itération sur le journal pour l'ensemble des commits jusqu'à ce moment-là. Toutefois, si les anciennes versions du référentiel (ou les anciennes versions de fichiers) sont nécessaires, le clone local n'aura pas cette information. (Git fournit une option limitée avec un «clone superficiel», qui peut avoir une seule révision d'un référentiel, mais sans l'historique.)
En étendant les APIs Mercurial, les objets de commit manquants peuvent être téléchargés à partir du serveur à distance lorsqu'ils sont demandés, mais ne sont téléchargés dans le clone initial que lorsqu'ils sont nécessaires. Bien sûr, cela signifie que si le serveur central est en panne ou n'est pas disponible, les développeurs ne seront pas en mesure de vérifier les anciennes versions de code. Mais étant donné que le journal de commits est disponible, de nouveaux commits peuvent être créés et poussés sur le serveur. (Par comparaison, les clones superficiels git ont le même contenu mais n'ont pas les mêmes commits, ce qui signifie qu'ils ne peuvent être utilisés qu'à des fins de lecture seule.)
Ces améliorations, avec une couche memcached, ont accéléré l'utilisation par Facebook de Mercurial allant jusqu'à surperformer Git pour les pull/clone et les calculs de l'état du répertoire de travail par un facteur de 5. Ces deux changements sont disponibles via des dépôts mercurial de Facebook, remotefilelog et hgwatchman. Bien que cette configuration et l'approche ne soient pas adaptées pour chaque utilisateur Mercurial, il donne au DVCS un coup de pouce dans un monde open-source de plus en plus dominé par Git.