or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

directory.mdfdb.mdindex.mdsubspace.mdtuple.md
tile.json

tessl/golang-github-com-apple-foundationdb-bindings-go

Go language bindings for FoundationDB, a distributed key-value store with ACID transactions

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
golangpkg:golang/github.com/apple/foundationdb/bindings/go@v7.3.69

To install, run

npx @tessl/cli install tessl/golang-github-com-apple-foundationdb-bindings-go@7.3.0

index.mddocs/

FoundationDB Go Bindings

The FoundationDB Go bindings provide a comprehensive interface to FoundationDB, a distributed key-value database with multi-version concurrency control (MVCC) and ACID transactions. These bindings enable Go applications to leverage FoundationDB's strong consistency guarantees, automatic conflict resolution, and distributed architecture.

Package Information

  • Package Name: github.com/apple/foundationdb/bindings/go
  • Package Type: golang
  • Language: Go
  • Installation: go get github.com/apple/foundationdb/bindings/go@v7.3.69
  • Requirements: Go 1.11+ with CGO enabled, FoundationDB C API client libraries

Core Imports

import (
    "github.com/apple/foundationdb/bindings/go/src/fdb"
    "github.com/apple/foundationdb/bindings/go/src/fdb/tuple"
    "github.com/apple/foundationdb/bindings/go/src/fdb/subspace"
    "github.com/apple/foundationdb/bindings/go/src/fdb/directory"
)

Basic Usage

package main

import (
    "fmt"
    "log"
    "github.com/apple/foundationdb/bindings/go/src/fdb"
)

func main() {
    // Set API version (required before any other operations)
    fdb.MustAPIVersion(730)

    // Open the default database
    db := fdb.MustOpenDefault()
    defer db.Close()

    // Perform a transaction
    result, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
        // Write a key-value pair
        tr.Set(fdb.Key("hello"), []byte("world"))

        // Read a value
        value := tr.Get(fdb.Key("hello")).MustGet()

        return value, nil
    })

    if err != nil {
        log.Fatalf("Transaction failed: %v", err)
    }

    fmt.Printf("Value: %s\n", string(result.([]byte)))
}

Architecture

The FoundationDB Go bindings are organized into four main packages:

Core Package (fdb)

The core package provides database connectivity, transaction management, and fundamental operations. It implements:

  • Connection Management: Opening databases and managing network lifecycle
  • Transaction Handling: Automatic retry logic with ACID guarantees
  • Asynchronous Operations: Future-based API for parallel execution
  • Atomic Operations: Single-operation mutations (Add, BitAnd, BitOr, BitXor, Max, Min, etc.)
  • Range Queries: Efficient iteration over key ranges with streaming modes
  • Tenant Support: Multi-tenant key isolation

Tuple Package

The tuple package provides encoding/decoding of multi-element tuples into FoundationDB keys while preserving sort order. This enables hierarchical key structures where keys can be composed of multiple typed elements (strings, integers, floats, booleans, UUIDs, etc.) that maintain proper lexicographic ordering.

Subspace Package

The subspace package implements namespace management using tuple prefixes. Subspaces partition the keyspace into logical regions, enabling:

  • Multi-tenancy within a single database
  • Application-level key organization
  • Collision-free key allocation across different data types

Directory Layer

The directory layer provides hierarchical path-based organization of subspaces, similar to a filesystem. It automatically allocates short prefixes for each directory path, enabling:

  • Human-readable hierarchical naming
  • Efficient prefix allocation
  • Path-based access control
  • Directory metadata management

Capabilities

Database Connection and Management

Connect to FoundationDB clusters and manage database lifecycle.

// Open database using default cluster file
func OpenDefault() (Database, error)
func MustOpenDefault() Database

// Open database with specific cluster file
func OpenDatabase(clusterFile string) (Database, error)
func MustOpenDatabase(clusterFile string) Database

// Open database with connection string
func OpenWithConnectionString(connectionString string) (Database, error)

// Close database
func (d Database) Close()

Core FDB Package

Transaction Management

Execute ACID transactions with automatic retry logic for transient conflicts.

// Run transaction with automatic commit and retry
func (d Database) Transact(f func(Transaction) (interface{}, error)) (interface{}, error)

