Skip to content

Commit 849ed49

Browse files
Now handle duplicates properly by doing a right shift.
1 parent 44d3ba6 commit 849ed49

File tree

4 files changed

+106
-13
lines changed

4 files changed

+106
-13
lines changed

rtree/hilbert/action.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (ga *getAction) nodes() []*node {
6262
}
6363

6464
func (ga *getAction) rects() []*hilbertBundle {
65-
return nil
65+
return []*hilbertBundle{&hilbertBundle{}}
6666
}
6767

6868
func newGetAction(rect rtree.Rectangle) *getAction {

rtree/hilbert/node.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,51 @@ limitations under the License.
1717
package hilbert
1818

1919
import (
20+
"log"
2021
"sort"
2122

2223
"github.com/Workiva/go-datastructures/rtree"
2324
)
2425

26+
func init() {
27+
log.Printf(`I HATE THIS.`)
28+
}
29+
2530
type hilbert int64
2631

2732
type hilberts []hilbert
2833

29-
func getParent(parent *node, key hilbert) *node {
34+
func getParent(parent *node, key hilbert, r1 rtree.Rectangle) *node {
3035
var n *node
3136
for parent != nil && !parent.isLeaf {
3237
n = parent.searchNode(key)
3338
parent = n
3439
}
3540

41+
if parent != nil && r1 != nil { // must be leaf and we need exact match
42+
// we are safe to travel to the right
43+
i := parent.search(key)
44+
for parent.keys.byPosition(i) == key {
45+
if equal(parent.nodes.list[i], r1) {
46+
break
47+
}
48+
49+
i++
50+
if i == parent.keys.len() {
51+
if parent.right == nil { // we are far to the right
52+
break
53+
}
54+
55+
if parent.right.keys.byPosition(0) != key {
56+
break
57+
}
58+
59+
parent = parent.right
60+
i = 0
61+
}
62+
}
63+
}
64+
3665
return parent
3766
}
3867

@@ -195,8 +224,8 @@ type node struct {
195224

196225
func (n *node) insert(kb *keyBundle) rtree.Rectangle {
197226
i := n.keys.search(kb.key)
198-
if n.isLeaf && i != n.keys.len() { // we can have multiple keys with the same hilbert number
199-
for n.keys.list[i] == kb.key {
227+
if n.isLeaf { // we can have multiple keys with the same hilbert number
228+
for i < n.keys.len() && n.keys.list[i] == kb.key {
200229
if equal(n.nodes.list[i], kb.left) {
201230
old := n.nodes.list[i]
202231
n.nodes.list[i] = kb.left

rtree/hilbert/tree.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,15 @@ type keyBundle struct {
5757

5858
type tree struct {
5959
root *node
60-
_padding0 [8]uint64
60+
_ [8]uint64
6161
number uint64
62-
_padding1 [8]uint64
62+
_ [8]uint64
6363
ary, bufferSize uint64
6464
actions *queue.RingBuffer
6565
cache []interface{}
66-
buffer0 [8]uint64
66+
_ [8]uint64
6767
disposed uint64
68-
buffer1 [8]uint64
68+
_ [8]uint64
6969
running uint64
7070
}
7171

@@ -169,7 +169,7 @@ func (tree *tree) fetchKeysInSerial(xns interfaces) {
169169
switch action.operation() {
170170
case add, remove:
171171
for i, key := range action.rects() {
172-
n := getParent(tree.root, key.hilbert)
172+
n := getParent(tree.root, key.hilbert, key.rect)
173173
action.addNode(int64(i), n)
174174
}
175175
case get:
@@ -217,16 +217,17 @@ func (tree *tree) fetchKeysInParallel(xns []interface{}) {
217217
action := xns[index].(action)
218218

219219
j := atomic.AddInt64(&forCache.js[index], 1)
220-
if j > int64(len(action.keys())) { // someone else is updating i
220+
if j > int64(len(action.rects())) { // someone else is updating i
221221
continue
222-
} else if j == int64(len(action.keys())) {
222+
} else if j == int64(len(action.rects())) {
223223
atomic.StoreInt64(&forCache.i, index+1)
224224
continue
225225
}
226226

227227
switch action.operation() {
228228
case add, remove:
229-
n := getParent(tree.root, action.keys()[j])
229+
hb := action.rects()[j]
230+
n := getParent(tree.root, hb.hilbert, hb.rect)
230231
action.addNode(j, n)
231232
case get:
232233
ga := action.(*getAction)

rtree/hilbert/tree_test.go

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func TestDeleteIdenticalHilbergNumber(t *testing.T) {
121121
}
122122

123123
func TestDeleteAll(t *testing.T) {
124-
points := constructRandomMockPoints(5)
124+
points := constructRandomMockPoints(3)
125125
tree := newTree(3, 3)
126126
tree.Insert(points...)
127127
assert.Equal(t, uint64(len(points)), tree.Len())
@@ -346,6 +346,56 @@ func TestMultipleInsertsCauseInternalSplitEvenAryRandomOrder(t *testing.T) {
346346
}
347347
}
348348

349+
func TestInsertDuplicateHilbert(t *testing.T) {
350+
r1 := newMockRectangle(0, 0, 20, 20)
351+
r2 := newMockRectangle(1, 1, 19, 19)
352+
r3 := newMockRectangle(2, 2, 18, 18)
353+
r4 := newMockRectangle(3, 3, 17, 17)
354+
tree := newTree(3, 3)
355+
tree.Insert(r1)
356+
tree.Insert(r2)
357+
tree.Insert(r3)
358+
tree.Insert(r4)
359+
360+
assert.Equal(t, uint64(4), tree.Len())
361+
q := newMockRectangle(0, 0, 30, 30)
362+
result := tree.Search(q)
363+
assert.Len(t, result, 4)
364+
assert.Contains(t, result, r1)
365+
assert.Contains(t, result, r2)
366+
assert.Contains(t, result, r3)
367+
assert.Contains(t, result, r4)
368+
}
369+
370+
func TestDeleteAllDuplicateHilbert(t *testing.T) {
371+
r1 := newMockRectangle(0, 0, 20, 20)
372+
r2 := newMockRectangle(1, 1, 19, 19)
373+
r3 := newMockRectangle(2, 2, 18, 18)
374+
r4 := newMockRectangle(3, 3, 17, 17)
375+
tree := newTree(3, 3)
376+
tree.Insert(r1)
377+
tree.Insert(r2)
378+
tree.Insert(r3)
379+
tree.Insert(r4)
380+
381+
tree.Delete(r1, r2, r3, r4)
382+
assert.Equal(t, uint64(0), tree.Len())
383+
result := tree.Search(constructInfiniteRect())
384+
assert.Len(t, result, 0)
385+
}
386+
387+
func TestInsertDuplicateRect(t *testing.T) {
388+
r1 := newMockRectangle(0, 0, 20, 20)
389+
r2 := newMockRectangle(0, 0, 20, 20)
390+
tree := newTree(3, 3)
391+
tree.Insert(r1)
392+
tree.Insert(r2)
393+
394+
assert.Equal(t, uint64(1), tree.Len())
395+
result := tree.Search(constructInfiniteRect())
396+
assert.Equal(t, rtree.Rectangles{r2}, result)
397+
}
398+
349399
func BenchmarkBulkAddPoints(b *testing.B) {
350400
numItems := 1000
351401
points := constructMockPoints(numItems)
@@ -408,3 +458,16 @@ func BenchmarkQueryBulkPoints(b *testing.B) {
408458
tree.Search(newMockRectangle(i, i, int32(numItems), int32(numItems)))
409459
}
410460
}
461+
462+
func BenchmarkDelete(b *testing.B) {
463+
numItems := b.N
464+
points := constructMockPoints(numItems)
465+
tree := newTree(8, 8)
466+
tree.Insert(points...)
467+
468+
b.ResetTimer()
469+
470+
for i := 0; i < b.N; i++ {
471+
tree.Delete(points[i%numItems])
472+
}
473+
}

0 commit comments

Comments
 (0)