-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcompaction.go
76 lines (70 loc) · 1.62 KB
/
compaction.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Copyright (c) 2018-2019 Burak Sezer. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sorted
import (
"log"
"time"
)
func (m *SortedMap) compaction() {
defer m.wg.Done()
// Run immediately. The ticker will trigger that function
// every 10 milliseconds to prevent blocking the SortedMap instance.
if done := m.compactSkipLists(); done {
// Fragmented skiplists are compactd. Quit.
return
}
for {
select {
case <-time.After(10 * time.Millisecond):
if done := m.compactSkipLists(); done {
// Fragmented skiplists are compactd. Quit.
return
}
case <-m.ctx.Done():
return
}
}
}
func (m *SortedMap) compactSkipLists() bool {
m.mu.Lock()
defer m.mu.Unlock()
if len(m.skiplists) == 1 {
m.compacting = false
return true
}
var total int
fresh := m.skiplists[len(m.skiplists)-1]
for _, old := range m.skiplists[:len(m.skiplists)-1] {
if old.len() == 0 {
// It will be removed by the garbage collector.
break
}
it := old.newIterator()
for it.next() {
key := it.key()
err := fresh.set(key, it.value())
if err != nil {
log.Printf("[ERROR] Failed to compact skiplists: %v", err)
return false
}
old.delete(key)
total++
if total > 100000 {
// It's enough. Don't block the instance.
return false
}
}
}
// Remove empty skiplists. Keep the last table.
tmp := []*skipList{m.skiplists[len(m.skiplists)-1]}
for _, t := range m.skiplists[:len(m.skiplists)-1] {
if t.len() == 0 {
continue
}
tmp = append(tmp, t)
}
m.skiplists = tmp
m.compacting = false
return true
}