Skip to content

Commit

Permalink
feat: move tcp to 计算机网络
Browse files Browse the repository at this point in the history
  • Loading branch information
yangjie committed Aug 13, 2020
1 parent d783b3d commit e6e3969
Show file tree
Hide file tree
Showing 19 changed files with 1,148 additions and 65 deletions.
331 changes: 330 additions & 1 deletion LEVLEDB/compaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,333 @@



除了level 0以外,任何一个level的文件内部是有序的,文件之间也是有序的。但是level(n)和level(n+1)中的两个文件的key可能存在交叉。正是因为这种交叉,查找某个key值的时候,level(n) 的查找无功而返,而不得不去level(n+1)查找。如果查找了多次,某个文件不得不查找,却总也找不到,总是去高一级的level,才能找到。这说明该层级的文件和上一级的文件,key的范围重叠的很严重,这是不合理的,会导致效率的下降。因此,需要对该level 发起一次major compaction,减少 level 和level + 1的重叠情况。
除了level 0以外,任何一个level的文件内部是有序的,文件之间也是有序的。但是level(n)和level(n+1)中的两个文件的key可能存在交叉。正是因为这种交叉,查找某个key值的时候,level(n) 的查找无功而返,而不得不去level(n+1)查找。如果查找了多次,某个文件不得不查找,却总也找不到,总是去高一级的level,才能找到。这说明该层级的文件和上一级的文件,key的范围重叠的很严重,这是不合理的,会导致效率的下降。因此,需要对该level 发起一次major compaction,减少 level 和level + 1的重叠情况。



####

```go
// For this user key:
// (1) there is no data in higher levels
// (2) data in lower levels will have larger seq numbers
// (3) data in layers that are being compacted here and have
// smaller seq numbers will be dropped in the next
// few iterations of this loop (by rule (A) above).
// Therefore this deletion marker is obsolete and can be dropped.
```



```go
// NewMergedIterator returns an iterator that merges its input. Walking the
// resultant iterator will return all key/value pairs of all input iterators
// in strictly increasing key order, as defined by cmp.
// The input's key ranges may overlap, but there are assumed to be no duplicate
// keys: if iters[i] contains a key k then iters[j] will not contain that key k.
// None of the iters may be nil.
//
// If strict is true the any 'corruption errors' (i.e errors.IsCorrupted(err) == true)
// won't be ignored and will halt 'merged iterator', otherwise the iterator will
// continue to the next 'input iterator'.
```

我们使用一个迭代器,不断返回按照比较器最小的key。(也就是跳表中最前面的)

- put操作比delete小
- sequence大的比较小

从本例可以看出:switch人第一个expr为true的case开始执行,如果case带有fallthrough,程序会继续执行下一条case,不会再判断下一条case的expr。



- lastukey,表示上一次flush之后的ukey



- 我们会通过snaplist的链表得到当前最小的任期号。

- 小于最小的任期号,表示当前没有活跃的读取正在进行读取。

- ```go
// Gets minimum sequence that not being snapshotted.
func (db *DB) minSeq() uint64 {
db.snapsMu.Lock()
defer db.snapsMu.Unlock()

if e := db.snapsList.Front(); e != nil {
return e.Value.(*snapshotElement).seq
}

return db.getSeq()
}
```



- 迭代器不断取出最小的internal key
- parse解码获得sequecnce, ukey, type



#### 对于相同的ukey

- 我们按照任期号从大到小, 任期号相同则put操作在前面遍历数据



#### 遍历到一个新的ukey的时

我们会尝试flush,生成一个i + 1层文件,要么当前这个文件满了,要么与i + 2层文件重叠过多。



无论是否flush。

- 使用lastukey
- lastseq设置为最大

#### 如果ukey相同

- 对于第一个ukey。使用lastseq这个变量记录seq

- 注意第一个肯定会添加进里头,无论是put还是delete。

- 因为lastseq初始值最大。





- 如果lastseq小于minsequence,那么就丢掉。(因为已经有了一个更新的了)(不管是put还是delete)

这里一方面是说,在sequence相同的时候,已经有了一个key添加到里头去了。

另一方面是说,太老了可以删除。毕竟memetable的find绝对不会返回这条数据。

