LevelDB场景分析4--BackgroundCompaction

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()) {
10     uint64_t new_log_number = impl->versions_->NewFileNumber();
11     WritableFile* lfile;
12     s = options.env->NewWritableFile(LogFileName(dbname, new_log_number),
13                                      &lfile);
14     if (s.ok()) {
15       edit.SetLogNumber(new_log_number);
16       impl->logfile_ = lfile;
17       impl->logfile_number_ = new_log_number;
18       impl->log_ = new log::Writer(lfile);
19       s = impl->versions_->LogAndApply(&edit, &impl->mutex_);
20     }
21     if (s.ok()) {
22       impl->DeleteObsoleteFiles();
23       impl->MaybeScheduleCompaction();
24     }
25   }
26   impl->mutex_.Unlock();
27   if (s.ok()) {
28     *dbptr = impl;
29   } else {
30     delete impl;
31   }
32   return s;
33 }

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 {
10     snapshot = versions_->LastSequence();
11   }
12 
13   MemTable* mem = mem_;
14   MemTable* imm = imm_;
15   Version* current = versions_->current();
16   mem->Ref();
17   if (imm != NULL) imm->Ref();
18   current->Ref();
19 
20   bool have_stat_update = false;
21   Version::GetStats stats;
22 
23   // Unlock while reading from files and memtables
24   {
25     mutex_.Unlock();
26     // First look in the memtable, then in the immutable memtable (if any).
27     LookupKey lkey(key, snapshot);
28     if (mem->Get(lkey, value, &s)) {
29       // Done
30     } else if (imm != NULL && imm->Get(lkey, value, &s)) {
31       // Done
32     } else {
33       s = current->Get(options, lkey, value, &stats);
34       have_stat_update = true;
35     }
36     mutex_.Lock();
37   }
38 
39   if (have_stat_update && current->UpdateStats(stats)) {
40     MaybeScheduleCompaction();
41   }
42   mem->Unref();
43   if (imm != NULL) imm->Unref();
44   current->Unref();
45   return s;
46 }

DBImpl::RecordReadSample

1 void DBImpl::RecordReadSample(Slice key) {
2   MutexLock l(&mutex_);
3   if (versions_->current()->RecordReadSample(key)) {
4     MaybeScheduleCompaction();
5   }
6 }

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_;
10       break;
11     } else if (
12         allow_delay &&
13         versions_->NumLevelFiles(0) >= config::kL0_SlowdownWritesTrigger) {
14       // We are getting close to hitting a hard limit on the number of
15       // L0 files.  Rather than delaying a single write by several
16       // seconds when we hit the hard limit, start delaying each
17       // individual write by 1ms to reduce latency variance.  Also,
18       // this delay hands over some CPU to the compaction thread in
19       // case it is sharing the same core as the writer.
20       mutex_.Unlock();
21       env_->SleepForMicroseconds(1000);
22       allow_delay = false;  // Do not delay a single write more than once
23       mutex_.Lock();
24     } else if (!force &&
25                (mem_->ApproximateMemoryUsage() <= options_.write_buffer_size)) {
26       // There is room in current memtable
27       break;
28     } else if (imm_ != NULL) {
29       // We have filled up the current memtable, but the previous
30       // one is still being compacted, so we wait.
31       Log(options_.info_log, "Current memtable full; waiting...\n");
32       bg_cv_.Wait();
33     } else if (versions_->NumLevelFiles(0) >= config::kL0_StopWritesTrigger) {
34       // There are too many level-0 files.
35       Log(options_.info_log, "Too many L0 files; waiting...\n");
36       bg_cv_.Wait();
37     } else {
38       // Attempt to switch to a new memtable and trigger compaction of old
39       assert(versions_->PrevLogNumber() == 0);
40       uint64_t new_log_number = versions_->NewFileNumber();
41       WritableFile* lfile = NULL;
42       s = env_->NewWritableFile(LogFileName(dbname_, new_log_number), &lfile);
43       if (!s.ok()) {
44         // Avoid chewing through file number space in a tight loop.
45         versions_->ReuseFileNumber(new_log_number);
46         break;
47       }
48       delete log_;
49       delete logfile_;
50       logfile_ = lfile;
51       logfile_number_ = new_log_number;
52       log_ = new log::Writer(lfile);
53       imm_ = mem_;
54       has_imm_.Release_Store(imm_);
55       mem_ = new MemTable(internal_comparator_);
56       mem_->Ref();
57       force = false;   // Do not force another compaction if have room
58       MaybeScheduleCompaction();
59     }
60   }
61   return s;
62 }

