Skip to content

Commit

Permalink
Add major compaction annotated
Browse files Browse the repository at this point in the history
  • Loading branch information
shenlongxing committed Apr 18, 2019
1 parent fa2692d commit 39f4a2c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 4 deletions.
11 changes: 10 additions & 1 deletion leveldb/db_compaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ func (b *tableCompactionBuilder) cleanup() {
}
}

// 真正的compaction动作
// 真正的compaction动作,实质上就是个归并compaction的过程
func (b *tableCompactionBuilder) run(cnt *compactionTransactCounter) error {
snapResumed := b.snapIter > 0
hasLastUkey := b.snapHasLastUkey // The key might has zero length, so this is necessary.
Expand Down Expand Up @@ -572,6 +572,7 @@ func (db *DB) tableCompaction(c *compaction, noTrivial bool) {
defer c.release()

rec := &sessionRecord{}
// 记录source level参与compaction的max key
rec.addCompPtr(c.sourceLevel, c.imax)

// 如果source层只有一个文件,source+1层没有符合的文件
Expand All @@ -594,7 +595,9 @@ func (db *DB) tableCompaction(c *compaction, noTrivial bool) {
rec.delTable(c.sourceLevel+i, t.fd.Num)
}
}
// 参与compaction的文件size和
sourceSize := int(stats[0].read + stats[1].read)
// 通过snapshot list,查找存在的最小的seq
minSeq := db.minSeq()
db.logf("table@compaction L%d·%d -> L%d·%d S·%s Q·%d", c.sourceLevel, len(c.levels[0]), c.sourceLevel+1, len(c.levels[1]), shortenb(sourceSize), minSeq)

Expand All @@ -608,10 +611,15 @@ func (db *DB) tableCompaction(c *compaction, noTrivial bool) {
strict: db.s.o.GetStrict(opt.StrictCompaction),
tableSize: db.s.o.GetCompactionTableSize(c.sourceLevel + 1),
}
// 真正的compaction动作
db.compactionTransact("table@build", b)

// Commit.
stats[1].startTimer()
// commit compaction,也就是:
// 1. 生成新的ersion,并计算cSocore、cLevel
// 2. 将sessionRecord写入manifest
// 3. 并将current version设置为新的version
db.compactionCommit("table", rec)
stats[1].stopTimer()

Expand Down Expand Up @@ -852,6 +860,7 @@ func (db *DB) tCompaction() {
default:
}
// Resume write operation as soon as possible.

if len(waitQ) > 0 && db.resumeWrite() {
for i := range waitQ {
waitQ[i].ack(nil)
Expand Down
36 changes: 33 additions & 3 deletions leveldb/session_compaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (s *session) pickCompaction() *compaction {
}
} else {
// 非cSore>1的场景,则是seekLeft == 0触发
// 这种场景下,参与compaction的source层文件就是seekLeft == 0的文件
// 这种场景下,参与compaction的source层文件就是seekLeft == 0的文件,记录在cSeek中
if p := atomic.LoadPointer(&v.cSeek); p != nil {
ts := (*tSet)(p)
sourceLevel = ts.level
Expand Down Expand Up @@ -193,6 +193,7 @@ func (c *compaction) release() {
}

// Expand compacted tables; need external synchronization.
// 基于source level的待compaction文件进行expand,查找参加compaction的文件
func (c *compaction) expand() {
// 参与compaction的文件数的上限
limit := int64(c.s.o.GetCompactionExpandLimit(c.sourceLevel))
Expand All @@ -206,20 +207,49 @@ func (c *compaction) expand() {

// c.levels是source,source+1层参与compaction的文件
t0, t1 := c.levels[0], c.levels[1]
// compaction源文件的[imin, imax]
imin, imax := t0.getRange(c.s.icmp)
// We expand t0 here just incase ukey hop across tables.
// 扩展source level参与compaction的文件
// 扩展source level参与compaction的文件,原则很简单,就是查找与source文件的[imin, imax]有overlap的文件
t0 = vt0.getOverlaps(t0, c.s.icmp, imin.ukey(), imax.ukey(), c.sourceLevel == 0)
if len(t0) != len(c.levels[0]) {
// 更新imin,imax
imin, imax = t0.getRange(c.s.icmp)
}
// 使用imin,imax去level+1层查找overlap的文件
t1 = vt1.getOverlaps(t1, c.s.icmp, imin.ukey(), imax.ukey(), false)
// Get entire range covered by compaction.
// level N/level N+1的[min,max]并集
amin, amax := append(t0, t1...).getRange(c.s.icmp)

// See if we can grow the number of inputs in "sourceLevel" without
// changing the number of "sourceLevel+1" files we pick up.
// 在不修改level+1的前提下,尽量扩大level层参与compaction的文件数
// 在不修改level+1的前提下,尽量扩大level层参与compaction的文件数,这么处理的原因是:
/*
a b c d
source level <-----><--------><--------><------>
A B C D E F
level +1 <---><---><----><----><----><---->
上面的例子中,比如发起compaction的源文件是b,查找compaction文件的流程如下:
1. 在source层进行expand,由于不是level 0,不存在overlap。结果还是b
2. 使用b文件的key范围[min,max]到level+1层进行比较,得到overlap的文件B、C、D
3. 此时b、B、C、D文件为compaction的输入文件
但是还有另外一种情况:
a b c d
source level <---><--------><--------><------>
A B C D E
level +1 <-------><----><----><----><---->
这种情况下的compaction流程为:
1. 在source层进行expand,由于不是level 0,不存在overlap。结果还是b
2. 使用b文件的key范围[min,max]到level+1层进行比较,得到overlap的文件A、B
3. 这时候compaction的输入文件是否就是b、A、B了呢?观察一下可以发现,source level的a文件
key的范围完全在A+B范围内。这时候把a进入到compaction的目标文件,完全不会影响level+1的key的范围
4. 因此,原则上:在不修改level+1的前提下,尽量扩大level层参与compaction的文件数
在第一个例子中,能不能把与B、C、D有overlap的a加进来呢?答案是否定的。因为leveldb中,除了level 0
以外,其他level不能存在key的overlap。如果把a加入到compaction的源文件,生成的结果文件会与A存在overlap。
*/
if len(t1) > 0 {
exp0 := vt0.getOverlaps(nil, c.s.icmp, amin.ukey(), amax.ukey(), c.sourceLevel == 0)
if len(exp0) > len(t0) && t1.size()+exp0.size() < limit {
Expand Down

0 comments on commit 39f4a2c

Please sign in to comment.