- 更新lastseq为当前的sequence
- fallthourg会不去判断条件而执行下一条指令



(由于case是会顺序执行的)

(因此这里如果当前sequence的第一条是delete。假设更上层没有数据,那么delete标记本身就可以被删除)。

(这也表示一种暗示,在这条delete操作的之后的put或者delete操作都会被删除)

(主要对于delete操作会做一个额外判断)。

- 如果出现了一个delete。

- 并且sequence小于当前活跃的最小的sequence
- 并且更高层没有这个key
- 丢弃这个delete操作
- 这说明这个delete操作没有用了。



#### case

活跃的sequence为11, 12,1 3。



- 比如说相同sequence,put多次。分别11,12,13.使用不同的任期号比如11,12进行遍历,结果不一样。
- 当我们加入了11之后,10,9,8都得删掉对吧。为什么用小于等于呢。因为同一个sequence只有一个put。
- 为什么要考虑等于呢,因为sequence相同的时候,delete操作和put操作相同。



- 如果说一个sequence,delete,11.
- 如果用11查找,找不到任何数据的。
- 但是我们不能立即删除它。因为如果删除了,那么sequence为3的sstable的put操作就无法删除。
- (毕竟在它之后很可能没有对相同key的put操作)
- 所以我们要判断,如果更高层没有数据,那么就可以直接删除了。
- 如果还有,不能删。而是要传递delete

```go
func (b *tableCompactionBuilder) run(cnt *compactionTransactCounter) error {
snapResumed := b.snapIter > 0
hasLastUkey := b.snapHasLastUkey // The key might has zero length, so this is necessary.
lastUkey := append([]byte{}, b.snapLastUkey...)
lastSeq := b.snapLastSeq
b.kerrCnt = b.snapKerrCnt
b.dropCnt = b.snapDropCnt
// Restore compaction state.
b.c.restore()

defer b.cleanup()

b.stat1.startTimer()
defer b.stat1.stopTimer()

iter := b.c.newIterator()
defer iter.Release()
for i := 0; iter.Next(); i++ {
// Incr transact counter.
cnt.incr()

// Skip until last state.
if i < b.snapIter {
continue
}

resumed := false
if snapResumed {
resumed = true
snapResumed = false
}

ikey := iter.Key()
ukey, seq, kt, kerr := parseInternalKey(ikey)

if kerr == nil {
shouldStop := !resumed && b.c.shouldStopBefore(ikey)

if !hasLastUkey || b.s.icmp.uCompare(lastUkey, ukey) != 0 {
// First occurrence of this user key.

// Only rotate tables if ukey doesn't hop across.
if b.tw != nil && (shouldStop || b.needFlush()) {
if err := b.flush(); err != nil {
return err
}

// Creates snapshot of the state.
b.c.save()
b.snapHasLastUkey = hasLastUkey
b.snapLastUkey = append(b.snapLastUkey[:0], lastUkey...)
b.snapLastSeq = lastSeq
b.snapIter = i
b.snapKerrCnt = b.kerrCnt
b.snapDropCnt = b.dropCnt
}

hasLastUkey = true
lastUkey = append(lastUkey[:0], ukey...)
lastSeq = keyMaxSeq
}

switch {
case lastSeq <= b.minSeq:
// Dropped because newer entry for same user key exist
fallthrough // (A)
case kt == keyTypeDel && seq <= b.minSeq && b.c.baseLevelForKey(lastUkey):
// For this user key:
// (1) there is no data in higher levels
// (2) data in lower levels will have larger seq numbers
// (3) data in layers that are being compacted here and have
// smaller seq numbers will be dropped in the next
// few iterations of this loop (by rule (A) above).
// Therefore this deletion marker is obsolete and can be dropped.
lastSeq = seq
b.dropCnt++
continue
default:
lastSeq = seq
}
} else {
if b.strict {
return kerr
}

// Don't drop corrupted keys.
hasLastUkey = false
lastUkey = lastUkey[:0]
lastSeq = keyMaxSeq
b.kerrCnt++
}

if err := b.appendKV(ikey, iter.Value()); err != nil {
return err
}
}

if err := iter.Error(); err != nil {
return err
}

// Finish last table.
if b.tw != nil && !b.tw.empty() {
return b.flush()
}
return nil
}
```





