or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

go-api.mddocs/reference/

FoundationDB Go API Reference

Complete reference for the FoundationDB Go client library, providing idiomatic Go interfaces to the distributed transactional key-value store.

Package Information

Import Path:

import "github.com/apple/foundationdb/bindings/go/src/fdb"

Version: 7.4.5

Architecture: The Go binding wraps the FoundationDB C API, providing a type-safe, idiomatic Go interface with error handling, interfaces, and strong typing conventions.

Initialization and Setup

Package-Level Initialization Functions

func APIVersion(version int) error

Select the API version for the client. Must be called before any other FoundationDB operations. Returns error if version is not supported.

func MustAPIVersion(version int)

Select the API version, panicking on error. Convenience wrapper around APIVersion.

func IsAPIVersionSelected() bool

Check whether an API version has been selected.

func GetAPIVersion() (int, error)

Get the currently selected API version.

Example:

// Initialize FoundationDB API
fdb.MustAPIVersion(740)

// Or with error handling
if err := fdb.APIVersion(740); err != nil {
    log.Fatal(err)
}

Database Connection Functions

func OpenDatabase(clusterFile string) (Database, error)

Open a database connection using the specified cluster file path. Empty string uses default cluster file.

func OpenDefault() (Database, error)

Open database connection using the default cluster file.

func OpenWithConnectionString(connectionString string) (Database, error)

Open database connection using an explicit connection string.

Example:

// Open default database
db, err := fdb.OpenDefault()
if err != nil {
    log.Fatal(err)
}

// Or with specific cluster file
db, err := fdb.OpenDatabase("/etc/foundationdb/fdb.cluster")
if err != nil {
    log.Fatal(err)
}

// Or with connection string
db, err := fdb.OpenWithConnectionString("test:test@127.0.0.1:4500")
if err != nil {
    log.Fatal(err)
}

Network Control Functions

func StartNetwork() error

Deprecated: Start the network thread. Network is now started automatically when API version is selected. Returns error if network cannot be started.

func StopNetwork() error

Stop the network thread. Should be called during application shutdown.

Network Options

func Options() NetworkOptions

Get network options for configuring global FoundationDB behavior.

Key Types and Interfaces

Key Type

type Key []byte

Represents a database key as a byte slice. Implements KeyConvertible interface.

Methods:

func (k Key) FDBKey() Key
func (k Key) String() string
  • FDBKey() - Convert to Key (identity function for Key type)
  • String() - Returns human-readable string representation of the key

KeyConvertible Interface

type KeyConvertible interface {
    FDBKey() Key
}

Interface for types that can be converted to database keys. Implemented by Key, subspaces, and tuples.

Selectable Interface

type Selectable interface {
    FDBKeySelector() KeySelector
}

Interface for types that can be converted to key selectors. Implemented by Key and KeySelector.

KeySelector Type

type KeySelector struct {
    Key    KeyConvertible
    OrEqual bool
    Offset  int
}

Represents a key selector for selecting keys relative to a boundary.

Constructor Functions:

func FirstGreaterThan(key KeyConvertible) KeySelector

Create key selector for first key strictly greater than the specified key.

func FirstGreaterOrEqual(key KeyConvertible) KeySelector

Create key selector for first key greater than or equal to the specified key.

func LastLessThan(key KeyConvertible) KeySelector

Create key selector for last key strictly less than the specified key.

func LastLessOrEqual(key KeyConvertible) KeySelector

Create key selector for last key less than or equal to the specified key.

Methods:

func (ks KeySelector) FDBKeySelector() KeySelector

Convert to KeySelector (identity function).

Example:

// Select first key >= "user/"
beginSel := fdb.FirstGreaterOrEqual(fdb.Key("user/"))

// Select first key >= "user0" (last key of "user/" prefix range)
endSel := fdb.FirstGreaterOrEqual(fdb.Key("user0"))

Range Types

Range Interface

type Range interface {
    FDBRangeKeys() (KeyConvertible, KeyConvertible)
    FDBRangeKeySelectors() (Selectable, Selectable)
}

Interface for types representing key ranges.

KeyRange Type

type KeyRange struct {
    Begin KeyConvertible
    End   KeyConvertible
}

Represents a key range with begin (inclusive) and end (exclusive) boundaries. Implements Range interface.

ExactRange Type

type ExactRange struct {
    Begin Key
    End   Key
}

Represents an exact key range with concrete byte slice boundaries. Implements Range interface.

