Convert Figma logo to code with AI

tidwall logobtree

B-tree implementation for Go

1,189
98
1,189
21

Top Related Projects

4,128

BTree provides a simple, ordered, in-memory data structure for Go programs.

9,313

An embedded key/value database for Go.

14,597

An embedded key/value database for Go.

LevelDB key/value database in Go.

15,383

Fast key-value DB in Go.

5,714

RocksDB/LevelDB inspired key-value database in Go

Quick Overview

tidwall/btree is a Go implementation of a B-tree data structure. It provides an efficient, in-memory key/value store with ordered keys and fast operations. The library is designed to be simple, fast, and memory-efficient.

Pros

  • High performance for large datasets
  • Supports ordered key traversal
  • Thread-safe operations
  • Simple API for easy integration

Cons

  • In-memory only, not suitable for persistent storage
  • Limited to Go language
  • May have higher memory usage compared to some other data structures
  • Lacks some advanced features found in more complex databases

Code Examples

  1. Creating a B-tree and inserting key-value pairs:
import "github.com/tidwall/btree"

bt := btree.New(2)
bt.Set("apple", 1)
bt.Set("banana", 2)
bt.Set("cherry", 3)
  1. Retrieving a value and checking if a key exists:
value, ok := bt.Get("banana")
if ok {
    fmt.Printf("Value for 'banana': %v\n", value)
}

exists := bt.Has("grape")
fmt.Printf("'grape' exists: %v\n", exists)
  1. Iterating over keys in ascending order:
bt.Ascend(func(key string, value interface{}) bool {
    fmt.Printf("%s: %v\n", key, value)
    return true
})
  1. Deleting a key-value pair:
deleted := bt.Delete("cherry")
fmt.Printf("'cherry' deleted: %v\n", deleted)

Getting Started

To use tidwall/btree in your Go project, follow these steps:

  1. Install the package:

    go get -u github.com/tidwall/btree
    
  2. Import the package in your Go code:

    import "github.com/tidwall/btree"
    
  3. Create a new B-tree and start using it:

    bt := btree.New(2)
    bt.Set("key", "value")
    value, ok := bt.Get("key")
    

That's it! You can now use the B-tree data structure in your Go application.

Competitor Comparisons

4,128

BTree provides a simple, ordered, in-memory data structure for Go programs.

Pros of btree (Google)

  • More comprehensive documentation and examples
  • Wider adoption and community support
  • Better performance for larger datasets

Cons of btree (Google)

  • More complex API, potentially steeper learning curve
  • Larger codebase, which may impact compilation times

Code Comparison

btree (Google):

import "github.com/google/btree"

tree := btree.New(2)
tree.ReplaceOrInsert(btree.Item(1))
v := tree.Get(btree.Item(1))

btree (tidwall):

import "github.com/tidwall/btree"

tree := btree.New(2)
tree.Set("key", "value")
v, _ := tree.Get("key")

Key Differences

  • btree (Google) uses a generic Item interface, while btree (tidwall) uses key-value pairs
  • btree (tidwall) offers a simpler API with string keys and interface{} values
  • btree (Google) provides more advanced features like custom comparators and iterators

Use Cases

  • btree (Google): Suitable for complex applications requiring fine-grained control and optimized performance
  • btree (tidwall): Ideal for simpler use cases and projects prioritizing ease of use

Both libraries provide efficient B-tree implementations in Go, with btree (Google) offering more features and performance optimizations, while btree (tidwall) focuses on simplicity and ease of use.

9,313

An embedded key/value database for Go.

Pros of bbolt

  • Persistent storage: bbolt provides a persistent key/value store, while btree is an in-memory data structure
  • ACID transactions: Supports fully ACID-compliant transactions
  • Mature and battle-tested: Used in production by etcd and other projects

Cons of bbolt

  • Higher memory usage: Requires more memory due to its persistence and transactional features
  • Slower for certain operations: May be slower for some in-memory operations compared to btree

Code comparison

bbolt:

db, _ := bolt.Open("my.db", 0600, nil)
defer db.Close()

db.Update(func(tx *bolt.Tx) error {
    b, _ := tx.CreateBucketIfNotExists([]byte("MyBucket"))
    return b.Put([]byte("answer"), []byte("42"))
})

btree:

tr := btree.New(2)
tr.Set("answer", "42")
value, _ := tr.Get("answer")

Summary

