blob: 31dc55c8f4cc030df6d353780f8930a1673345c1 [file] [log] [blame]
package build_cache
import (
"time"
"github.com/petar/GoLLRB/llrb"
)
// treeNode is a struct used as a node in a LLRB tree. It implements the
// llrb.Item interface.
type treeNode struct {
key int64
values []string
}
func (n *treeNode) Less(b llrb.Item) bool {
return n.key < b.(*treeNode).key
}
// TimeRangeTree is a struct used for indexing builds by timestamp. It stores
// BuildIDs in a tree ordered by time and supports querying for builds within
// a time range.
type TimeRangeTree struct {
tree *llrb.LLRB
}
// NewTimeRangeTree returns a TimeRangeTree instance.
func NewTimeRangeTree() *TimeRangeTree {
return &TimeRangeTree{
tree: llrb.New(),
}
}
// Insert inserts the given BuildID into the TimeRangeTree.
func (t *TimeRangeTree) Insert(k time.Time, v string) {
ts := k.UnixNano()
newItem := &treeNode{
key: ts,
values: []string{v},
}
item := t.tree.Get(newItem)
if item != nil {
node := item.(*treeNode)
node.values = append(node.values, v)
} else {
item = newItem
}
t.tree.ReplaceOrInsert(item)
}
// Delete removes the given BuildID from the TimeRangeTree.
func (t *TimeRangeTree) Delete(k time.Time, v string) string {
rv := ""
ts := k.UnixNano()
item := t.tree.Get(&treeNode{
key: ts,
})
if item != nil {
node := item.(*treeNode)
i := -1
for idx, val := range node.values {
if v == val {
i = idx
break
}
}
if i == -1 {
return ""
}
rv = node.values[i]
node.values = append(node.values[:i], node.values[i+1:]...)
if len(node.values) == 0 {
t.tree.Delete(node)
} else {
t.tree.ReplaceOrInsert(node)
}
}
return rv
}
// GetRange returns BuildIDs within the given time range.
func (t *TimeRangeTree) GetRange(from, to time.Time) []string {
rv := []string{}
a := &treeNode{
key: from.UnixNano(),
}
b := &treeNode{
key: to.UnixNano(),
}
t.tree.AscendRange(a, b, func(v llrb.Item) bool {
rv = append(rv, v.(*treeNode).values...)
return true
})
return rv
}