Functions:

func PrefixRange(prefix []byte) (KeyRange, error)

Create range containing all keys with the specified prefix. Returns error if prefix cannot be converted to a range (e.g., if strinc fails).

Example:

// Range with prefix
userRange := fdb.PrefixRange([]byte("user/"))

// Explicit range
customRange := fdb.KeyRange{
    Begin: fdb.Key("a"),
    End:   fdb.Key("z"),
}

Database Type

type Database struct {
    // Internal fields
}

Struct representing a database connection. Implements Transactor and ReadTransactor.

Methods

CreateTransaction: Create a new transaction. Manual transaction management with explicit commit and retry handling.

Transact: Execute a transactional function with automatic retry logic. The function receives a Transaction and returns a result and error. If the transaction encounters a retryable error, it will be automatically retried.

ReadTransact: Execute a read-only transactional function with automatic retry logic. The function receives a ReadTransaction.

Options: Get database options for configuration.

Close: Close the database and clean up resources. Must be called exactly once for each created database. Do not use the database after calling Close().

func (d Database) Close()

LocalityGetBoundaryKeys: Get boundary keys for the specified range, useful for parallel processing. Returns keys representing storage server boundaries.

Example:

// Transactional write with automatic retry
result, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    tr.Set(fdb.Key("mykey"), []byte("myvalue"))
    return nil, nil
})

// Read-only transaction
value, err := db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
    return tr.Get(fdb.Key("mykey")).Get()
})

// Manual transaction
tr, err := db.CreateTransaction()
if err != nil {
    log.Fatal(err)
}
tr.Set(fdb.Key("key"), []byte("value"))
err = tr.Commit().Get()

ReadTransaction Interface

type ReadTransaction interface {
    Get(key KeyConvertible) FutureByteSlice
    GetKey(sel Selectable) FutureKey
    GetRange(r Range, options RangeOptions) RangeResult
    GetReadVersion() FutureInt64
    GetEstimatedRangeSizeBytes(r ExactRange) FutureInt64
    GetRangeSplitPoints(er ExactRange, chunkSize int64) FutureKeyArray
    Snapshot() ReadTransaction
    Options() TransactionOptions
}

Interface for read-only transaction operations.

Read Methods

func Get(key KeyConvertible) FutureByteSlice

Read a single value for the specified key. Returns a future that will resolve to the value bytes or nil if key does not exist.

func GetKey(sel Selectable) FutureKey

Resolve a key selector to an actual key. Returns a future containing the resolved key.

func GetRange(r Range, options RangeOptions) RangeResult

Read a range of key-value pairs. Returns a RangeResult for iteration.

func GetReadVersion() FutureInt64

Get the read version used by this transaction.

func GetEstimatedRangeSizeBytes(r ExactRange) FutureInt64

Estimate the storage size of the specified range in bytes.

func GetRangeSplitPoints(er ExactRange, chunkSize int64) FutureKeyArray

Get suggested split points for parallelizing operations over the range. chunkSize specifies target size in bytes for each chunk.

Snapshot Access

func Snapshot() ReadTransaction

Get a snapshot view of the transaction. Reads through the snapshot do not add read conflict ranges (snapshot isolation instead of serializable isolation).

Options

func Options() TransactionOptions

Get transaction options for configuration.

Example:

db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
    // Simple get
    future := tr.Get(fdb.Key("mykey"))
    value, err := future.Get()
    if err != nil {
        return nil, err
    }

    // Snapshot read (no conflicts)
    snapshot := tr.Snapshot()
    snapshotValue, _ := snapshot.Get(fdb.Key("other")).Get()

    // Range read
    rangeResult := tr.GetRange(fdb.PrefixRange([]byte("prefix/")), fdb.RangeOptions{
        Limit: 100,
    })

    return value, nil
})

Transaction Interface