bbolt is a persistent key/value store with ACID transactions, while btree is an in-memory B-tree implementation. bbolt is better suited for applications requiring data persistence and transactional integrity, while btree may be more efficient for in-memory operations and simpler use cases.

14,597

An embedded key/value database for Go.

Pros of Bolt

  • Full-featured embedded key/value database with ACID transactions
  • Supports multiple buckets for organizing data
  • Battle-tested and widely used in production environments

Cons of Bolt

  • Read-only transactions can block writes
  • Limited querying capabilities beyond simple key lookups
  • Larger memory footprint due to mmap-based design

Code Comparison

Bolt:

db, _ := bolt.Open("my.db", 0600, nil)
defer db.Close()

db.Update(func(tx *bolt.Tx) error {
    b, _ := tx.CreateBucketIfNotExists([]byte("MyBucket"))
    return b.Put([]byte("answer"), []byte("42"))
})

Btree:

tree := btree.New(2)
tree.Set("answer", "42")
value, _ := tree.Get("answer")

Key Differences

  • Bolt is a full database solution, while Btree is an in-memory data structure
  • Bolt provides persistence and ACID transactions, Btree is ephemeral
  • Bolt has a more complex API due to its transactional nature
  • Btree offers simpler, direct access to data without transactions
  • Bolt is better suited for larger datasets and persistent storage needs

LevelDB key/value database in Go.

Pros of goleveldb

  • Implements a full key-value store with persistence
  • Supports advanced features like snapshots and iterators
  • Based on Google's LevelDB, a proven and widely-used database

Cons of goleveldb

  • More complex to use and integrate compared to btree
  • Higher memory overhead due to additional features
  • Slower for in-memory operations

Code Comparison

goleveldb example:

db, _ := leveldb.OpenFile("path/to/db", nil)
defer db.Close()

db.Put([]byte("key"), []byte("value"), nil)
data, _ := db.Get([]byte("key"), nil)

btree example:

tr := btree.New(2)
tr.Set("key", "value")
value, _ := tr.Get("key")

goleveldb provides a full database solution with persistence, while btree offers a simpler in-memory B-tree implementation. goleveldb is better suited for applications requiring a robust key-value store with advanced features, whereas btree is more appropriate for lightweight, in-memory data structures with fast access times.

The choice between these libraries depends on the specific requirements of your project, such as persistence needs, performance constraints, and desired feature set.

15,383

Fast key-value DB in Go.

Pros of Badger

  • Designed as a full-featured key-value store with persistence
  • Optimized for SSDs with LSM tree structure
  • Supports transactions and ACID compliance

Cons of Badger

  • Higher complexity and resource usage
  • Steeper learning curve for implementation
  • May be overkill for simple in-memory use cases

Code Comparison

Badger:

db, _ := badger.Open(badger.DefaultOptions("/tmp/badger"))
defer db.Close()

err := db.Update(func(txn *badger.Txn) error {
    return txn.Set([]byte("key"), []byte("value"))
})

Btree:

tree := btree.New(2, nil)
tree.Set("key", "value")
value, found := tree.Get("key")

Key Differences

  • Badger is a persistent key-value store, while Btree is an in-memory data structure
  • Badger offers more features like transactions and persistence, but with added complexity
  • Btree is simpler and lighter, suitable for in-memory operations and basic key-value storage
  • Badger is optimized for SSDs and large datasets, while Btree is more general-purpose
  • Implementation complexity is higher for Badger, but it provides more robust data management capabilities

Both libraries have their strengths, and the choice between them depends on specific project requirements, such as persistence needs, dataset size, and performance considerations.

5,714

RocksDB/LevelDB inspired key-value database in Go

Pros of Pebble

  • More comprehensive storage engine with advanced features like compaction and WAL
  • Designed for high-performance distributed databases (used in CockroachDB)
  • Better suited for large-scale, production-grade applications

Cons of Pebble

  • Higher complexity and steeper learning curve
  • Potentially overkill for simpler use cases or smaller applications
  • Larger codebase and more dependencies

Code Comparison

Pebble (opening a database):

db, err := pebble.Open("path/to/db", &pebble.Options{})
if err != nil {
    log.Fatal(err)
}
defer db.Close()

Btree (creating and using a B-tree):

tr := btree.New(2, nil)
tr.Set("key", "value")
value, ok := tr.Get("key")

Summary

Pebble is a more robust storage engine suitable for large-scale distributed databases, while Btree is a simpler in-memory B-tree implementation. Pebble offers advanced features like compaction and WAL, making it better for production-grade applications. However, it comes with increased complexity and may be overkill for simpler use cases. Btree, on the other hand, is easier to use and integrate but lacks the advanced features and scalability of Pebble.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

