GetByScoreRange search reverse will return empty header node, when there is no smaller score than high bound score.
icey129 opened this issue · comments
liumiaomiao commented
When GetByScoreRange with start > end, and start < min(score) in SortedSet, it will return SortedSet.header created by New() function. This confuses the caller and cause unexpected exception.
func New() *SortedSet {
sortedSet := SortedSet{
level: 1,
dict: make(map[string]*SortedSetNode),
}
sortedSet.header = createNode(SKIPLIST_MAXLEVEL, 0, "", nil)
return &sortedSet
}
The logic of reverse search is:
if reverse { // search from end to start
**x := this.header**
if excludeEnd {
for i := this.level - 1; i >= 0; i-- {
for x.level[i].forward != nil &&
x.level[i].forward.score < end {
x = x.level[i].forward
}
}
} else {
for i := this.level - 1; i >= 0; i-- {
for x.level[i].forward != nil &&
x.level[i].forward.score <= end {
x = x.level[i].forward
}
}
}
for x != nil && limit > 0 {
if excludeStart {
if x.score <= start {
break
}
} else {
if x.score < start {
break
}
}
next := x.backward
**nodes = append(nodes, x)**
limit--
x = next
}
}
For example, run the following test will retun the unexpected header create by New() function.
func TestGetByScoreRange(t *testing.T) {
var (
set = sortedset.New()
datas = []struct {
key string
score sortedset.SCORE
value int
}{
{
key: "100",
score: 100,
value: 100,
},
{
key: "103",
score: 103,
value: 103,
},
{
key: "105-1",
score: 105,
value: 105,
},
{
key: "105-2",
score: 105,
value: 105,
},
{
key: "107",
score: 107,
value: 107,
},
}
)
for _, v := range datas {
set.AddOrUpdate(v.key, v.score, v.value)
}
nodes := set.GetByScoreRange(sortedset.SCORE(80), sortedset.SCORE(0), nil)
fmt.Println(len(nodes))
if len(nodes) > 0 {
t.Errorf("return unexpected node, key=%s, score=%d, value=%v", nodes[0].Key(), nodes[0].Score(), nodes[0].Value)
}
}