type Transaction interface {
    ReadTransaction

    // Write operations
    Set(key KeyConvertible, value []byte)
    Clear(key KeyConvertible)
    ClearRange(er ExactRange)

    // Atomic operations
    Add(key KeyConvertible, param []byte)
    BitAnd(key KeyConvertible, param []byte)
    BitOr(key KeyConvertible, param []byte)
    BitXor(key KeyConvertible, param []byte)
    Max(key KeyConvertible, param []byte)
    Min(key KeyConvertible, param []byte)
    SetVersionstampedKey(key KeyConvertible, param []byte)
    SetVersionstampedValue(key KeyConvertible, param []byte)
    CompareAndClear(key KeyConvertible, param []byte)
    ByteMin(key KeyConvertible, param []byte)
    ByteMax(key KeyConvertible, param []byte)

    // Transaction control
    Commit() FutureNil
    OnError(e Error) FutureNil
    Reset()
    Cancel()
    Watch(key KeyConvertible) FutureNil

    // Version operations
    SetReadVersion(version int64)
    GetCommittedVersion() (int64, error)
    GetVersionstamp() FutureKey
    GetApproximateSize() FutureInt64

    // Conflict ranges
    AddReadConflictRange(er ExactRange) error
    AddReadConflictKey(key KeyConvertible) error
    AddWriteConflictRange(er ExactRange) error
    AddWriteConflictKey(key KeyConvertible) error
}

Interface for read-write transactions. Extends ReadTransaction.

Write Methods

func Set(key KeyConvertible, value []byte)

Write a key-value pair. Overwrites existing value if key exists.

func Clear(key KeyConvertible)

Delete a single key.

func ClearRange(er ExactRange)

Delete all keys in the specified range [begin, end).

Example:

db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    // Write
    tr.Set(fdb.Key("user/123"), []byte("John Doe"))

    // Delete
    tr.Clear(fdb.Key("temp/old"))

    // Delete range
    tr.ClearRange(fdb.PrefixRange([]byte("cache/")))

    return nil, nil
})

Atomic Operations

func Add(key KeyConvertible, param []byte)

Atomic addition. Treats key value as little-endian integer and adds param to it.

func BitAnd(key KeyConvertible, param []byte)

Atomic bitwise AND operation.

func BitOr(key KeyConvertible, param []byte)

Atomic bitwise OR operation.

func BitXor(key KeyConvertible, param []byte)

Atomic bitwise XOR operation.

func Max(key KeyConvertible, param []byte)

Atomic maximum. Sets key to max(current_value, param) as little-endian integers.

func Min(key KeyConvertible, param []byte)

Atomic minimum. Sets key to min(current_value, param) as little-endian integers.

func SetVersionstampedKey(key KeyConvertible, param []byte)

Set with versionstamp in key. The key must contain an incomplete versionstamp placeholder that will be filled with the transaction's commit version.

func SetVersionstampedValue(key KeyConvertible, param []byte)

Set with versionstamp in value. The value must contain an incomplete versionstamp placeholder.

func CompareAndClear(key KeyConvertible, param []byte)

Atomic compare and clear. Clears key if current value equals param.

func ByteMin(key KeyConvertible, param []byte)

Atomic byte-wise minimum comparison.

func ByteMax(key KeyConvertible, param []byte)

Atomic byte-wise maximum comparison.

Example:

db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    // Increment counter
    tr.Add(fdb.Key("counter"), []byte{1, 0, 0, 0, 0, 0, 0, 0})

    // Set max value
    tr.Max(fdb.Key("high_score"), encodeInt64(9500))

    // Bitwise operations for flags
    tr.BitOr(fdb.Key("flags"), []byte{0x04})

    return nil, nil
})

Transaction Control

func Commit() FutureNil

Commit the transaction. Returns a future that completes when commit succeeds or fails.

func OnError(e Error) FutureNil

Handle an error with automatic retry logic. Returns a future that completes when the transaction is ready to be retried or when the error is non-retryable.

func Reset()

Reset the transaction to its initial state. All operations are discarded.

func Cancel()

Cancel the transaction. All pending operations are aborted.

func Watch(key KeyConvertible) FutureNil

Watch a key for changes. Returns a future that completes when the key is modified by another transaction.

Example:

// Manual retry loop
tr, _ := db.CreateTransaction()
for {
    tr.Set(fdb.Key("key"), []byte("value"))
    err := tr.Commit().Get()
    if err == nil {
        break
    }

    // Handle error and retry if needed
    err = tr.OnError(err.(fdb.Error)).Get()
    if err != nil {
        return err // Non-retryable error
    }
    // Loop continues to retry
}

// Watch for changes
watchFuture := tr.Watch(fdb.Key("config/version"))
go func() {
    watchFuture.Get() // Blocks until key changes
    log.Println("Config changed!")
}()

Version Operations

func SetReadVersion(version int64)

Set the read version for the transaction. All reads will be at this version.

func GetCommittedVersion() (int64, error)