btree

GoDoc

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.
  • Allows for array-like operations. (Counted B-tree)

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

// Basic
Set(key, value)    // insert or replace an item
Get(key, value)    // get an existing item
Delete(key)        // delete an item
Len()              // return the number of items in the map

// Iteration
Scan(iter)         // scan items in ascending order
Reverse(iter)      // scan items in descending order
Ascend(key, iter)  // scan items in ascending order that are >= to key
Descend(key, iter) // scan items in descending order that are <= to key.
Iter()             // returns a read-only iterator for for-loops.

// Array-like operations
GetAt(index)       // returns the item at index
DeleteAt(index)    // deletes the item at index

// Bulk-loading
Load(key, value)   // load presorted items into tree

Example

package main

import (
	"fmt"
	"github.com/tidwall/btree"
)

func main() {
	// create a map
	var users btree.Map[string, string]

	// add some users
	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")

	// Iterate over the maps and print each user
	users.Scan(func(key, value string) bool {
		fmt.Printf("%s %s\n", key, value)
		return true
	})
	fmt.Printf("\n")

	// Delete a couple
	users.Delete("user:5")
	users.Delete("user:1")

	// print the map again
	users.Scan(func(key, value string) bool {
		fmt.Printf("%s %s\n", key, value)
		return true
	})
	fmt.Printf("\n")

	// Output:
	// user:1 Jane
	// user:2 Andy
	// user:3 Steve
	// user:4 Andrea
	// user:5 Janet
	// user:6 Andy
	//
	// user:2 Andy
	// user:3 Steve
	// user:4 Andrea
	// user:6 Andy
}

btree.Set

// Basic
Insert(key)        // insert an item
Contains(key)      // test if item exists
Delete(key)        // delete an item
Len()              // return the number of items in the set

// Iteration
Scan(iter)         // scan items in ascending order
Reverse(iter)      // scan items in descending order
Ascend(key, iter)  // scan items in ascending order that are >= to key
Descend(key, iter) // scan items in descending order that are <= to key.
Iter()             // returns a read-only iterator for for-loops.

// Array-like operations
GetAt(index)       // returns the item at index
DeleteAt(index)    // deletes the item at index

// Bulk-loading
Load(key)          // load presorted item into tree

Example

package main

import (
	"fmt"
	"github.com/tidwall/btree"
)

func main() {
	// create a set
	var names btree.Set[string]

	// add some names
	names.Insert("Jane")
	names.Insert("Andrea")
	names.Insert("Steve")
	names.Insert("Andy")
	names.Insert("Janet")
	names.Insert("Andy")

	// Iterate over the maps and print each user
	names.Scan(func(key string) bool {
		fmt.Printf("%s\n", key)
		return true
	})
	fmt.Printf("\n")

	// Delete a couple
	names.Delete("Steve")
	names.Delete("Andy")

	// print the map again
	names.Scan(func(key string) bool {
		fmt.Printf("%s\n", key)
		return true
	})
	fmt.Printf("\n")

	// Output:
	// Andrea
	// Andy
	// Jane
	// Janet
	// Steve
	//
	// Andrea
	// Jane
	// Janet
}

btree.BTreeG

// Basic
Set(item)               // insert or replace an item
Get(item)               // get an existing item
Delete(item)            // delete an item
Len()                   // return the number of items in the btree

// Iteration
Scan(iter)              // scan items in ascending order
Reverse(iter)           // scan items in descending order
Ascend(key, iter)       // scan items in ascending order that are >= to key
Descend(key, iter)      // scan items in descending order that are <= to key.
Iter()                  // returns a read-only iterator for for-loops.

// Array-like operations
GetAt(index)            // returns the item at index
DeleteAt(index)         // deletes the item at index

// Bulk-loading
Load(item)              // load presorted items into tree

// Path hinting
SetHint(item, *hint)    // insert or replace an existing item
GetHint(item, *hint)    // get an existing item
DeleteHint(item, *hint) // delete an item
AscendHint(key, iter, *hint)
DescendHint(key, iter, *hint)
SeekHint(key, iter, *hint)

// Copy-on-write
Copy()                  // copy the btree

Example

package main

import (
	"fmt"

	"github.com/tidwall/btree"
)

type Item struct {
	Key, Val string
}