BackgroundCompaction

1 void DBImpl::BackgroundCompaction() {
 2   mutex_.AssertHeld();
 3 
 4   if (imm_ != NULL) {
 5     CompactMemTable();
 6     return;
 7   }
 8 
 9   Compaction* c;
10   bool is_manual = (manual_compaction_ != NULL); // 正常情况下为false,因为初始化时为空
11   InternalKey manual_end;
12   if (is_manual) {
13     ManualCompaction* m = manual_compaction_;
14     c = versions_->CompactRange(m->level, m->begin, m->end);
15     m->done = (c == NULL);
16     if (c != NULL) {
17       manual_end = c->input(0, c->num_input_files(0) - 1)->largest;
18     }
19     Log(options_.info_log,
20         "Manual compaction at level-%d from %s .. %s; will stop at %s\n",
21         m->level,
22         (m->begin ? m->begin->DebugString().c_str() : "(begin)"),
23         (m->end ? m->end->DebugString().c_str() : "(end)"),
24         (m->done ? "(end)" : manual_end.DebugString().c_str()));
25   } else {
26     c = versions_->PickCompaction(); // 找出应该合并的 level 及 level + 1层的FileMetaData*
27   }
28 
29   Status status;
30   if (c == NULL) {
31     // Nothing to do
32   } else if (!is_manual && c->IsTrivialMove()) {
33     // Move file to next level
34     assert(c->num_input_files(0) == 1);
35     FileMetaData* f = c->input(0, 0);
36     c->edit()->DeleteFile(c->level(), f->number);
37     c->edit()->AddFile(c->level() + 1, f->number, f->file_size,
38                        f->smallest, f->largest);
39     status = versions_->LogAndApply(c->edit(), &mutex_);
40     if (!status.ok()) {
41       RecordBackgroundError(status);
42     }
43     VersionSet::LevelSummaryStorage tmp;
44     Log(options_.info_log, "Moved #%lld to level-%d %lld bytes %s: %s\n",
45         static_cast<unsigned long long>(f->number),
46         c->level() + 1,
47         static_cast<unsigned long long>(f->file_size),
48         status.ToString().c_str(),
49         versions_->LevelSummary(&tmp));
50   } else {
51     CompactionState* compact = new CompactionState(c);
52     status = DoCompactionWork(compact); // 核心Compact
53     if (!status.ok()) {
54       RecordBackgroundError(status);
55     }
56     CleanupCompaction(compact);
57     c->ReleaseInputs();
58     DeleteObsoleteFiles();
59   }
60   delete c;
61 
62   if (status.ok()) {
63     // Done
64   } else if (shutting_down_.Acquire_Load()) {
65     // Ignore compaction errors found during shutting down
66   } else {
67     Log(options_.info_log,
68         "Compaction error: %s", status.ToString().c_str());
69   }
70 
71   if (is_manual) {
72     ManualCompaction* m = manual_compaction_;
73     if (!status.ok()) {
74       m->done = true;
75     }
76     if (!m->done) {
77       // We only compacted part of the requested range.  Update *m
78       // to the range that is left to be compacted.
79       m->tmp_storage = manual_end;
80       m->begin = &m->tmp_storage;
81     }
82     manual_compaction_ = NULL;
83   }
84 }

时间: 2024-08-01 03:39:15

LevelDB场景分析4--BackgroundCompaction的相关文章

LevelDB场景分析1--整体结构分析