Get the version at which the transaction was committed. Only valid after successful commit.

func GetVersionstamp() FutureKey

Get the versionstamp for the transaction. Returns a future containing the 10-byte versionstamp. Only valid after commit.

func GetApproximateSize() FutureInt64

Get the approximate transaction size in bytes. Useful for staying under transaction size limits.

Example:

db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    // Read at specific version
    tr.SetReadVersion(12345678)

    // Get transaction size
    sizeFuture := tr.GetApproximateSize()
    size, _ := sizeFuture.Get()
    if size > 9000000 { // Near 10MB limit
        return nil, errors.New("transaction too large")
    }

    return nil, nil
})

Conflict Ranges

func AddReadConflictRange(er ExactRange) error

Manually add a read conflict range for the specified key range.

func AddReadConflictKey(key KeyConvertible) error

Manually add a read conflict for a single key.

func AddWriteConflictRange(er ExactRange) error

Manually add a write conflict range for the specified key range.

func AddWriteConflictKey(key KeyConvertible) error

Manually add a write conflict for a single key.

Example:

db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    // Add conflicts manually for custom logic
    tr.AddReadConflictRange(fdb.PrefixRange([]byte("index/")))
    tr.AddWriteConflictKey(fdb.Key("lock/mylock"))

    return nil, nil
})

Future Types

Future Interface

type Future interface {
    BlockUntilReady()
    IsReady() bool
    Cancel()
}

Base interface for all asynchronous operations.

BlockUntilReady: Block the current goroutine until the future is ready.

IsReady: Check if the future is ready without blocking.

Cancel: Cancel the future operation.

FutureNil

type FutureNil interface {
    Future
    Get() error
    MustGet()
}

Future for operations that return no value (only success/error).

Get: Block and return error if operation failed, nil if succeeded.

MustGet: Block and panic if operation failed.

FutureByteSlice

type FutureByteSlice interface {
    Future
    Get() ([]byte, error)
    MustGet() []byte
}

Future for operations that return a byte slice value.

Get: Block and return the byte slice value and error. Returns nil slice if key does not exist.

MustGet: Block and return the value, panicking on error.

FutureKey

type FutureKey interface {
    Future
    Get() (Key, error)
    MustGet() Key
}

Future for operations that return a key.

Get: Block and return the key and error.

MustGet: Block and return the key, panicking on error.

FutureInt64

type FutureInt64 interface {
    Future
    Get() (int64, error)
    MustGet() int64
}

Future for operations that return an integer value.

Get: Block and return the integer and error.

MustGet: Block and return the integer, panicking on error.

FutureKeyArray

type FutureKeyArray interface {
    Future
    Get() ([]Key, error)
    MustGet() []Key
}

Future for operations that return an array of keys.

Get: Block and return the key slice and error.

MustGet: Block and return the key slice, panicking on error.

Example:

// Using futures
future := tr.Get(fdb.Key("mykey"))

// Check if ready without blocking
if future.IsReady() {
    value, err := future.Get()
    // Use value
}

// Or just block and get
value, err := future.Get()

// Or panic on error
value := future.MustGet()

// Cancel if no longer needed
future.Cancel()

Range Results

RangeResult Interface

type RangeResult interface {
    GetSliceWithError() ([]KeyValue, error)
    GetSliceOrPanic() []KeyValue
    Iterator() *RangeIterator
}

Interface for range query results.

GetSliceWithError: Fetch all results and return as a slice. Blocks until all data is fetched.

GetSliceOrPanic: Fetch all results as a slice, panicking on error.

Iterator: Get an iterator for lazy iteration over results.

RangeIterator

type RangeIterator struct {
    // Internal fields
}

Iterator for lazily fetching range results.

Methods:

func (ri *RangeIterator) Advance() bool

Move to the next key-value pair. Returns false when no more items or on error.

func (ri *RangeIterator) Get() (KeyValue, error)

Get the current key-value pair.

KeyValue Struct

type KeyValue struct {
    Key   Key
    Value []byte
}

Represents a key-value pair from a range read.

Example:

// Get all results as slice
result := tr.GetRange(fdb.PrefixRange([]byte("user/")), fdb.RangeOptions{})
kvs, err := result.GetSliceWithError()
for _, kv := range kvs {
    fmt.Printf("Key: %s, Value: %s\n", kv.Key, kv.Value)
}

