Alluxio开发与代码规范

如果您是一名新的开源贡献者,请先浏览Alluxio开发新手指南以熟悉如何向Alluxio贡献源码。

我们非常感谢您对Alluxio的关注与兴趣!特别感谢您对Alluxio开源社区作出的贡献!

提交代码

  • 我们鼓励你每次尽可能提交小的、单一目的的补丁包,因为要合并一个含有许多不相关的特性的大的改动十分困难。

  • 我们会追踪JIRA里的issues和features,如果你还没有帐号,请先进行注册。

  • 设立JIRA里的一个ticket,在里面详细介绍提议的修改和该修改的目的。

  • 将你的修改作为一个GitHub pull request进行提交,可以查看Github向导中的forking a reposending a pull request学习如何进行这些操作。

  • 在你提交的pull request的标题中,确保其引用了该JIRA ticket,这将会连接到该指定的ticket。例如:

[ALLUXIO-100] Implement an awesome new feature
  • 在pull request的描述框中,请添加该JIRA ticket的超链接。

注意对于一些很小的修改,在提交pull request之前不必创建对应的JIRA tickets,例如

  • 对于仅仅修改一些错别字或者进行一些格式化的pull request,你可以在该pull request的标题中添加”[SMALLFIX]”前缀,例如:
[SMALLFIX] Fix formatting in Foo.java
  • 对于改善Alluxio项目网站的文档(例如修改docs目录下的markdown文件)的pull request,你可以在该pull request的标题中添加”[DOCFIX]”前缀,例如,修改由docs/Contributing-to-Alluxio.md生成的网页文件,其标题可以是:
[DOCFIX] Improve documentation of how to contribute to Alluxio

单元测试

  • 运行所有单元测试
$ cd ${ALLUXIO_HOME}
$ mvn test

这会使用本地文件系统作为底层文件系统。

  • 运行单个单元测试
$ mvn -Dtest=AlluxioFSTest#createFileTest -DfailIfNoTests=false test
  • 要运行特定模块的单元测试, 在想要的子模块下执行maven test命令。例如,要运行HDFS UFS模块测试,执行以下命令
$ mvn test -pl underfs/hdfs

您可以指定运行模块单元测试的Hadoop版本, 我们会创建该版本的模拟HDFS服务来进行测试:

# build and run test on HDFS under filesystem module for Hadoop 2.7.0
$ mvn test -pl underfs/hdfs -Phadoop-2 -Dhadoop.version=2.7.0
# build and run test on HDFS under filesystem module for Hadoop 3.0.0
$ mvn test -pl underfs/hdfs -Phadoop-3 -Dhadoop.version=3.0.0

您也可以使用一个正在运行的HDFS服务来对Alluxio的HDFS 底层文件系统进行更加全面的测试:

$ mvn test -pl underfs/hdfs -PufsContractTest -DtestHdfsBaseDir=hdfs://ip:port/alluxio_test
  • 要想日志输出到STDOUT, 在mvn命令后添加以下参数:
-Dtest.output.redirect=false -Dalluxio.root.logger=DEBUG,CONSOLE
  • 要以交互的方式快速运行某些API测试,你可能需要使用Scala shell,这在 blog有详细说明。

  • 如果libfuse库丢失,其测试将被忽略。要运行这些测试,请安装FUSE中所提到的正确的库。

系统设置

有时你要配置一些系统设置使得测试能在本地通过。其中之一就是ulimit

要使得MacOS上允许的文件数和进程数增加,运行以下命令

$ sudo launchctl limit maxfiles 32768 32768
$ sudo launchctl limit maxproc 32768 32768

同时建议关闭本地Alluxio文件夹的spotlight定位服务。否则,你的Mac在单元测试时将会一直挂起来尝试重新定位文件系统。去System Preferences > Spotlight > Privacy,点击+键,浏览你本地Alluxio的目录,点击Choose将其添加到排除列表。