// byKeys is a comparison function that compares item keys and returns true
// when a is less than b.
func byKeys(a, b Item) bool {
	return a.Key < b.Key
}

// byVals is a comparison function that compares item values and returns true
// when a is less than b.
func byVals(a, b Item) bool {
	if a.Val < b.Val {
		return true
	}
	if a.Val > b.Val {
		return false
	}
	// Both vals are equal so we should fall though
	// and let the key comparison take over.
	return byKeys(a, b)
}

func main() {
	// Create a tree for keys and a tree for values.
	// The "keys" tree will be sorted on the Keys field.
	// The "values" tree will be sorted on the Values field.
	keys := btree.NewBTreeG[Item](byKeys)
	vals := btree.NewBTreeG[Item](byVals)

	// Create some items.
	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"},
	}

	// Insert each user into both trees
	for _, user := range users {
		keys.Set(user)
		vals.Set(user)
	}

	// Iterate over each user in the key tree
	keys.Scan(func(item Item) bool {
		fmt.Printf("%s %s\n", item.Key, item.Val)
		return true
	})
	fmt.Printf("\n")

	// Iterate over each user in the val tree
	vals.Scan(func(item Item) bool {
		fmt.Printf("%s %s\n", item.Key, item.Val)
		return true
	})

	// Output:
	// user:1 Jane
	// user:2 Andy
	// user:3 Steve
	// user:4 Andrea
	// user:5 Janet
	// user:6 Andy
	//
	// user:4 Andrea
	// user:2 Andy
	// user:6 Andy
	// user:1 Jane
	// user:5 Janet
	// user:3 Steve
}

btree.BTree

// Basic
Set(item)               // insert or replace an item
Get(item)               // get an existing item
Delete(item)            // delete an item
Len()                   // return the number of items in the btree

// Iteration
Scan(iter)              // scan items in ascending order
Reverse(iter)           // scan items in descending order
Ascend(key, iter)       // scan items in ascending order that are >= to key
Descend(key, iter)      // scan items in descending order that are <= to key.
Iter()                  // returns a read-only iterator for for-loops.

// Array-like operations
GetAt(index)            // returns the item at index
DeleteAt(index)         // deletes the item at index

// Bulk-loading
Load(item)              // load presorted items into tree

// Path hinting
SetHint(item, *hint)    // insert or replace an existing item
GetHint(item, *hint)    // get an existing item
DeleteHint(item, *hint) // delete an item
AscendHint(key, iter, *hint)
DescendHint(key, iter, *hint)
SeekHint(key, iter, *hint)

// Copy-on-write
Copy()                  // copy the btree

Example

package main

import (
	"fmt"

	"github.com/tidwall/btree"
)

type Item struct {
	Key, Val string
}

// byKeys is a comparison function that compares item keys and returns true
// when a is less than b.
func byKeys(a, b interface{}) bool {
	i1, i2 := a.(*Item), b.(*Item)
	return i1.Key < i2.Key
}

// byVals is a comparison function that compares item values and returns true
// when a is less than b.
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
	}
	// Both vals are equal so we should fall though
	// and let the key comparison take over.
	return byKeys(a, b)
}

func main() {
	// Create a tree for keys and a tree for values.
	// The "keys" tree will be sorted on the Keys field.
	// The "values" tree will be sorted on the Values field.
	keys := btree.New(byKeys)
	vals := btree.New(byVals)

	// Create some items.
	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"},
	}

	// Insert each user into both trees
	for _, user := range users {
		keys.Set(user)
		vals.Set(user)
	}

	// Iterate over each user in the key tree
	keys.Ascend(nil, func(item interface{}) bool {
		kvi := item.(*Item)
		fmt.Printf("%s %s\n", kvi.Key, kvi.Val)
		return true
	})

	fmt.Printf("\n")
	// Iterate over each user in the val tree
	vals.Ascend(nil, func(item interface{}) bool {
		kvi := item.(*Item)
		fmt.Printf("%s %s\n", kvi.Key, kvi.Val)
		return true
	})

	// Output:
	// user:1 Jane
	// user:2 Andy
	// user:3 Steve
	// user:4 Andrea
	// user:5 Janet
	// user:6 Andy
	//
	// user:4 Andrea
	// user:2 Andy
	// user:6 Andy
	// user:1 Jane
	// user:5 Janet
	// user:3 Steve
}

Performance

See tidwall/btree-benchmark for benchmark numbers.

Contact

Josh Baker @tidwall

License

Source code is available under the MIT License.