// Or use iterator for lazy loading
iter := result.Iterator()
for iter.Advance() {
    kv, err := iter.Get()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Key: %s\n", kv.Key)
}

Range Options

RangeOptions Struct

type RangeOptions struct {
    Limit   int
    Mode    StreamingMode
    Reverse bool
}

Options for configuring range reads.

Limit: Maximum number of key-value pairs to return. 0 means no limit.

Mode: Streaming mode hint for fetch behavior.

Reverse: If true, return results in reverse order.

StreamingMode Type

type StreamingMode int

Hint for how to fetch range data.

Constants:

const (
    StreamingModeWantAll   StreamingMode = -1 // Fetch all data at once
    StreamingModeIterator  StreamingMode = 0  // Balanced for iteration (default)
    StreamingModeExact     StreamingMode = 1  // Fetch exactly limit items
    StreamingModeSmall     StreamingMode = 2  // Hint: small amount of data
    StreamingModeMedium    StreamingMode = 3  // Hint: medium amount of data
    StreamingModeLarge     StreamingMode = 4  // Hint: large amount of data
    StreamingModeSerial    StreamingMode = 5  // Minimize latency
)

Example:

// Basic range read
result := tr.GetRange(fdb.PrefixRange([]byte("items/")), fdb.RangeOptions{
    Limit: 100,
    Reverse: false,
})

// Reverse range with all data
result := tr.GetRange(fdb.KeyRange{
    Begin: fdb.Key("z"),
    End:   fdb.Key("a"),
}, fdb.RangeOptions{
    Reverse: true,
    Mode:    fdb.StreamingModeWantAll,
})

// Small data hint for better performance
result := tr.GetRange(range, fdb.RangeOptions{
    Mode: fdb.StreamingModeSmall,
    Limit: 10,
})

Error Handling

Error Interface

type Error interface {
    error
    Code() int
}

Interface for FoundationDB errors. Extends standard error interface.

Code: Get the numeric error code.

Example:

_, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    // Operations...
    return nil, nil
})

if err != nil {
    if fdbErr, ok := err.(fdb.Error); ok {
        fmt.Printf("FDB Error %d: %v\n", fdbErr.Code(), fdbErr)

        // Check specific error codes
        if fdbErr.Code() == 1007 { // transaction_too_old
            // Handle specific error
        }
    }
}

Transactor Interfaces

Transactor Interface

type Transactor interface {
    Transact(func(Transaction) (interface{}, error)) (interface{}, error)
}

Interface for types that can execute transactional functions with automatic retry. Implemented by Database.

ReadTransactor Interface

type ReadTransactor interface {
    ReadTransact(func(ReadTransaction) (interface{}, error)) (interface{}, error)
}

Interface for types that can execute read-only transactional functions. Implemented by Database.

Example:

// Any Transactor can be used
func updateCounter(tr fdb.Transactor, key fdb.Key) error {
    _, err := tr.Transact(func(tr fdb.Transaction) (interface{}, error) {
        tr.Add(key, []byte{1, 0, 0, 0, 0, 0, 0, 0})
        return nil, nil
    })
    return err
}

// Works with Database
updateCounter(db, fdb.Key("counter"))

Options Interfaces

NetworkOptions Interface

type NetworkOptions interface {
    // Configuration methods for network-level settings
    SetLocalAddress(addr string) error
    SetClusterFile(path string) error
    SetTraceEnable(path string) error
    SetTraceRollSize(size int) error
    SetTraceMaxLogsSize(size int) error
    SetTraceLogGroup(group string) error
    SetTraceFormat(format string) error
    SetKnob(knob string, value string) error
    SetTLSPlugin(plugin string) error
    SetTLSCertPath(path string) error
    SetTLSCertBytes(bytes []byte) error
    SetTLSCAPath(path string) error
    SetTLSCABytes(bytes []byte) error
    SetTLSKeyPath(path string) error
    SetTLSKeyBytes(bytes []byte) error
    SetTLSPassword(password string) error
    SetTLSVerifyPeers(constraint []byte) error
    // ... and more configuration options
}

Interface for configuring network-level options. Get instance via fdb.Options().

DatabaseOptions Interface

