@@ -12,21 +12,23 @@ import (
12
12
"github.com/google/btree"
13
13
)
14
14
15
- var _ heap.Interface = (* syncWorkHeap )(nil )
15
+ var _ heap.Interface = (* innerHeap )(nil )
16
16
17
17
type heapItem struct {
18
18
workItem * syncWorkItem
19
19
heapIndex int
20
20
}
21
21
22
+ type innerHeap []* heapItem
23
+
22
24
// A priority queue of syncWorkItems.
23
25
// Note that work item ranges never overlap.
24
26
// Supports range merging and priority updating.
25
27
// Not safe for concurrent use.
26
28
type syncWorkHeap struct {
27
29
// Max heap of items by priority.
28
30
// i.e. heap.Pop returns highest priority item.
29
- priorityHeap [] * heapItem
31
+ innerHeap innerHeap
30
32
// The heap items sorted by range start.
31
33
// A nil start is considered to be the smallest.
32
34
sortedItems * btree.BTreeG [* heapItem ]
@@ -35,7 +37,6 @@ type syncWorkHeap struct {
35
37
36
38
func newSyncWorkHeap () * syncWorkHeap {
37
39
return & syncWorkHeap {
38
- priorityHeap : make ([]* heapItem , 0 ),
39
40
sortedItems : btree .NewG (
40
41
2 ,
41
42
func (a , b * heapItem ) bool {
@@ -56,7 +57,10 @@ func (wh *syncWorkHeap) Insert(item *syncWorkItem) {
56
57
return
57
58
}
58
59
59
- heap .Push (wh , & heapItem {workItem : item })
60
+ wrappedItem := & heapItem {workItem : item }
61
+
62
+ heap .Push (& wh .innerHeap , wrappedItem )
63
+ wh .sortedItems .ReplaceOrInsert (wrappedItem )
60
64
}
61
65
62
66
// Pops and returns a work item from the heap.
@@ -65,7 +69,9 @@ func (wh *syncWorkHeap) GetWork() *syncWorkItem {
65
69
if wh .closed || wh .Len () == 0 {
66
70
return nil
67
71
}
68
- return heap .Pop (wh ).(* heapItem ).workItem
72
+ item := heap .Pop (& wh .innerHeap ).(* heapItem )
73
+ wh .sortedItems .Delete (item )
74
+ return item .workItem
69
75
}
70
76
71
77
// Insert the item into the heap, merging it with existing items
@@ -97,7 +103,7 @@ func (wh *syncWorkHeap) MergeInsert(item *syncWorkItem) {
97
103
// merged into [beforeItem.start, item.end]
98
104
beforeItem .workItem .end = item .end
99
105
beforeItem .workItem .priority = math .Max (item .priority , beforeItem .workItem .priority )
100
- heap .Fix (wh , beforeItem .heapIndex )
106
+ heap .Fix (& wh . innerHeap , beforeItem .heapIndex )
101
107
mergedBefore = beforeItem
102
108
}
103
109
return false
@@ -113,7 +119,7 @@ func (wh *syncWorkHeap) MergeInsert(item *syncWorkItem) {
113
119
// [item.start, afterItem.end].
114
120
afterItem .workItem .start = item .start
115
121
afterItem .workItem .priority = math .Max (item .priority , afterItem .workItem .priority )
116
- heap .Fix (wh , afterItem .heapIndex )
122
+ heap .Fix (& wh . innerHeap , afterItem .heapIndex )
117
123
mergedAfter = afterItem
118
124
}
119
125
return false
@@ -128,61 +134,54 @@ func (wh *syncWorkHeap) MergeInsert(item *syncWorkItem) {
128
134
wh .remove (mergedAfter )
129
135
// update the priority
130
136
mergedBefore .workItem .priority = math .Max (mergedBefore .workItem .priority , mergedAfter .workItem .priority )
131
- heap .Fix (wh , mergedBefore .heapIndex )
137
+ heap .Fix (& wh . innerHeap , mergedBefore .heapIndex )
132
138
}
133
139
134
140
// nothing was merged, so add new item to the heap
135
141
if mergedBefore == nil && mergedAfter == nil {
136
142
// We didn't merge [item] with an existing one; put it in the heap.
137
- heap . Push ( wh , & heapItem { workItem : item } )
143
+ wh . Insert ( item )
138
144
}
139
145
}
140
146
141
147
// Deletes [item] from the heap.
142
148
func (wh * syncWorkHeap ) remove (item * heapItem ) {
143
- oldIndex := item .heapIndex
144
- newLength := len (wh .priorityHeap ) - 1
149
+ heap .Remove (& wh .innerHeap , item .heapIndex )
145
150
146
- // swap with last item, delete item, then fix heap if required
147
- wh .Swap (newLength , item .heapIndex )
148
- wh .priorityHeap [newLength ] = nil
149
- wh .priorityHeap = wh .priorityHeap [:newLength ]
150
-
151
- // the item was already the last item, so nothing needs to be fixed
152
- if oldIndex != newLength {
153
- heap .Fix (wh , oldIndex )
154
- }
155
151
wh .sortedItems .Delete (item )
156
152
}
157
153
154
+ func (wh * syncWorkHeap ) Len () int {
155
+ return wh .innerHeap .Len ()
156
+ }
157
+
158
158
// below this line are the implementations required for heap.Interface
159
159
160
- func (wh * syncWorkHeap ) Len () int {
161
- return len (wh . priorityHeap )
160
+ func (h innerHeap ) Len () int {
161
+ return len (h )
162
162
}
163
163
164
- func (wh * syncWorkHeap ) Less (i int , j int ) bool {
165
- return wh . priorityHeap [i ].workItem .priority > wh . priorityHeap [j ].workItem .priority
164
+ func (h innerHeap ) Less (i int , j int ) bool {
165
+ return h [i ].workItem .priority > h [j ].workItem .priority
166
166
}
167
167
168
- func (wh * syncWorkHeap ) Swap (i int , j int ) {
169
- wh . priorityHeap [i ], wh . priorityHeap [j ] = wh . priorityHeap [j ], wh . priorityHeap [i ]
170
- wh . priorityHeap [i ].heapIndex = i
171
- wh . priorityHeap [j ].heapIndex = j
168
+ func (h innerHeap ) Swap (i int , j int ) {
169
+ h [i ], h [j ] = h [j ], h [i ]
170
+ h [i ].heapIndex = i
171
+ h [j ].heapIndex = j
172
172
}
173
173
174
- func (wh * syncWorkHeap ) Pop () interface {} {
175
- newLength := len ( wh . priorityHeap ) - 1
176
- value := wh . priorityHeap [ newLength ]
177
- wh . priorityHeap [ newLength ] = nil
178
- wh . priorityHeap = wh . priorityHeap [: newLength ]
179
- wh . sortedItems . Delete ( value )
180
- return value
174
+ func (h * innerHeap ) Pop () interface {} {
175
+ old := * h
176
+ n := len ( old )
177
+ item := old [ n - 1 ]
178
+ old [ n - 1 ] = nil
179
+ * h = old [ 0 : n - 1 ]
180
+ return item
181
181
}
182
182
183
- func (wh * syncWorkHeap ) Push (x interface {}) {
183
+ func (h * innerHeap ) Push (x interface {}) {
184
184
item := x .(* heapItem )
185
- item .heapIndex = len (wh .priorityHeap )
186
- wh .priorityHeap = append (wh .priorityHeap , item )
187
- wh .sortedItems .ReplaceOrInsert (item )
185
+ item .heapIndex = len (* h )
186
+ * h = append (* h , item )
188
187
}
0 commit comments