0 编译
leveldb没有使用autoconf/automake来生成Makefile,而是自己编写了Makefile以及平台检测脚本。Makefile中会先调用检测脚本build_detect_platform,并将设置的环境变量保存在build_config.mk文件里。随后Makefile会include build_config.mk文件以进行编译,相关Makefile代码如下,其中的PLATFORM_CCFLAGS等参数将在build_detect_platform中设置并输出给build_config.mk文件:
--- # detect what platform we're building on $(shell CC=$(CC) CXX=$(CXX) TARGET_OS=$(TARGET_OS) \ ./build_detect_platform build_config.mk ./) # this file is generated by the previous line to set build flags and sources include build_config.mk CFLAGS += -I. -I./include $(PLATFORM_CCFLAGS) $(OPT) CXXFLAGS += -I. -I./include $(PLATFORM_CXXFLAGS) $(OPT) LDFLAGS += $(PLATFORM_LDFLAGS) LIBS += $(PLATFORM_LIBS) ---
build_detect_platform脚本内部使用’uname -s’命令来检测类Unix/Linux操作系统的各版本并设置合适的变量(如CC/PLATFORM等变量,以及选择合适的底层平台文件,主要是port/port_posix.cc),然后会依次检测编译环境中是否支持c++ 0x、snappy、tcmalloc,比如检测snappy是否安装的代码如下,对于snappy,若已安装,则会定义-DSNAPPY宏:
# Test whether Snappy library is installed # http://code.google.com/p/snappy/ $CXX $CXXFLAGS -x c++ - -o /dev/null 2>/dev/null <<EOF #include <snappy.h> int main() {} EOF if [ "$?" = 0 ]; then COMMON_FLAGS="$COMMON_FLAGS -DSNAPPY" PLATFORM_LIBS="$PLATFORM_LIBS -lsnappy" fi
如果你想更进一步,连leveldb本身提供的Makefile都不想使用,你想将源代码集成进来,则只需要注意包含port/port_posix.cc文件或者其他合适的跨平台文件,以及定义合适的平台参数,比如对于POSIX环境,可简单的使用’-DLEVELDB_PLATFORM_POSIX’就可以编译。
这里简单介绍了leveldb的编译过程,下面来看看其对平台的具体支持。
leveldb大致通过3层来实现平台语义的支持。
第一层是对外接口,在env.cc/.h与mutexlock.h中实现,mutexlock.h提供了锁的上层接口,而env则主要提供了文件与线程操作的上层接口。这部分代码对于不同平台没有多大差别。主要定义了一个抽象接口。
第二层是文件与线程操作的实际实现,对于posix,则为env_posix.cc。
第三层则是一些原子操作的封装,比如信号、锁等。对于posix,对应的文件为port_posix.cc/.h。
第一层:
Env:环境对象,提供文件、目录、线程等的操作接口。用户可自定义新Env对象,以加强对系统的控制;否则会使用默认的Env对象。对于posix,就是PosixEnv对象。
SequentialFile:顺序读文件
RandomAccessFile:随机读文件
WritableFile:顺序写文件
FileLock:文件锁
第二层:
PosixSequentialFile是对SequentialFile接口的实现,也就是简单调用fread读文件。
posix的RandomAccessFile实现有两个,一个是PosixRandomAccessFile,另一个是PosixMmapReadableFile,前者调用pread读取指定偏移的文件数据,后者为使用mmap来读取文件。
PosixMmapFile是对WritableFile接口的实现,始终使用mmap来写文件。
最终的PosixEnv对象通过调用这些子类来对外提供服务。对于随机读文件,在64位环境下,最多允许1000个文件使用mmap的方式,其他则使用pread方式。
第三层:
利用C++的语言特性定义了Mutex、CondVar,以在使用过程中自动释放pthread_mutex_t、pthread_cond_t资源。另外,也提供了Snappy的操作接口:Snappy_Compress与Snappy_Uncompress。
大部分代码并不复杂,这里就不一一分析了。
helpers/memenv目录下实现了自定义的Env类 — InMemoryEnv,完全基于内存操作的Env对象,对自定义Env对象感兴趣的可了解下。