type DatabaseOptions interface {
    // Configuration methods for database-level settings
    SetLocationCacheSize(size int) error
    SetMaxWatches(max int) error
    SetDatacenterId(id string) error
    SetMachineId(id string) error
    SetSnapshotRywEnable() error
    SetSnapshotRywDisable() error
    SetTransactionLoggingMaxFieldLength(length int) error
    SetTransactionTimeout(timeout int) error
    SetTransactionMaxRetryDelay(delay int) error
    SetTransactionSizeLimit(limit int) error
    SetTransactionRetryLimit(limit int) error
    SetTransactionCausalReadRisky() error
    // ... and more configuration options
}

Interface for configuring database-level options. Get instance via Database.Options().

TransactionOptions Interface

type TransactionOptions interface {
    // Configuration methods for transaction-level settings
    SetCausalWriteRisky() error
    SetCausalReadRisky() error
    SetReadYourWritesDisable() error
    SetReadAheadDisable() error
    SetDurabilityDatacenter() error
    SetDurabilityRisky() error
    SetDurabilityDevNullIsWebScale() error
    SetPrioritySystemImmediate() error
    SetPriorityBatch() error
    SetInitializeNewDatabase() error
    SetAccessSystemKeys() error
    SetReadSystemKeys() error
    SetTimeout(timeout int) error
    SetRetryLimit(limit int) error
    SetMaxRetryDelay(delay int) error
    SetUsedDuringCommitProtectionDisable() error
    SetDebugTransactionIdentifier(id string) error
    SetLogTransaction() error
    SetTransactionLoggingMaxFieldLength(length int) error
    SetReadLockAware() error
    SetLockAware() error
    SetFirstInBatch() error
    SetReportConflictingKeys() error
    SetExpensiveClearCostEstimationEnable() error
    SetBypassUnreadable() error
    SetRawAccess() error
    // ... and more configuration options
}

Interface for configuring transaction-level options. Get instance via Transaction.Options() or ReadTransaction.Options().

Example:

// Network options
fdb.Options().SetTraceEnable("/var/log/fdb-trace")
fdb.Options().SetKnob("min_trace_severity", "10")

// Database options
db.Options().SetTransactionTimeout(5000) // 5 second timeout
db.Options().SetTransactionRetryLimit(100)
db.Options().SetLocationCacheSize(100001)

// Transaction options
db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    tr.Options().SetPriorityBatch() // Low priority
    tr.Options().SetTimeout(3000)    // 3 second timeout

    // Operations...
    return nil, nil
})

// Snapshot read (via options, alternative to Snapshot() method)
db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
    tr.Options().SetReadYourWritesDisable()
    // Now reads won't conflict
    return nil, nil
})

Tuple Package

Import: github.com/apple/foundationdb/bindings/go/src/fdb/tuple

The tuple package provides ordered encoding of structured keys.

Tuple Type

type Tuple []TupleElement

A tuple is a slice of tuple elements that can be encoded to/from bytes.

type TupleElement interface{}

Elements can be: nil, []byte, string, int64, uint64, int, float32, float64, bool, UUID, Versionstamp, or nested Tuple.

Methods

func (t Tuple) Pack() []byte

Encode the tuple to bytes. Preserves lexicographic ordering.

func (t Tuple) PackWithVersionstamp(prefix []byte) ([]byte, error)

Pack tuple containing an incomplete versionstamp. Returns packed bytes with placeholder for versionstamp.

Note: The Go Tuple type does not have an Append method. To concatenate tuples, use standard slice append:

t1 := tuple.Tuple{"a", 1}
t2 := tuple.Tuple{"b", 2}
combined := append(t1, t2...)

Functions

func Unpack(b []byte) (Tuple, error)

Decode bytes to a tuple.

Special Types

type Versionstamp struct {
    TransactionVersion [10]byte
    UserVersion        uint16
}

Represents a versionstamp value. Can be incomplete (for use before commit) or complete (after commit).

Note: The Versionstamp type does not have an IsIncomplete method in the Go binding. To check if a versionstamp is incomplete, compare the transaction version bytes to the incomplete placeholder (10 bytes of 0xFF).

type UUID [16]byte

Represents a UUID value in tuples.

Example:

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

// Create tuple keys
userKey := tuple.Tuple{"users", 12345, "profile"}.Pack()
indexKey := tuple.Tuple{"index", "email", "john@example.com", 12345}.Pack()

db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    tr.Set(fdb.Key(userKey), []byte("John Doe"))
    tr.Set(fdb.Key(indexKey), []byte(""))
    return nil, nil
})

// Unpack keys
t, err := tuple.Unpack(userKey)
// t == Tuple{"users", 12345, "profile"}

