btree
An efficient B-tree implementation in Go.
Features
- Support for Generics (Go 1.18+).
Map
and Set
types for ordered key-value maps and sets,- Fast bulk loading for pre-ordered data using the
Load()
method. Copy()
method with copy-on-write support.- Path hinting optimization for operations with nearby keys.
Using
To start using this package, install Go and run:
$ go get github.com/tidwall/btree
B-tree types
This package includes the following types of B-trees:
-
btree.Map
:
A fast B-tree for storing ordered key value pairs.
-
btree.Set
:
Like Map
, but only for storing keys.
-
btree.BTreeG
:
A feature-rich B-tree for storing data using a custom comparator. Thread-safe.
-
btree.BTree
:
Like BTreeG
but uses the interface{}
type for data. Backwards compatible. Thread-safe.
btree.Map
Set(key, value)
Get(key, value)
Delete(key)
Len()
Scan(iter)
Reverse(iter)
Ascend(key, iter)
Descend(key, iter)
Iter()
GetAt(index)
DeleteAt(index)
Load(key, value)
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
func main() {
var users btree.Map[string, string]
users.Set("user:4", "Andrea")
users.Set("user:6", "Andy")
users.Set("user:2", "Andy")
users.Set("user:1", "Jane")
users.Set("user:5", "Janet")
users.Set("user:3", "Steve")
users.Scan(func(key, value string) bool {
fmt.Printf("%s %s\n", key, value)
return true
})
fmt.Printf("\n")
users.Delete("user:5")
users.Delete("user:1")
users.Scan(func(key, value string) bool {
fmt.Printf("%s %s\n", key, value)
return true
})
fmt.Printf("\n")
}
btree.Set
Insert(key)
Contains(key)
Delete(key)
Len()
Scan(iter)
Reverse(iter)
Ascend(key, iter)
Descend(key, iter)
Iter()
GetAt(index)
DeleteAt(index)
Load(key)
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
func main() {
var names btree.Set[string]
names.Insert("Jane")
names.Insert("Andrea")
names.Insert("Steve")
names.Insert("Andy")
names.Insert("Janet")
names.Insert("Andy")
names.Scan(func(key string) bool {
fmt.Printf("%s\n", key)
return true
})
fmt.Printf("\n")
names.Delete("Steve")
names.Delete("Andy")
names.Scan(func(key string) bool {
fmt.Printf("%s\n", key)
return true
})
fmt.Printf("\n")
}
btree.BTreeG
Set(item)
Get(item)
Delete(item)
Len()
Scan(iter)
Reverse(iter)
Ascend(key, iter)
Descend(key, iter)
Iter()
GetAt(index)
DeleteAt(index)
Load(item)
SetHint(item, *hint)
GetHint(item, *hint)
DeleteHint(item, *hint)
AscendHint(key, iter, *hint)
DescendHint(key, iter, *hint)
SeekHint(key, iter, *hint)
Copy()
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
type Item struct {
Key, Val string
}
func byKeys(a, b Item) bool {
return a.Key < b.Key
}
func byVals(a, b Item) bool {
if a.Val < b.Val {
return true
}
if a.Val > b.Val {
return false
}
return byKeys(a, b)
}
func main() {
keys := btree.NewBTreeG[Item](byKeys)
vals := btree.NewBTreeG[Item](byVals)
users := []Item{
Item{Key: "user:1", Val: "Jane"},
Item{Key: "user:2", Val: "Andy"},
Item{Key: "user:3", Val: "Steve"},
Item{Key: "user:4", Val: "Andrea"},
Item{Key: "user:5", Val: "Janet"},
Item{Key: "user:6", Val: "Andy"},
}
for _, user := range users {
keys.Set(user)
vals.Set(user)
}
keys.Scan(func(item Item) bool {
fmt.Printf("%s %s\n", item.Key, item.Val)
return true
})
fmt.Printf("\n")
vals.Scan(func(item Item) bool {
fmt.Printf("%s %s\n", item.Key, item.Val)
return true
})
}
btree.BTree
Set(item)
Get(item)
Delete(item)
Len()
Scan(iter)
Reverse(iter)
Ascend(key, iter)
Descend(key, iter)
Iter()
GetAt(index)
DeleteAt(index)
Load(item)
SetHint(item, *hint)
GetHint(item, *hint)
DeleteHint(item, *hint)
AscendHint(key, iter, *hint)
DescendHint(key, iter, *hint)
SeekHint(key, iter, *hint)
Copy()
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
type Item struct {
Key, Val string
}
func byKeys(a, b interface{}) bool {
i1, i2 := a.(*Item), b.(*Item)
return i1.Key < i2.Key
}
func byVals(a, b interface{}) bool {
i1, i2 := a.(*Item), b.(*Item)
if i1.Val < i2.Val {
return true
}
if i1.Val > i2.Val {
return false
}
return byKeys(a, b)
}
func main() {
keys := btree.New(byKeys)
vals := btree.New(byVals)
users := []*Item{
&Item{Key: "user:1", Val: "Jane"},
&Item{Key: "user:2", Val: "Andy"},
&Item{Key: "user:3", Val: "Steve"},
&Item{Key: "user:4", Val: "Andrea"},
&Item{Key: "user:5", Val: "Janet"},
&Item{Key: "user:6", Val: "Andy"},
}
for _, user := range users {
keys.Set(user)
vals.Set(user)
}
keys.Ascend(nil, func(item interface{}) bool {
kvi := item.(*Item)
fmt.Printf("%s %s\n", kvi.Key, kvi.Val)
return true
})
fmt.Printf("\n")
vals.Ascend(nil, func(item interface{}) bool {
kvi := item.(*Item)
fmt.Printf("%s %s\n", kvi.Key, kvi.Val)
return true
})
}
Performance
See tidwall/btree-benchmark for benchmark numbers.
Contact
Josh Baker @tidwall
License
Source code is available under the MIT License.