forked from cockroachdb/pebble
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmerging_iter_heap.go
More file actions
140 lines (126 loc) · 3.61 KB
/
Copy pathmerging_iter_heap.go
File metadata and controls
140 lines (126 loc) · 3.61 KB
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2018 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
package pebble
import "github.com/cockroachdb/pebble/internal/invariants"
// mergingIterHeap is a heap of mergingIterLevels. It only reads
// mergingIterLevel.iterKV.K.
//
// REQUIRES: Every mergingIterLevel.iterKV is non-nil.
//
// TODO(sumeer): consider using golang generics.
type mergingIterHeap struct {
cmp Compare
reverse bool
items []mergingIterHeapItem
}
type mergingIterHeapItem struct {
*mergingIterLevel
winnerChild winnerChild
}
// winnerChild represents the child that is less than the other child, i.e.,
// would get promoted up the heap before the other child if the parent was
// removed, or the parent's value "increased".
//
// It can be unknown, represented by winnerChildUnknown. If both children are
// equal, or if there is only one child, any of the three values are
// permitted.
type winnerChild uint8
const (
winnerChildUnknown winnerChild = iota
winnerChildLeft
winnerChildRight
)
// len returns the number of elements in the heap.
func (h *mergingIterHeap) len() int {
return len(h.items)
}
// clear empties the heap.
func (h *mergingIterHeap) clear() {
h.items = h.items[:0]
}
// less is an internal method, to compare the elements at i and j.
func (h *mergingIterHeap) less(i, j int) bool {
ikv, jkv := h.items[i].iterKV, h.items[j].iterKV
if c := h.cmp(ikv.K.UserKey, jkv.K.UserKey); c != 0 {
if h.reverse {
return c > 0
}
return c < 0
}
if h.reverse {
return ikv.K.Trailer < jkv.K.Trailer
}
return ikv.K.Trailer > jkv.K.Trailer
}
// swap is an internal method, used to swap the elements at i and j.
func (h *mergingIterHeap) swap(i, j int) {
h.items[i].mergingIterLevel, h.items[j].mergingIterLevel =
h.items[j].mergingIterLevel, h.items[i].mergingIterLevel
}
// init initializes the heap.
func (h *mergingIterHeap) init() {
// heapify
n := h.len()
for i := n/2 - 1; i >= 0; i-- {
h.down(i, n)
}
}
// fixTop restores the heap property after the top of the heap has been
// modified.
func (h *mergingIterHeap) fixTop() {
h.down(0, h.len())
}
// pop removes the top of the heap.
func (h *mergingIterHeap) pop() *mergingIterLevel {
n := h.len() - 1
h.swap(0, n)
// Parent of n does not know which child is the winner. But since index n is
// removed, the parent of n will have at most one child, and so the value of
// winnerChild is irrelevant, and we don't need to do:
// h.items[(n-1)/2].winnerChild = winnerChildUnknown
h.down(0, n)
item := h.items[n]
h.items = h.items[:n]
return item.mergingIterLevel
}
// down is an internal method. It moves i down the heap, which has length n,
// until the heap property is restored.
func (h *mergingIterHeap) down(i, n int) {
for {
j1 := 2*i + 1
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
break
}
j := j1 // left child
if j2 := j1 + 1; j2 < n {
if h.items[i].winnerChild == winnerChildUnknown {
if h.less(j2, j1) {
h.items[i].winnerChild = winnerChildRight
} else {
h.items[i].winnerChild = winnerChildLeft
}
} else if invariants.Enabled {
wc := winnerChildUnknown
if h.less(j1, j2) {
wc = winnerChildLeft
} else if h.less(j2, j1) {
wc = winnerChildRight
}
if wc != winnerChildUnknown && wc != h.items[i].winnerChild {
panic("winnerChild mismatch")
}
}
if h.items[i].winnerChild == winnerChildRight {
j = j2 // = 2*i + 2 // right child
}
}
if !h.less(j, i) {
break
}
// NB: j is a child of i.
h.swap(i, j)
h.items[i].winnerChild = winnerChildUnknown
i = j
}
}