[原]RocksDB在cygwin编译与使用

前言

RocksDB是在LevelDB原来的代码上进行改进完善的,所以在用法上与LevelDB非常的相似,其特点在http://blog.csdn.net/tzdjzs/article/details/20838945已在详细说明

https://github.com/facebook/rocksdb/wiki/Performance-Benchmarks 来看,RocksDB对比LevelDB的性能有大的提高,由于英文水平不行,这里就不翻译英文说明了。

编译

由于家里的笔记本配置低,一旦运行虚拟机就会卡机,因此才会选择cygwin编译

1. 编译环境

从INSTALL.md文件内容来看,编译RocksDB需要使用到C++11的特点,需要gcc4.7以上版本,RocksDB需要压缩表内容,需要第三方库zlib,bzip2,snappy,并且需要一个编译参数处理库:gflags。第三方库的编译过程可以查看文件说明,而cygwin要支持新的gcc,可以使用cygwin的setup.exe来进行安装,这里推荐163的镜像:mirrors.163.com,从那里可以查看怎么添加cygwin源的。本人使用的是gcc4.8

2. 修改源码

由于本身不支持 Windows 平台, 在 Cygwin 里编译的话, 也会报”Unknow platform”错误,但对比leveldb来说,修改源码的地方会相对较多

2.1 修改build_detect_platform文件

PLATFORM_CXXFLAGS="-std=c++11" 

改为

PLATFORM_CXXFLAGS="-std=gnu++11" 

好像cygwin不能很好支持c++11参数,后来上网找了一下,可以改为gnu++11

case "$TARGET_OS"  in 判断中增加对cygwin平台的支持

CYGWIN_*)
        PLATFORM=OS_LINUX
        COMMON_FLAGS="$COMMON_FLAGS $MEMCMP_FLAG -lpthread -DOS_CYGWIN"
        PLATFORM_LDFLAGS="-lpthread"
        PORT_FILE=port/port_posix.cc
        ;;

2.2 修改Makefile

WARNING_FLAGS = -Wall -Werror
改为
WARNING_FLAGS = -Wall

由于编译会有一个warning,因此需要去掉-Werror参数

2.3 在include/rocksdb/slice.h增加 头文件引用

#include <cstdio>

2.4 修改include/rocksdb/status.h,增加 以下内容

#include <sstream>
#include <cstdlib>

#if defined(OS_CYGWIN) 
namespace std {
    template <class Tdigit>
    string to_string(Tdigit value)
    {
        stringstream stream;
        stream << value;
        return stream.str();
    }
    inline int stoi(const string& str)
    {
        return ::atoi(str.c_str());
    }
}
#endif
这里主要是因为std::to_string及std::stoi是c++11新加的,虽然在cygwin下编译时已增加gnu++11参数,但不知道为何还是不能支持这两个参数的定义,后来就直接增加这两个参数的定义来暂时解决问题 **2.5 修改port/port_posix.h** 在
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
    defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
    defined(OS_ANDROID)
// Use fread/fwrite/fflush on platforms without _unlocked variants
#define fread_unlocked fread
#define fwrite_unlocked fwrite
#define fflush_unlocked fflush
#endif
需要增加对cygwin平台的支持,改为
#if defined(OS_MACOSX) || defined(OS_SOLARIS) || defined(OS_FREEBSD) ||\
    defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_DRAGONFLYBSD) ||\
    defined(OS_ANDROID) || defined(OS_CYGWIN)
// Use fread/fwrite/fflush on platforms without _unlocked variants
#define fread_unlocked fread
#define fwrite_unlocked fwrite
#define fflush_unlocked fflush
#endif

2.6  修改 util/env_posix.cc

需要修改PosixRandomAccessFile函数,把其中一句代码注释掉,最后为

public:
  PosixRandomAccessFile(const std::string& fname, int fd,
                        const EnvOptions& options)
      : filename_(fname), fd_(fd), use_os_buffer_(options.use_os_buffer) {
    //assert(!options.use_mmap_reads);
  }
在NowNanos函数中增加对cygwin平台的支持
 virtual uint64_t NowNanos() {
#if defined(OS_LINUX) || defined(OS_CYGWIN)
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
#elif __MACH__
    clock_serv_t cclock;
    mach_timespec_t ts;
    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
    clock_get_time(cclock, &ts);
    mach_port_deallocate(mach_task_self(), cclock);
#endif
    return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
  }

3. 编译

4. 注意的地方

4.1  好像单元测试的并不能完全通过,由于初步接触,虽然使用了gdb跟踪,但还是不能找到正确的原因,其中上面的2.5把options.use_mmap_reads注释掉,主要是为了通过第一个单元测试db_test,但更新rocksdb主代码后又出现另外的情况,暂时不跟踪了,后来编写一个简单的测试盒子时正常运行,因此先不管单元测试例子的异常情况。

4.2  编译出来的静态库有30多M,比起leveldb静态库不到1M的大小,实在是相差太大。

5. 例子

编译完后,编写一个简单的测试例子来查看结果

5.1 例子源码

#include "rocksdb/db.h"
#include <string>
#include <iostream>

int main(int argc,char**argv)
{
  rocksdb::DB* db;
  rocksdb::Options options;
  options.create_if_missing = true;
  std::string key1 = "abc";
  std::string key2 = "ddd";
  std::string value;

  rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/mytestdb", &db);

  assert(status.ok());

  status = db->Get(rocksdb::ReadOptions(), key1, &value);
  std::cout<<"get key:"<<key1<<",value:"<<value<< std::endl;
  value.clear();
  value = "hello";
  status = db->Put(rocksdb::WriteOptions(), key2, value);
  value.clear();
  status = db->Get(rocksdb::ReadOptions(), key2, &value);
  std::cout<<"get key:"<<key2<<",value:"<<value<< std::endl;
  status = db->Delete(rocksdb::WriteOptions(), key1);

  delete db;
  return 0;
}

5.2 Makefile

INCLUDEDIR=rocksdb.git

all:
    g++ --std=gnu++11 -DSNAPPY -DZLIB -I../$(INCLUDEDIR) -I../$(INCLUDEDIR)/include -c testdb.cpp
    g++ testdb.o -L../$(INCLUDEDIR) -lrocksdb -lsnappy -lz -o testdb

5.3 编译

$ make
g++ --std=gnu++11 -DSNAPPY -DZLIB -I../rocksdb.git -I../rocksdb.git/include -c testdb.cpp
g++ testdb.o -L../rocksdb.git -lrocksdb -lsnappy -lz -o testdb
** **5.4 运行结果**
$ ./testdb.exe
get key:abc,value:
get key:ddd,value:hello