数据库架构,分布式与并行编程

Enjoy life! Love Program!

  • 博客访问: 423618
  • 博文数量: 42
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-01 22:46
  • 认证徽章:
个人简介

6年Oracle,RAC以及exatadata部署实施经验,对internal有深入研究。曾从事PostgreSQL,MySQL内核开发与性能优化。具备丰富的大规模数据库管理架构与内核研发经验。目前在阿里巴巴从事数据库架构以及新技术引进与落地,并对分布式存储和数据库以及并行计算编程有深入研究。请加微信:ljs521688

ITPUB论坛APP

ITPUB论坛APP



APP发帖 享双倍积分

文章分类

全部博文(42)

文章存档

2017年(13)

2015年(29)

微信关注

IT168企业级官微



微信号:IT168qiye



系统架构师大会



微信号:SACC2013

订阅
热词专题
RocksDB引擎加载 2017-04-05 22:36:30

分类: 数据库开发技术

RocksDB引擎的加载,具体操作是通过DB:Open()方法进行的,具体实现类是DBImpl类。 1.引擎加载call stack

Rocksdb引擎注册和加载时call stack:

###Step 1.在storage engine plugin中的声明,在ha_rocksdb.cc源文件中

myrocks::rocksdb_init_func, /* Plugin Entry Point */

### Step 2.初始化plugin,在加载时被调用,在ha_rocksdb.cc源文件中

static int rocksdb_init_func(void *p)

### Step 3.打开TransactionDB,事务支持,在transaction_db.cc源文件中

status= rocksdb::TransactionDB::Open(main_opts, tx_db_options,rocksdb_datadir, cf_descr,

&cf_handles, &rdb);

###4.最终调用DBImpl实现类的DB::Open方法,完成引擎加载,这里面的

###dbname不是数据库名,而是rocksdb的”data_dir”。在db_impl.cc源文件中

s = DB::Open(db_options_2pc, dbname, column_families_copy, handles, &db);

s = ValidateOptions(db_options, column_families);

当DB::Open()方法被调用并加载引擎时,在此database中的所有CF将被初始化。 2.Column Families元数据读取

在上面的”Step 2”中,也就是初始化plugin时,会根据rocksdb的”data_dir”,list出所有的cf,也就是会调用下面的方法:

status= rocksdb::DB::ListColumnFamilies(rocksdb_db_options, rocksdb_datadir,&cf_names);

这里,我们详细看一下cf是如何被全部list出来的。

在rocksdb的”data_dir”目录下面有一个“CURRENT”文件。我们来strings一把,发现CURRENT文件中存放的内容为“MANIFEST-000017”,这个内容刚好是当前最新的MANIFEST文件。

clip_image002[4]

clip_image004[5]

clip_image005[5]

那么,这是不是巧合呢?我们来看一下源码上的执行路径:

###Step 1:找到CURRENT文件

// Read "CURRENT" file, which contains a pointer to the current manifest file

std::string current;

Status s = ReadFileToString(env, CurrentFileName(dbname), ¤t);

###Step 2:读取CURRENT文件

std::string CurrentFileName(const std::string& dbname) {

return dbname + "/CURRENT";

}

###Step3: 从MANIFEST文件中读取column families,”default”放在“slot 0“中

std::map column_family_names;

// default column family is always implicitly there

column_family_names.insert({0, kDefaultColumnFamilyName});

从源码分析知道,这里的读取只是简单的元数据信息而已,并没有真正的生成内存handle对象。真正生成handle对象是在引擎打开的时候,也就是调用DB::Open()方法的时候。

DB::Open方法是打开rocksdb引擎的入口,它有多个方法的重载。其中有一个重载方法的参数中并没有”column families”,它只有DB option,dbname(实际上是data_dir)以及DB的指针。这个方法,默认只初始化了”default” CF,随后将cf以及空的cf handles传给第二个同名重载方法进行其它非默认CF 初始化。

Status DB::Open(const Options& options, const std::string& dbname, DB** dbptr){

column_families.push_back(

ColumnFamilyDescriptor(kDefaultColumnFamilyName, cf_options));

std::vector handles;

Status s = DB::Open(db_options, dbname, column_families, &handles, dbptr);

…};

这第二个带”column_families”和“handles”参数的DB:Open重载方法是初始化和加载所有CF的关键。

这里值得一提的是,如果这个重载方法调用后,返回的handles中只有一个元素(handle[0]永远指向”default” CF); 那么这个元素将从handles中删除,因为DBImpl类永远有一个指针指向”default” CF,不需要再通过handles来获取。

进入DB:Open()重载方法体后,会进行一系列的检查,主要检查db_option和cf option。

db_option主要检查数据库的db_path,这个db_path就是我们存放SST Table的物理位置。如果没有特意配置db_path,那么一个数据库只允许存放到一个目录下。另外,如果指定db_path时,不允许超过4个。

Cf主要检查各个level 的SST Table当前配置的压缩算法是否支持,也就是在源码编译的时候,是否已经link进来。如果没有,则在open的时候就会报错,导致rocksdb引擎加载失败。 3.初始化Table Cache和memTable

进入DB:Open()之后,会new出实现类DBImpl。在DBImpl的构造方法中,主要完成以下几个功能:

l 初始化table_cache_size

如果“max_open_files==-1“,那table_cache_size的值是” 4194304”,否则就是” max_open_files-10”,保留10个用于其它用途。并按此size初始化table LRU cache队列。

l 初始化column families 的memTable

根据上面ListColumnFamilies()方法拿到的column families,初始对应的memTable

l DUMP数据库信息到日志文件

将各种文件信息DUMP到rocksdb的日志文件中,当然也包含option信息,还包含SST当前Table所支持的压缩算法等

clip_image007[5] 4.执行recover

在recover之前,会对wal_dir以及archive_dir目录进行检查,如果没有就会重新创建目录,默认在db_path下面。

###这把是instrumented锁,用于统计信息之类

impl->mutex_.Lock();

// Handles create_if_missing, error_if_exists

###开始恢复操作

s = impl->Recover(column_families);

进入recover()方法后,会去检查wal_dir和db_path目录,并且检查db_path目录下的“CURRENT”,”IDENTITY”和“LOCK”文件。

首先会检查“LOCK”文件;再检查“CURRENT”文件,此文件主要指向当前最新的“MANIFEST”文件,上文已经提到过;最后检查“IDENTIFY”文件,此文件中存放当前rocksdb的唯一标识。

找到“MANIFEST”文件后,读取最近“MANIFEST“文件中的内容。当然首先会判断”MANIFEST”文件是否损坏,是否以正常的”\n”结尾。如果”MANIFEST”文件正常,则开始执行从”MANIFEST”文件恢复操作。“MANIFEST“文件类似于Oracle的控制文件,因此在运维层面需要不断的备份。

这里的recover仅仅是检查并恢复“MANIFEST”文件中的记录到内存中,这里会再一次的读取“MANIFEST”文件中存储的column families信息,并跟前面ListColumnFamilies()方法中读取到的column families做一个比对。

但是跟ListColumnFamilies()方法不同的是,这里除了读取column families信息以外,还会读取last_sequence,next_file_number,max_column_familiy等内容。

随后在DBImpl::CheckConsistency()类中遍历每个CF下的SST Table物理文件,检查实际文件大小与“MANIFEST“文件中的元数据是否一致,如果不一致,则说明已经损坏。

接下来,将是recover的重要一步,就是获取rocksdb的wal日志进行回放,apply log的详细过程,这需先不赘述,下次再展开。

s = RecoverLogFiles(logs, &next_sequence, read_only);

阅读(127) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册