基本用法 数据结构 class DBImpl : public DB { private: struct CompactionState; struct Writer;// Information kept for every waiting writer Env* const env_; // 文件,目录,日志,Schedule线程 const InternalKeyComparator internal_comparator_; const InternalFilterPolicy inte

LevelDB场景分析2--Open

1.源码 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-&

scala akka 修炼之路6(scala函数式柯里化风格应用场景分析)

胜败兵家事不期,包羞忍耻是男儿--斗牛士fighting,fighting,fighting... 小象学习和使用scala也一段时间了,最初小象学习scala主要为了学习spark生态,但是深入学习scala的一些特性后,深深被scala函数式和面向对象的风格所折服,不得不赞美设计这门语言的设计者.小象大学阶段在使用MATLAB做数据分析和自动化设计时,就非常喜欢使用MATLAB的命令行和面向矩阵运算的风格编写分析代码:喜欢使用java编写层次化和清晰的模块接口,而这些Scala语言设计中都有

典型用户及用户场景分析

典型用户及用户场景分析 糖糖---一个热爱编程的准程序员 名字 糖糖 性别.年龄 男,刚21岁 收入 暂时还没有 比例和重要性 市场比例很大,很重要 典型场景 写了一段自认为很优秀的代码,想要保存在一个合适的地方 使用本软件/服务的环境 需要保存自己的代码 生活/工作情况 现在还是学生,努力学习 知识层次和能力 大学还未毕业,学习热情极高,编程能力较好 用户的动机.目的和困难 保存代码,但是没有合适的地方 用户的偏好 喜欢给代码增加自定义的标签 呆呆---热爱思考人生的缺乏编程联系的“小学生”

mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法

mariadb 10 多源复制(Multi-source replication) 业务使用场景分析,及使用方法 官方mysql一个slave只能对应一个master,mariadb 10开始支持多源复制,一个slave可以有多个master,分别从各自的master复制不同的DB. 这个特性可以用在OLAP环境中,传统电商DB都是拆了再拆,分库分表,sharding,而OLAP环境或者大数据平台环境,通常需要各种数据的聚合,多个平台多个DB数据的复合查询,而这些数据分散在各个库中,怎么办了,当

用户分析和场景分析

用户分析: 名字:二柱子 年龄:30 收入:3000元一个月 代表的比例:代表的是程序维护人员 二柱子:二柱子是一名负责任的找到了网站的管理员,对电脑有很好的掌握,平常最反感得是那些在网站中发小广告的,严重影响了网站的秩序,对网站维护产生干扰, 用户偏好: 场景分析:在进行维护网站的时候,发现有人在网站中发小广告,这让他很生气,希望把这个用户移除出这个网站,并对这个ip进行判断,禁止这个ip访问该网站.

电商抢购秒杀系统的设计_1_应用场景分析

电商抢购秒杀系统的设计_1_应用场景分析 概述 所谓知已知彼,百战不殆,在开始详细介绍实战中的抢购秒杀系统时,我们了解一些抢购秒杀系统系统面临的尴尬与难点.另外需要说明一点,下面的内容都是在工作中慢慢总结得来,我们团队也是慢慢摸着石头过河,甚至最初的的架构设计并非是抢购秒杀系统. 评估系统处理能力 理论基础:LNMP的并发考虑与资源分配 虽然有基础去评估我们应用系统的处理能力,但是电商购买的业务流程挺复杂,从登录,商品详情,购物车,填写收货地址,选择支付方式,创建订单,完成支付,以及隐含的定时服

软件工程结队项目——智能点餐系统典型用户及用户场景分析

一.典型用户分析:一个典型用户描述了一组用户的典型技巧.能力.需要.想法.工作习惯和工作环境. 1.买家典型用户分析: 名字 小郭(石家庄铁道大学交1202-5班) 性别.年龄 男,22岁 联系方式 18330108270 职业 学生 收入 暂无 知识层次和能力 大学在读,会使用各种手机APP软件 生活/工作情况 上课,吃饭,睡觉,偶尔打打游戏,经常在学校门口买饭 动机,目的,困难 很喜欢吃学校门口小吃摊的炒饼,困难:中午3,4节有课时,下课都排队买饭,等的时间太长. 用户偏好 睡觉,打球 用户

典型用户与用户场景分析

自习室查询APP典型用户和用户场景分析: 典型用户 姓名 阿涛 年龄 19 收入 目前为在校大学生,平时做一些兼职工作 用户比例 典型场景 使用软件的查询自习室功能 使用环境 android智能手机 生活工作能力 周一到周五期间在校学习,周末节假日到校外兼职. 知识层次和能力 在校大学生,对电脑.手机使用熟练 动机.目的和困难 姜东每次上自习都需要到教学楼大厅下查看空教室,如果电子屏坏了(比如说二教)就只能一个教室一个教室的去找了. 用户的偏好 爱学习,平时喜欢去图书馆,喜欢科技类书籍 用户场景