Java Solaris 加入Sun中国技术社区 我的社区 注册说明
 
JDK 6.0 API 中文版
 
 
 
 
Java API 文档中文版
OpenGrok 内部原理
 
By Chandan B.N, 4/30/08  

OpenGrok 包含以下主要工具包:

  • org.opensolaris.opengrok.analysis:负责分析程序、源文件、归档文件(如 ZIP 和 tar)、文档(如手册页)、xml 和 html 文件,以及图像等。
  • org.opensolaris.opengrok.index:构建或更新 Lucene 索引,反复沿目录树向下。
  • org.opensolaris.opengrok.search:拥有一些实用程序,提供搜索结果、匹配的上下文等界面。
  • org.opensolaris.opengrok.history:源代码版本控制的抽象。
  • org.opensolaris.opengrok.web: webapp 使用的实用程序例程。

源是其工作方式的最终参考指南,以下是某些机制的简要说明。

分析

可以将这个包看做一个独立的部门,该部门拥有一些工程师(称为 Analyzer),他们是各种程序类型或文件类型方面的主题专家。 CAnalyzer 了解 C 编程语言。ELF Analyzer 知道如何读取 ELF 符号以及如何从 ELF 文件(可执行文件)读取字符串表。

分析的核心是 Analyzer Guru。他了解所有 Analyzer 的名称。大部分分析器坐在静态办公室中。为每个分析工作雇佣一个新 Analyzer 是比较昂贵的。

当索引器认为他需要分析要索引的文件,他会调用 Analyzer Guru。Analyzer Guru 确切地知道应该将文件发送给谁。他创建一个空白的 Lucene Document 和一个 FileInputStream 并将它发送给合适的 Analyzer。他知道 Analyzer 的名称,因为他们最初需要告诉他他们专长的文件扩展名和文件类型的幻数。

得到文档时,Analyzer 会将它发送给他的老板(上级),使他们用更多的 Lucene 字段填充它。老板再将它发送给他的老板,以此类推。越在管理链的上一级,所做的工作越少(越专)。例如,CAnalyzer 知道大量关于 C 关键字和注释的知识,知道如何生成超文本交叉参考 C 文件,他的老板 Plain Analyzer 就只能读取纯文本文件。他的标点知识较少,并且会忽略大部分他认为没有必要的标点符号。他知道哪些是网站地址和电子邮件地址,因此当要求他交叉参考一个文件时,他只需超链接他能识别的 URL。

Plain Analyzer 还会完成一项重要的工作。他将在程序文件中找到的定义外包到 Exuberant Ctags 中。他将文件发送到 exuberant ctags,exuberant ctags 将确切地告诉他哪些符号被看作定义。Plain Analyzer 将该信息添加到 Lucene Document。

他的老板,File Analyzer 是该部门的老板。每个人都要向他报告。他所做的就是在 Lucene 文档上盖上文件日期和名称,然后将它发送回来。

此工具包是非常模块化的。可以扩展它来分析任何程序类型。要添加某种新编程语言或文件类型的 Analyzer,只需扩展或复制一个合适的 Analyzer 并将他的名字介绍给 Analyzer Guru。

要获得版本控制历史,Analyzer Guru 会调用他的老朋友 History Guru。这家伙比 Analyzer Guru 老多了,他的长胡子几乎碰到地上了。他有几个助手叫做 History Reader。它们只是读取给定文件和目录的版本控制日志历史。目前,这些助手可以读取 Subversion、CVS 和 SCCS 日志。要能够支持一种新的源代码版本控制,只需使用一个新的可以读取这些日志的助理读取器即可。

Analyzer Guru 一得到返回的带有不同信息(比如定义、全文、符号、历史)的 Document,就会将它发送回 Indexer。

索引更新

该索引是源树中所有文件的反向索引。对于源树中每一个惟一的单词,它都包含一个在其中可以找到该单词的文件列表。同时,像 cscope 和 ctags 这样的工具也会构建索引,它们不能以增量方式更新它。只能从头重新构建它。OpenGrok 使用了现代索引方法并能采用增量方式更新其索引(即只更新自上次构建索引以来被更改/添加/删除的文件)。

要知道哪些文件被更改或被创建或删除了,我们需要在索引中保留一个分类的文件列表,这些文件标记有上次修改文件的日期(转换为字母数字字符串,这样如果 date1 < date2 则 dateString(date1) < dateString(date2)。我们遍历文件树,在每个阶段分类子节点上,通过这种方式得到分类的文件路径列表。

它向下找到两个分类列表的不同(磁盘上的文件列表 Vs 索引中的文件列表)。左手侧是文件树,其右手侧是需要更新的索引。为了进行说明,我们昨天已经有了一个正确索引的树。

今天,我们删除一个 makefile 并添加一个新文件 foo.c 并修改 frotz.c。在第一个过程中,我们发现索引列表上 makefile-yesterday 和 frotz.c-today 与树遍历列表不一致。因此我们从索引中删除这些行(即文档)。

在第二个过程中,我们发现 foo.c-today 和 frotzc-today 是新的,我们将这些文档添加到索引。

Lucene 反向索引可以打开来添加更多文档或删除现有文档。要更新文档,必须首先删除它,关闭索引,然后再次添加它。要优化进行快速更新,我们可以首先在索引中删除所有源树中被更改或删除的文件。然后,在第二个过程中,添加所有不在索引中的文档。