代码风格

  • 请遵循已有代码的风格。具体来说我们使用Google Java style风格,但有以下不同:
    • 每行最多100个字符
    • 第三方导入被整理到一起以使得IDE格式化起来更简单
    • 类成员变量要使用m前缀,例如private WorkerClient mWorkerClient;
    • 静态成员变量要使用s前缀,例如public static String sUnderFSAddress;
  • Bash脚本遵循Google Shell style, 且必须兼容Bash 3.x版本
  • 你可以下载我们提供的Eclipse formatter
    • 为了让Eclipse能够正确地组织你的导入, 配置”组织导入”以看上去像 这样
    • 如果你使用IntelliJ IDEA:
      • 你可以使用我们提供的formatter,参考Eclipse Code Formatter,或者在IntelliJ IDEA中使用Eclipse Code Formatter Plugin
      • 要自动格式化import,在Preferences->Code Style->Java->Imports->Import中设置Layout为该顺序
      • 要自动将方法按字母顺序重新排序,可以使用Rearranger插件,打开Preferences,查找rearrager,去除不必要的内容,然后右击,选择”Rearrange”,代码将格式化成你需要的风格。
  • 为验证编码风格符合标准,你在提交pull request之前应该先运行checkstyle,并且保证没有警告:
$ mvn checkstyle:checkstyle

日志约定

Alluxio使用SLF4J记录日志,典型用法为:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public MyClass {

  private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);

  public void someMethod() {
    LOG.info("Hello world");
  }
}

下面是Alluxio源码对不同类别日志的约定:

  • 错误级别日志(LOG.error)表示无法恢复的系统级问题。错误级别日志需要包括堆栈跟踪信息。
    LOG.error("Failed to do something due to an exception", e);
    
  • 警告级别日志(LOG.warn)常用于描述用户预期行为与Alluxio实践行为之间的差异。警告级别日志伴有异常消息。相关的堆栈跟踪信息可能在调试级日志中记录。
    LOG.warm("Failed to do something due to {}", e.getMessage());
    
  • 信息级别日志(LOG.info)记录了重要系统状态的更改信息。当有错误消息或需要记录堆栈跟踪信息时,请不要使用信息级别日志。需要注意的是,该日志级别不应该出现在频繁使用的关键路径上的程序中以避免对性能的不利影响。
    LOG.info("Master started.");
    
  • 调试级别日志(LOG.debug)包括Alluxio系统各方面的详细信息。控制流日志记录(Alluxio系统的进入和退出调用)在调试级别日志中完成。调试级别日志异常通常有包含堆栈跟踪的具体信息。
    LOG.debug("Failed to connec to {} due to exception", host + ":" + port, e); // wrong
    LOG.debug("Failed to connec to {} due to exception", mAddress, e); // OK
    if (LOG.isDebugEnabled()) {
    LOG.debug("Failed to connec to address {} due to exception", host + ":" + port, e); // OK
    }
    
  • 跟踪级别日志(LOG.trace)在Alluxio中不使用。

FindBugs

在提交pull request之前,对最新的代码运行 FindBugs确保不出现警告:

$ mvn compile findbugs:findbugs

IDE

你可以通过运行以下命令生成Eclipse配置文件:

$ mvn clean -Pdeveloper install -DskipTests
$ mvn clean -Pdeveloper -DskipTests eclipse:eclipse -DdownloadJavadocs=true -DdownloadSources=true

然后将该文件夹导入到Eclipse中。

也可以运行以下命令将M2_REPO添加到classpath变量中:

$ mvn -Declipse.workspace="your Eclipse Workspace" eclipse:configure-workspace

如果你使用的是IntelliJ IDEA,你可能需要修改Maven profile配置中的’developer’以防止导入错误,可以通过以下方式进行:

View > Tool Windows > Maven Projects

更改Thrift RPC的定义

Alluxio使用Thrift来完成客户端与服务端的RPC通信。common/src/thrift/目录下的.thrift文件,其一方面用于自动生成客户端调用RPC的Java代码,另一方面用于实现服务端的RPC。要想更改一个Thrift定义,你首先必须要安装Thrift的编译器。如果你的机器上有brew,你可以通过运行下面的命令来完成。

$ brew install thrift

然后重新生成Java代码,运行

$ bin/alluxio thriftGen

更改Protocol Buffer消息

Alluxio使用Protocol Buffer来读写日志消息。servers/src/proto/journal/目录下的.proto文件用于为Protocol Buffer消息自动生成Java定义。如果需要修改这些消息,首先要读取更新消息类型从而保证你的修改不会破坏向后兼容性。然后请安装protoc。如果你的机器上有brew,你可以通过运行下面的命令来完成。