// Run read-only transaction
func (d Database) ReadTransact(f func(ReadTransaction) (interface{}, error)) (interface{}, error)

// Create manual transaction
func (d Database) CreateTransaction() (Transaction, error)

// Transaction operations
func (tr Transaction) Set(key KeyConvertible, value []byte)
func (tr Transaction) Get(key KeyConvertible) FutureByteSlice
func (tr Transaction) Clear(key KeyConvertible)
func (tr Transaction) Commit() FutureNil
func (tr Transaction) OnError(e error) FutureNil

Core FDB Package

Key-Value Operations

Read and write key-value pairs with support for atomic operations.

// Basic operations
func (tr Transaction) Get(key KeyConvertible) FutureByteSlice
func (tr Transaction) Set(key KeyConvertible, value []byte)
func (tr Transaction) Clear(key KeyConvertible)
func (tr Transaction) ClearRange(r Range)

// Atomic operations
func (tr Transaction) Add(key KeyConvertible, param []byte)
func (tr Transaction) BitAnd(key KeyConvertible, param []byte)
func (tr Transaction) BitOr(key KeyConvertible, param []byte)
func (tr Transaction) BitXor(key KeyConvertible, param []byte)
func (tr Transaction) Max(key KeyConvertible, param []byte)
func (tr Transaction) Min(key KeyConvertible, param []byte)
func (tr Transaction) CompareAndClear(key KeyConvertible, param []byte)

Core FDB Package

Range Queries

Efficiently iterate over key ranges with configurable streaming modes.

// Get range of key-value pairs
func (tr Transaction) GetRange(r Range, options RangeOptions) RangeResult

// Range options
type RangeOptions struct {
    Limit   int           // Maximum number of results (0 = unlimited)
    Mode    StreamingMode // Balances latency vs bandwidth
    Reverse bool          // Iterate in reverse order
}

// Iterate over results
func (rr RangeResult) Iterator() RangeIterator
func (ri RangeIterator) Advance() bool
func (ri RangeIterator) Get() (KeyValue, error)

Core FDB Package

Tuple Encoding

Encode and decode multi-element tuples into FoundationDB keys with sort order preservation.

// Create and pack tuples
type Tuple []TupleElement

func (t Tuple) Pack() []byte
func (t Tuple) FDBKey() Key

// Unpack tuples from keys
func Unpack(b []byte) (Tuple, error)

// Versionstamp support
func (t Tuple) PackWithVersionstamp(prefix []byte) ([]byte, error)
func IncompleteVersionstamp(userVersion uint16) Versionstamp

Tuple Package

Subspace Management

Organize keys into namespaced regions using tuple prefixes.

// Create subspaces
func Sub(el ...TupleElement) Subspace
func FromBytes(b []byte) Subspace
func AllKeys() Subspace

// Subspace operations
type Subspace interface {
    Sub(el ...TupleElement) Subspace
    Pack(t Tuple) Key
    Unpack(k KeyConvertible) (Tuple, error)
    Contains(k KeyConvertible) bool
    Bytes() []byte
}

Subspace Package

Directory Layer

Organize subspaces hierarchically using filesystem-like paths.

// Access default root directory
func Root() Directory

// Create custom directory layer
func NewDirectoryLayer(nodeSS, contentSS Subspace, allowManualPrefixes bool) Directory

// Directory operations
type Directory interface {
    CreateOrOpen(t Transactor, path []string, layer []byte) (DirectorySubspace, error)
    Open(rt ReadTransactor, path []string, layer []byte) (DirectorySubspace, error)
    Create(t Transactor, path []string, layer []byte) (DirectorySubspace, error)
    Move(t Transactor, oldPath []string, newPath []string) (DirectorySubspace, error)
    Remove(t Transactor, path []string) (bool, error)
    Exists(rt ReadTransactor, path []string) (bool, error)
    List(rt ReadTransactor, path []string) ([]string, error)
}

// Package-level convenience functions
func CreateOrOpen(t Transactor, path []string, layer []byte) (DirectorySubspace, error)
func Open(rt ReadTransactor, path []string, layer []byte) (DirectorySubspace, error)
func Create(t Transactor, path []string, layer []byte) (DirectorySubspace, error)