#### next

- 对每一个sst,我们抽象成一个iterator
- 我们保存,每一个文件最小的key到内存里头来。
- 然后再使用for循环遍历,找到最小的key是哪一个文件里头的。
- 我们保存下标index。这方便从对应的iterator中取出数据

```go
type mergedIterator struct {
cmp comparer.Comparer
iters []Iterator
strict bool

keys [][]byte
index int
dir dir
err error
errf func(err error)
releaser util.Releaser
}
```

```go
func (i *mergedIterator) next() bool {
var key []byte
if i.dir == dirForward {
key = i.keys[i.index]
}
for x, tkey := range i.keys {
if tkey != nil && (key == nil || i.cmp.Compare(tkey, key) < 0) {
key = tkey
i.index = x
}
}
if key == nil {
i.dir = dirEOI
return false
}
i.dir = dirForward
return true
}
```



https://www.cnblogs.com/ym65536/p/10995048.html

#### baselevel

baselevel判断这个key是否不存在i + 2层等更上层。

```go
func (c *compaction) baseLevelForKey(ukey []byte) bool {
for level := c.sourceLevel + 2; level < len(c.v.levels); level++ {
tables := c.v.levels[level]
for c.tPtrs[level] < len(tables) {
t := tables[c.tPtrs[level]]
if c.s.icmp.uCompare(ukey, t.imax.ukey()) <= 0 {
// We've advanced far enough.
if c.s.icmp.uCompare(ukey, t.imin.ukey()) >= 0 {
// Key falls in this file's range, so definitely not base level.
return false
}
break
}
c.tPtrs[level]++
}
}
return true
}
```
8 changes: 7 additions & 1 deletion LEVLEDB/leveldb.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ const (



- 注意sequence不同但是ukey相同的会紧密排列



- 比方说,刚开始sequence为3,插入时候使用4.插入了100个数据后变成104.
- get的时候使用104

Expand Down Expand Up @@ -414,6 +418,8 @@ const (
// 比较的时候先比较key,如果key一样
// 再比较num,num包括sequence序列号和操作类型
// 序列号更小的, 或者序列号相同,delete操作更大。

// 这样子来说在跳表中越小的越前。
func (icmp *iComparer) Compare(a, b []byte) int {
x := icmp.uCompare(internalKey(a).ukey(), internalKey(b).ukey())
if x == 0 {
Expand Down Expand Up @@ -608,7 +614,7 @@ leveldb中的snapshot通过一个读写锁和链表提供。

- acquireSnapshot用于back链表,返回最新的snapshotElemet
- 因此当get的时候,使用当前的sequence生成一个snapshot,结束时侯释放。
- 如果有多个get那么会使用相同的snapshotElement进行访问。
- 如果有多个get那么会使用相同的snapshotElement进行访问。(如果这中间有写操作更新了sequence,那么事实上会使用最新的seq用来生成)(不过好处在于在两个write操作的间隙,都是使用一个snapshotElement就行)(对于snapshotelement就不需要原子读取)。

```go
type snapshotElement struct {
Expand Down
2 changes: 1 addition & 1 deletion LEVLEDB/mwrge.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ if batch.internalLen > db.s.o.GetWriteBuffer() && !db.s.o.GetDisableLargeBatchTr
#### compaction

- opendb的时候开启了两个协程
- 一个叫做mcompaction(不断for循环阻塞在一个管道上, 有值发送过来就执行compaction, 然后往这个cAuto(发送一个nil), 告诉那边完成了)
- 一个叫做mcompaction(不断for循环阻塞在一个管道上, 有值发送过来就执行compaction, 然后往这个cAuto(发送一个nil), 告诉那边完成了)(或许是既能同步又能异步?)

- 一个叫做tcompaction()

Expand Down
2 changes: 1 addition & 1 deletion LEVLEDB/sstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

sstable 是memtable经过minor compaction生成的磁盘数据。

- 避免日志文件过大
- 避免日志文件过大(嘻嘻)
- 降低内存使用率

#### block
Expand Down
Loading

0 comments on commit e6e3969

Please sign in to comment.