// Versionstamp keys
vsKey := tuple.Tuple{"log", tuple.Versionstamp{}}.PackWithVersionstamp(nil)

Subspace Package

Import: github.com/apple/foundationdb/bindings/go/src/fdb/subspace

The subspace package provides key prefixing for logical namespaces.

Subspace Interface

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

    // Implements KeyConvertible and Range
    FDBKey() fdb.Key
    FDBRangeKeys() (fdb.KeyConvertible, fdb.KeyConvertible)
    FDBRangeKeySelectors() (fdb.Selectable, fdb.Selectable)
}

Interface for key prefixing and namespacing.

Functions

func FromBytes(b []byte) Subspace

Create a subspace from a raw byte prefix.

func Sub(el ...tuple.TupleElement) Subspace

Create a subspace from tuple elements.

Methods

func Sub(el ...tuple.TupleElement) Subspace

Create a nested subspace by appending tuple elements.

func Bytes() []byte

Get the raw prefix bytes.

func Pack(t tuple.Tuple) fdb.Key

Pack a tuple with the subspace prefix.

func Unpack(k fdb.KeyConvertible) (tuple.Tuple, error)

Unpack a key, removing the subspace prefix and returning the tuple.

func Contains(k fdb.KeyConvertible) bool

Check if a key belongs to this subspace.

Example:

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

// Create subspaces
users := subspace.Sub("users")
profiles := users.Sub("profiles")
emails := users.Sub("emails")

db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    // Pack keys with subspace prefix
    profileKey := profiles.Pack(tuple.Tuple{12345})
    emailKey := emails.Pack(tuple.Tuple{"john@example.com"})

    tr.Set(profileKey, []byte("John Doe"))
    tr.Set(emailKey, []byte("12345"))

    // Range read within subspace
    result := tr.GetRange(profiles, fdb.RangeOptions{})

    return nil, nil
})

// Check containment
if profiles.Contains(someKey) {
    // Key belongs to profiles subspace
}

// Unpack
t, err := profiles.Unpack(profileKey)
// t == tuple.Tuple{12345}

Directory Package

Import: github.com/apple/foundationdb/bindings/go/src/fdb/directory

The directory package provides dynamic prefix allocation and hierarchical namespacing.

DirectoryLayer Struct

type DirectoryLayer struct {
    // Internal fields
}

Manages a directory hierarchy for dynamic prefix allocation.

Functions

func NewDirectoryLayer(nodeSubspace, contentSubspace subspace.Subspace, allowManualPrefixes bool) DirectoryLayer

Create a new directory layer with custom configuration.

func Root() Directory

Get the root directory using the default directory layer.

Directory Interface

type Directory interface {
    subspace.Subspace

    CreateOrOpen(tr fdb.Transactor, path []string, layer []byte) (DirectorySubspace, error)
    Create(tr fdb.Transactor, path []string, layer []byte) (DirectorySubspace, error)
    Open(tr fdb.ReadTransactor, path []string, layer []byte) (DirectorySubspace, error)
    Exists(tr fdb.ReadTransactor, path []string) (bool, error)
    List(tr fdb.ReadTransactor, path []string) ([]string, error)
    Move(tr fdb.Transactor, oldPath []string, newPath []string) (DirectorySubspace, error)
    Remove(tr fdb.Transactor, path []string) (bool, error)
}

Interface for directory operations. Extends subspace.Subspace.

Methods

func CreateOrOpen(tr fdb.Transactor, path []string, layer []byte) (DirectorySubspace, error)

Create directory if it doesn't exist, or open if it does. Returns a DirectorySubspace.

func Create(tr fdb.Transactor, path []string, layer []byte) (DirectorySubspace, error)

Create a new directory. Returns error if it already exists.

func Open(tr fdb.ReadTransactor, path []string, layer []byte) (DirectorySubspace, error)

Open an existing directory. Returns error if it doesn't exist.

func Exists(tr fdb.ReadTransactor, path []string) (bool, error)

Check if a directory exists.

func List(tr fdb.ReadTransactor, path []string) ([]string, error)

List immediate subdirectories at the specified path.

func Move(tr fdb.Transactor, oldPath []string, newPath []string) (DirectorySubspace, error)

Move a directory to a new location in the hierarchy.

func Remove(tr fdb.Transactor, path []string) (bool, error)

Remove a directory and all its contents. Returns false if directory doesn't exist.

DirectorySubspace Interface

