Facebook让Mercurial比Git更快

本周早些时候,Facebook在他们的项目博客上发布了文章《Facebook可伸缩Mercurial》,介绍如何修改Mercurial来扩展版本库。

Facebook在单个版本库中存储了所有代码,两年前存放在subversion上。这样就不用为每个项目区分版本库(共享二进制版本库),整个代码库存储在单个大型源代码版本库上。

对于Facebook不幸的是,git和mercurial的设计都不支持存储所有工程的单个大版本库。由于分布式版本控制系统的目的是存储完整历史,因此,如果公司项目都存储在一个版本库内,那么包含历史的版本库可能大的离谱。相比之下,像CVS和Subversion等集中版本控制系统都能够处理多个项目,使其共享一个版本库,这是因为客户端可以只签出最新版本或者或版本库的子集。

尽管Facebook团队研究修改Git来满足需求,但结论是Mercurial有更多方便的编程API,这些API可用于挂钩,以支持他们的需求。(Git有定义良好的对象结构,工具可解析,而Mercurial具有代码库可用的低层API)。他们已经把许多优化反馈给了上游的Mercurial项目,包括新的图形算法和用C重写的代码。

两项具体修改使Facebook能用Mercurial来处理他们的版本库大小:修改文件的状态更新来检查指定文件的变化,而不是内容的变化(钩入文件变更的操作系统列表),修改签出的文件,以获得一个无需完整历史状态的轻量级副本。

一般情况下,分布式版本控制系统将依据数据的内容而不是时间戳进行哈希。因此,想要判断版本库是否有变化,往往需要扫描每一个文件的计算哈希值来判断文件内容是否有差异。通过限制文件集来检查操作系统报告的上次扫描发生变化的文件,速度与时间戳变化的文件大小成正比,而不是检查当前工作区中的所有文件。Git试图通过运行LSTAT确定具体的文件信息以减少消耗,但仍需扫描资源库所有文件,以确定它们是否发生变化。通过让操作系统提供上述信息,版本库可以优化为只扫描OS报告中发生变化的文件。

Facebook试图解决的另一问题是,最小化下载或克隆操作所需的数据量。将所有项目存储在同一个版本库,版本库的大小是与最后产生伸缩性问题的整个历史数据成正比。因为库中没有进行有效分区,解决方案只能是下载最新版本的文件,其中含有提交日志。

这让开发者能够快速获取当前文件集(与subversion和CVS处理方式大致相同),通过提交日志的迭代遍历,实现这点。然而,如果需要版本库的旧版本(或文件旧版本),本地副本就不含有这样的信息。(Git提供了“浅克隆”的限制选项,这可以从库中得到单一版本,但没有提交历史。)

通过扩展Mercurial API,遗失对象的提交可能“出错”,请求时从远程服务器下载内容,而直到需要时才下载它们。当然,这意味着,如果中心服务器出现故障或不可用,那么开发者将不能签出老版本的代码;由于提交日志可用,所以新提交的内容可以创建并推送到服务器。(相比之下,Git影子克隆具有相同的功能,但有差别的提交,这意味着它们只能用于只读目的。)

这些改进,再加上memcached层,加快了Facebook对Mercurial的使用,拉/克隆操作和工作目录状态都跑赢了Git 5倍。在remotefilelog 和hgwatchman的Facebook Mercurial库,两者都是可访问的。尽管构建和方式并不适合每个Mercurial用户,但是在日益占主导地位的Git开源世界里,它推动了DVCS(分布式版本控制系统的英文简称)的发展。

感谢侯伯薇对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至[email protected]。也欢迎大家通过新浪微博(@InfoQ)或者腾讯微博(@InfoQ)关注我们,并与我们的编辑和其他读者朋友交流。

你可能感兴趣的:(Facebook让Mercurial比Git更快)