LevelDB场景分析4--BackgroundCompaction
1.DBImpl::Open
1 Status DB::Open(const Options& options, const std::string& dbname,
2 DB** dbptr) {
3 *dbptr = NULL;
4
5 DBImpl* impl = new DBImpl(options, dbname);
6 impl->mutex_.Lock();
7 VersionEdit edit;
8 Status s = impl->Recover(&edit); // Handles create_if_missing, error_if_exists
9 if (s.ok()) {
uint64_t new_log_number = impl->versions_->NewFileNumber();
WritableFile* lfile;
s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),
&lfile);
if (s.ok()) {
edit.SetLogNumber(new_log_number);
impl->logfile_ = lfile;
impl->logfile_number_ = new_log_number;
impl->log_ = new log::Writer(lfile);
s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
}
if (s.ok()) {
impl->DeleteObsoleteFiles();
impl->MaybeScheduleCompaction();
}
}
impl->mutex_.Unlock();
if (s.ok()) {
*dbptr = impl;
} else {
delete impl;
}
return s;
}
2.DBImpl::Get
1 Status DBImpl::Get(const ReadOptions& options,
2 const Slice& key,
3 std::string* value) {
4 Status s;
5 MutexLock l(&mutex_);
6 SequenceNumber snapshot;
7 if (options.snapshot != NULL) {
8 snapshot = reinterpret_cast<const SnapshotImpl*>(options.snapshot)->number_;
9 } else {
snapshot = versions_->LastSequence();
}
MemTable* mem = mem_;
MemTable* imm = imm_;
Version* current = versions_->current();
mem->Ref();
if (imm != NULL) imm->Ref();
current->Ref();
bool have_stat_update = false;
Version::GetStats stats;
// Unlock while reading from files and memtables
{
mutex_.Unlock();
// First look in the memtable, then in the immutable memtable (if any).
LookupKey lkey(key, snapshot);
if (mem->Get(lkey, value, &s)) {
// Done
} else if (imm != NULL && imm->Get(lkey, value, &s)) {
// Done
} else {
s = current->Get(options, lkey, value, &stats);
have_stat_update = true;
}
mutex_.Lock();
}
if (have_stat_update && current->UpdateStats(stats)) {
MaybeScheduleCompaction();
}
mem->Unref();
if (imm != NULL) imm->Unref();
current->Unref();
return s;
}
3.DBImpl::RecordReadSample
void DBImpl::RecordReadSample(Slice key) {
MutexLock l(&mutex_);
if (versions_->current()->RecordReadSample(key)) {
MaybeScheduleCompaction();
}
}
4.DBImpl::MakeRoomForWrite
1 Status DBImpl::MakeRoomForWrite(bool force) {
2 mutex_.AssertHeld();
3 assert(!writers_.empty());
4 bool allow_delay = !force;
5 Status s;
6 while (true) {
7 if (!bg_error_.ok()) {
8 // Yield previous error
9 s = bg_error_;
break;
} else if (
allow_delay &&
versions_->NumLevelFiles() >= config::kL0_SlowdownWritesTrigger) {
// We are getting close to hitting a hard limit on the number of
// L0 files. Rather than delaying a single write by several
// seconds when we hit the hard limit, start delaying each
// individual write by 1ms to reduce latency variance. Also,
// this delay hands over some CPU to the compaction thread in
// case it is sharing the same core as the writer.
mutex_.Unlock();
env_->SleepForMicroseconds();
allow_delay = false; // Do not delay a single write more than once
mutex_.Lock();
} else if (!force &&
(mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {
// There is room in current memtable
break;
} else if (imm_ != NULL) {
// We have filled up the current memtable, but the previous
// one is still being compacted, so we wait.
Log(options_.info_log, "Current memtable full; waiting...\n");
bg_cv_.Wait();
} else if (versions_->NumLevelFiles() >= config::kL0_StopWritesTrigger) {
// There are too many level-0 files.
Log(options_.info_log, "Too many L0 files; waiting...\n");
bg_cv_.Wait();
} else {
// Attempt to switch to a new memtable and trigger compaction of old
assert(versions_->PrevLogNumber() == );
uint64_t new_log_number = versions_->NewFileNumber();
WritableFile* lfile = NULL;
s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);
if (!s.ok()) {
// Avoid chewing through file number space in a tight loop.
versions_->ReuseFileNumber(new_log_number);
break;
}
delete log_;
delete logfile_;
logfile_ = lfile;
logfile_number_ = new_log_number;
log_ = new log::Writer(lfile);
imm_ = mem_;
has_imm_.Release_Store(imm_);
mem_ = new MemTable(internal_comparator_);
mem_->Ref();
force = false; // Do not force another compaction if have room
MaybeScheduleCompaction();
}
}
return s;
}1-4均会调用MaybeScheduleCompaction()从而调用BackgroundCompaction来完成compact。
以下是核心Compact的过程
BackgroundCompaction
1 void DBImpl::BackgroundCompaction() {
2 mutex_.AssertHeld();
3
4 if (imm_ != NULL) {
5 CompactMemTable();
6 return;
7 }
8
9 Compaction* c;
bool is_manual = (manual_compaction_ != NULL); // 正常情况下为false,因为初始化时为空
InternalKey manual_end;
if (is_manual) {
ManualCompaction* m = manual_compaction_;
c = versions_->CompactRange(m->level, m->begin, m->end);
m->done = (c == NULL);
if (c != NULL) {
manual_end = c->input(, c->num_input_files() - )->largest;
}
Log(options_.info_log,
"Manual compaction at level-%d from %s .. %s; will stop at %s\n",
m->level,
(m->begin ? m->begin->DebugString().c_str() : "(begin)"),
(m->end ? m->end->DebugString().c_str() : "(end)"),
(m->done ? "(end)" : manual_end.DebugString().c_str()));
} else {
c = versions_->PickCompaction(); // 找出应该合并的 level 及 level + 1层的FileMetaData*
}
Status status;
if (c == NULL) {
// Nothing to do
} else if (!is_manual && c->IsTrivialMove()) {
// Move file to next level
assert(c->num_input_files() == );
FileMetaData* f = c->input(, );
c->edit()->DeleteFile(c->level(), f->number);
c->edit()->AddFile(c->level() + , f->number, f->file_size,
f->smallest, f->largest);
status = versions_->LogAndApply(c->edit(), &mutex_);
if (!status.ok()) {
RecordBackgroundError(status);
}
VersionSet::LevelSummaryStorage tmp;
Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n",
static_cast<unsigned long long>(f->number),
c->level() + ,
static_cast<unsigned long long>(f->file_size),
status.ToString().c_str(),
versions_->LevelSummary(&tmp));
} else {
CompactionState* compact = new CompactionState(c);
status = DoCompactionWork(compact); // 核心Compact
if (!status.ok()) {
RecordBackgroundError(status);
}
CleanupCompaction(compact);
c->ReleaseInputs();
DeleteObsoleteFiles();
}
delete c;
if (status.ok()) {
// Done
} else if (shutting_down_.Acquire_Load()) {
// Ignore compaction errors found during shutting down
} else {
Log(options_.info_log,
"Compaction error: %s", status.ToString().c_str());
}
if (is_manual) {
ManualCompaction* m = manual_compaction_;
if (!status.ok()) {
m->done = true;
}
if (!m->done) {
// We only compacted part of the requested range. Update *m
// to the range that is left to be compacted.
m->tmp_storage = manual_end;
m->begin = &m->tmp_storage;
}
manual_compaction_ = NULL;
}
}
LevelDB场景分析4--BackgroundCompaction的更多相关文章
- LevelDB场景分析1--整体结构分析
基本用法 数据结构 class DBImpl : public DB { private: struct CompactionState; struct Writer;// Infor ...
- LevelDB场景分析2--Open
1.源码 1 Status DB::Open(const Options& options, const std::string& dbname, uint64_t new_ ...
- TYPESDK手游聚合SDK服务端设计思路与架构之一:应用场景分析
TYPESDK 服务端设计思路与架构之一:应用场景分析 作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个各 ...
- Oracle dbms_lock.sleep()存储过程使用技巧-场景-分析-实例
<Oracle dbms_lock.sleep()存储过程使用技巧>-场景-分析-实例 摘要:今天是2014年3月10日,北京,雾霾,下午组织相关部门开会.会议的结尾一名开发工程师找到了我 ...
- 理解 python metaclass使用技巧与应用场景分析
理解python metaclass使用技巧与应用场景分析 参考: decorator与metaclass:http://jfine-python-classes.readthedocs. ...
- 数据结构之链表C语言实现以及使用场景分析
牢骚:本篇博客两个星期前已经存为草稿,鉴于发生一些糟糕的事情,今天才基本完成.本人6月份应届毕业生一枚,毕业后当天来到帝都,之后也非常顺利,面试了俩家公司都成功了.一家做C++方面电商ERP,一家做w ...
- mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法
mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法 官方mysql一个slave只能对应一个master,mariadb 10开始支持多源 ...
- ThreadLocal的理解与应用场景分析
对于Java ThreadLocal的理解与应用场景分析 一.对ThreadLocal理解 ThreadLocal提供一个方便的方式,可以根据不同的线程存放一些不同的特征属性,可以方便的在线程中进行存 ...
- Java 常用List集合使用场景分析
Java 常用List集合使用场景分析 过年前的最后一篇,本章通过介绍ArrayList,LinkedList,Vector,CopyOnWriteArrayList 底层实现原理和四个集合的区别.让 ...
随机推荐
- 是否应该将SAN上的SQL Server中的user database的data文件, log文件和TempDB文件放在不同的LUN上?
请看下面的两个精彩解答: 解答1: If your SAN has performance and availability algorithms built into the management ...
- 交叉编译git
git依赖openssl.zlib. 首先编译openssl ./Configure linux-armv4 shared 修改Makefile,CC.RANLIB.MAKEDEPPROG为对应的交叉 ...
- 【转】十个经典的C开源项目代码
原文: http://blog.51cto.com/chinalx1/2143904 --------------------------------------------------------- ...
- Cognos让指定用户不具有删除内容的权限
为了方便用户使用Cognos,现在很多对权限要求不够严格的用户就想到了可以让用户实现匿名登陆,即不登陆系统即可实现访问报表,当然这也仅仅是按照客户的需求,我个人认为一个安全性的数据平台还是需要对登陆. ...
- 简单账本-用完即走的微信小程序
作为一个记账强迫症患者,对当前手机中的记账App都不太满意.这类软件越来越臃肿,越来越慢,启动要半天.联网同步要半天,进入界面又有一堆新功能要介绍.好不容易开始记账,又得各种高大上的选择设定,一笔帐下 ...
- C#.NET常见问题(FAQ)-VS如何整个项目中查找字符串
Ctrl+F打开查找对话框,然后输入查找字符串,电机右边的小三角,选择整个解决方案,就可以遍历所有文件查找指定字符了 更多教学视频和资料下载,欢迎关注以下信息: 我的优酷空间: http:// ...
- Office WORD如何关闭自动检查语法
只要把打钩的地方全部去掉即可.
- Java从零开始学八(循环结构)
一.循环结构 循环结构则是根据判断条件的成立与否,决定程序段落的执行次数,而这个程序段落就称为循环主体.
- Java从零开始学一(环境配置)
一.JDK的下载和安装 1.下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151. ...
- ASP.NET MVC+Bootstrap 实现短信验证
短信验证大家都已经非常熟悉了,基本上每天都在接触手机短信的验证码,比方某宝,某东购物.站点注冊,网上银行等等,都要验证我们的手机号码真实性.这样做有什么优点呢. 曾经咱们在做站点的时候.为了提高用户注 ...