$ brew install protobuf@2.5
$ brew link --force protobuf@2.5

然后重新生成Java代码,运行

$ bin/alluxio protoGen

bin/alluxio目录下的命令列表

开发者所用到的大多数命令都在bin/alluxio目录下。下面的表格有对每条命令及其参数的说明。

命令参数介绍
extensions None
format [-s] 格式化Alluxio的Master和所有Worker。选项[-s]表示这条命令只有在底层文件系统为本地的、且已经不存在的情况下才格式化。
formatMaster None
formatWorker None 格式化Alluxio Worker的本地存储。
bootstrapConf <ALLUXIO_MASTER_HOSTNAME> 如果引导程序配置文件alluxio-env.sh不存在,利用ALLUXIO_MASTER_HOSTNAME生成。
fs [fs-commands] 在命令行中与Alluxio进行交互,从而完成基本的文件系统操作。详情见Command Line
fsadmin [fsadmin-commands]
getConf [key]
loadufs <AlluxioPath> <UfsPath> [ExcludePathPrefixes] UfsPath下的文件加载到给定的AlluxioPath中。ExcludePathPrefixes可以是一组用“;”隔开的前缀。ExcludePathPrefixes中每个前缀下的路径都不会被加载。
logLevel [--level <arg>] --logName <arg> [--target <arg>]
runTest <Example> <ReadType> <WriteType> 在一个Alluxio集群上运行一个端到端的测试。Example为"Basic"或者"BasicNonByteBuffer"。ReadType为"CACHE_PROMOTE", "CACHE",或者"NO_CACHE"。WriteType为"MUST_CACHE", "CACHE_THROUGH"或"THROUGH"。
runTests None 在一个Alluxio集群上运行所有端到端的测试。该命令等同于运行包含所有参数的runTest命令。
journalCrashTest [-creates <arg>] [-deletes <arg>] [-renames <arg>] [-maxAlive <arg>] [-testDir <arg>] [-totalTime <arg>] [-help] 在崩溃的情形下测试Master日志系统。可以执行alluxio journalCrashTest -help来获取每个参数的详细信息,或者你可以不带任何参数默认执行。
readJournal [-help] [-noTimeout] 从标准输入读取一个Alluxio的日志文件,并且以将其以文字形式写到标准输出上。你可以对一个日志文件执行类似于alluxio readJournal < journal/FileSystemMaster/log.out的命令。
upgradeJournal None
killAll <WORD> 杀死pid或命令中包含WORD的进程,WORD由用户指定。
copyDir <PATH> 将路径为PATH的文件复制到所有节点。
clearCache None 清空机器上的OS缓冲区缓存。这条命令需要管理员权限。
confDocGen None
thriftGen None 生成所有thrift代码。详情见Change a Thrift RPC definition
protoGen None 生成所有协议缓冲区代码。详情见Change a Protocol Buffer Message
version None 打印Alluxio版本信息。
validateConf None 验证Alluxio配置。
validateEnv <TARGET> [NAME] 验证Alluxio运行环境。TARGET可以是如下选项:
local 在本地运行所有验证项目
master 在本地运行master验证项目
worker 在本地运行worker验证项目
all 在所有master和worker结点运行相关验证项目
masters 在所有master结点运行相关验证项目
workers 在所有worker结点运行相关验证项目
NAME可以是任何项目名称前缀。
如果给出NAME参数,只有名称前缀和参数值相匹配的项目会运行。 例如,指定NAME参数为"master"或"ma"将运行验证项目 master.rpc.port.availablemaster.web.port.available,而不会运行 worker.rpc.port.available项目。
如果未指定NAME参数,所有TARGET相关的项目将被运行。

此外,这些命令的执行有不同的先决条件。formatformatWorkerjournalCrashTestreadJournalversionvalidateConfvalidateEnv命令的先决条件是你已经编译了Alluxio(见编译Alluxio源代码其介绍了如何手动构建Alluxio)。而fsloadufslogLevel, runTestrunTests命令的先决条件是你已经运行了Alluxio系统。

Need help? Ask a Question