File tree 2 files changed +19
-15
lines changed 2 files changed +19
-15
lines changed Original file line number Diff line number Diff line change @@ -301,24 +301,30 @@ func (root *mTreap) removeNode(t *treapNode) {
301
301
// find searches for, finds, and returns the treap node containing the
302
302
// smallest span that can hold npages. If no span has at least npages
303
303
// it returns nil.
304
- // This is slightly more complicated than a simple binary tree search
305
- // since if an exact match is not found the next larger node is
306
- // returned .
304
+ // This is a simple binary tree search that tracks the best-fit node found
305
+ // so far. The best-fit node is guaranteed to be on the path to a
306
+ // (maybe non-existent) lowest-base exact match .
307
307
func (root * mTreap ) find (npages uintptr ) * treapNode {
308
+ var best * treapNode
308
309
t := root .treap
309
310
for t != nil {
310
311
if t .spanKey == nil {
311
312
throw ("treap node with nil spanKey found" )
312
313
}
313
- if t .npagesKey < npages {
314
- t = t .right
315
- } else if t .left != nil && t .left .npagesKey >= npages {
314
+ // If we found an exact match, try to go left anyway. There could be
315
+ // a span there with a lower base address.
316
+ //
317
+ // Don't bother checking nil-ness of left and right here; even if t
318
+ // becomes nil, we already know the other path had nothing better for
319
+ // us anyway.
320
+ if t .npagesKey >= npages {
321
+ best = t
316
322
t = t .left
317
323
} else {
318
- return t
324
+ t = t . right
319
325
}
320
326
}
321
- return nil
327
+ return best
322
328
}
323
329
324
330
// removeSpan searches for, finds, deletes span along with
Original file line number Diff line number Diff line change @@ -58,11 +58,7 @@ func TestTreap(t *testing.T) {
58
58
}
59
59
tr .RemoveSpan (spans [0 ])
60
60
})
61
- t .Run ("Find" , func (t * testing.T ) {
62
- // Note that Find doesn't actually find the best-fit
63
- // element, so just make sure it always returns an element
64
- // that is at least large enough to satisfy the request.
65
- //
61
+ t .Run ("FindBestFit" , func (t * testing.T ) {
66
62
// Run this 10 times, recreating the treap each time.
67
63
// Because of the non-deterministic structure of a treap,
68
64
// we'll be able to test different structures this way.
@@ -72,8 +68,10 @@ func TestTreap(t *testing.T) {
72
68
tr .Insert (s )
73
69
}
74
70
i := tr .Find (5 )
75
- if i .Span ().Pages () < 5 {
76
- t .Fatalf ("expected span of size at least 5, got size %d" , i .Span ().Pages ())
71
+ if i .Span ().Pages () != 5 {
72
+ t .Fatalf ("expected span of size 5, got span of size %d" , i .Span ().Pages ())
73
+ } else if i .Span ().Base () != 0xc0040000 {
74
+ t .Fatalf ("expected span to have the lowest base address, instead got base %x" , i .Span ().Base ())
77
75
}
78
76
for _ , s := range spans {
79
77
tr .RemoveSpan (s )
You can’t perform that action at this time.
0 commit comments