type DirectorySubspace interface {
    Directory
    subspace.Subspace

    GetLayer() []byte
    GetPath() []string
}

A directory that is also a subspace. Combines directory operations with key prefixing.

func GetLayer() []byte

Get the layer bytes for this directory.

func GetPath() []string

Get the full path to this directory.

Example:

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

// Create directory structure
appDir, err := directory.Root().CreateOrOpen(db, []string{"myapp"}, nil)
usersDir, err := appDir.CreateOrOpen(db, []string{"users"}, nil)

db.Transact(func(tr fdb.Transaction) (interface{}, error) {
    // Use directory as subspace
    userKey := usersDir.Pack(tuple.Tuple{12345})
    tr.Set(userKey, []byte("John Doe"))

    // List subdirectories
    subdirs, err := appDir.List(tr, []string{})
    // subdirs == []string{"users"}

    return nil, nil
})

// Check if directory exists
exists, err := directory.Root().Exists(db, []string{"myapp", "users"})

// Move directory
newDir, err := directory.Root().Move(db,
    []string{"myapp", "users"},
    []string{"myapp", "accounts"})

// Remove directory
removed, err := directory.Root().Remove(db, []string{"myapp", "temp"})

// Get directory metadata
path := usersDir.GetPath()      // []string{"myapp", "users"}
layer := usersDir.GetLayer()     // nil or layer bytes
prefix := usersDir.Bytes()       // Allocated prefix bytes

Complete Usage Example

package main

import (
    "fmt"
    "log"

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

func main() {
    // Initialize API
    fdb.MustAPIVersion(740)

    // Open database
    db, err := fdb.OpenDefault()
    if err != nil {
        log.Fatal(err)
    }

    // Set up directory structure
    appDir, err := directory.Root().CreateOrOpen(db, []string{"myapp"}, nil)
    if err != nil {
        log.Fatal(err)
    }

    // Write data with automatic retry
    result, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
        // Create structured keys with tuples
        userKey := appDir.Pack(tuple.Tuple{"users", 12345})
        emailKey := appDir.Pack(tuple.Tuple{"emails", "john@example.com"})
        counterKey := appDir.Pack(tuple.Tuple{"counters", "users"})

        // Write data
        tr.Set(userKey, []byte("John Doe"))
        tr.Set(emailKey, []byte("12345"))

        // Atomic increment
        tr.Add(counterKey, []byte{1, 0, 0, 0, 0, 0, 0, 0})

        // Read data within same transaction
        future := tr.Get(userKey)
        value, err := future.Get()
        if err != nil {
            return nil, err
        }

        return value, nil
    })

    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Result: %s\n", result)

    // Read-only transaction
    count, err := db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
        // Range read
        rangeKey := appDir.Pack(tuple.Tuple{"users"})
        rangeResult := tr.GetRange(fdb.PrefixRange(rangeKey), fdb.RangeOptions{
            Limit: 100,
        })

        // Iterate results
        iter := rangeResult.Iterator()
        var users []string
        for iter.Advance() {
            kv, err := iter.Get()
            if err != nil {
                return nil, err
            }

            // Unpack key
            t, err := appDir.Unpack(kv.Key)
            if err != nil {
                return nil, err
            }

            users = append(users, fmt.Sprintf("%v: %s", t, kv.Value))
        }

        return len(users), nil
    })

    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d users\n", count)
}

Best Practices

  1. Always use automatic retry: Prefer Transact() and ReadTransact() over manual transaction management.

  2. Use structured keys: Leverage tuple encoding and subspaces for maintainable key schemas.

  3. Use directories for dynamic prefixes: Directories provide automatic prefix allocation and prevent conflicts.

  4. Handle errors properly: Check for fdb.Error and examine error codes for specific handling.

  5. Use snapshot reads when appropriate: Snapshot reads avoid conflicts for read-heavy workloads.

  6. Monitor transaction size: Use GetApproximateSize() to stay under the 10MB transaction limit.

  7. Set appropriate timeouts: Configure transaction timeouts based on your latency requirements.

  8. Use atomic operations: Prefer atomic operations like Add() over read-modify-write patterns.

  9. Batch operations: Group multiple operations in a single transaction for atomicity and performance.

  10. Use range reads efficiently: Choose appropriate StreamingMode based on expected data size.

Related Documentation

  • FoundationDB Documentation
  • Go API Examples
  • Error Codes
  • Developer Guide