Directory Package

API Version Selection

Configure runtime behavior by selecting an API version.

// Set API version (must be called before any other fdb operations)
func APIVersion(version int) error
func MustAPIVersion(version int)

// Query API version
func GetAPIVersion() (int, error)
func IsAPIVersionSelected() bool

Supported versions: 200-730

Core FDB Package

Tenant Support

Isolate key spaces for multi-tenant applications.

// Tenant management
func (d Database) CreateTenant(name KeyConvertible) error
func (d Database) DeleteTenant(name KeyConvertible) error
func (d Database) OpenTenant(name KeyConvertible) (Tenant, error)
func (d Database) ListTenants() ([]Key, error)

// Tenant operations
type Tenant interface {
    CreateTransaction() (Transaction, error)
    Transact(f func(Transaction) (interface{}, error)) (interface{}, error)
    ReadTransact(f func(ReadTransaction) (interface{}, error)) (interface{}, error)
    GetName() Key
}

Core FDB Package

Error Handling

FoundationDB errors are represented by the Error type, which contains an error code. The bindings support two error handling patterns:

Explicit Error Handling:

value, err := tr.Get(fdb.Key("mykey")).Get()
if err != nil {
    return nil, err
}

Panic-Based Error Handling (Recommended in Transactions):

// MustGet panics with fdb.Error, which Transact catches and handles
value := tr.Get(fdb.Key("mykey")).MustGet()

The Transact and ReadTransact methods automatically catch panicked fdb.Error values and either retry the transaction (for retryable errors) or return the error to the caller (for fatal errors).

Futures and Asynchronous Operations

Many operations return Future objects that represent values available at a later time:

  • FutureByteSlice: For Get operations
  • FutureKey: For GetKey operations
  • FutureNil: For operations with no return value (Commit, OnError, Watch)
  • FutureInt64: For operations returning integers
  • FutureKeyArray: For operations returning key arrays

All Future types support:

  • Get() - Block until ready and return value/error
  • MustGet() - Block until ready and return value (panics on error)
  • IsReady() - Check if ready without blocking
  • BlockUntilReady() - Block until ready
  • Cancel() - Cancel the operation

Multiple futures can be outstanding simultaneously, enabling parallel execution within a single goroutine.

Streaming Modes

Range queries support different streaming modes to balance latency and bandwidth:

  • StreamingModeIterator (default): Balanced mode for typical iteration
  • StreamingModeWantAll: Fetch all results (optimizes for bandwidth)
  • StreamingModeSmall: Optimize for small result sets (low latency)
  • StreamingModeMedium: Medium-sized result sets
  • StreamingModeLarge: Large result sets (high bandwidth)
  • StreamingModeSerial: Fetch results serially as needed
  • StreamingModeExact: Fetch exactly the specified limit

Best Practices

Transaction Design

  1. Keep transactions short: FoundationDB transactions have a 5-second time limit
  2. Use read-only transactions when possible: ReadTransact for queries without mutations
  3. Avoid goroutines in transactions: May cause unbounded retries and lost errors
  4. Use MustGet for cleaner code: Within Transact, MustGet is safer than explicit error checking
  5. Avoid blocking on external services: Transactions may retry, repeating external calls

Key Design

  1. Use tuples for structured keys: Maintains sort order and enables range queries
  2. Use subspaces for namespacing: Prevents key collisions between different data types
  3. Use directories for human-readable organization: Maps paths to short prefixes
  4. Plan for key locality: Related data should use nearby keys for efficient range queries

Performance

  1. Batch operations when possible: Multiple reads/writes in one transaction
  2. Use appropriate streaming modes: Balance latency vs bandwidth for range queries
  3. Leverage asynchronous operations: Issue multiple reads in parallel with futures
  4. Consider read snapshots: For consistent reads without preventing concurrent writes
  5. Monitor transaction conflicts: High conflict rates may require key space redesign

Error Handling

  1. Let Transact handle retries: Don't implement custom retry logic
  2. Use OnError for manual transactions: Determines if error is retryable
  3. Check for specific error codes: When handling errors outside transactions
  4. Handle non-retryable errors: Network issues, permissions, etc.