Complete reference for the FoundationDB Go client library, providing idiomatic Go interfaces to the distributed transactional key-value store.
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.
func APIVersion(version int) errorSelect 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() boolCheck 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)
}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)
}func StartNetwork() errorDeprecated: Start the network thread. Network is now started automatically when API version is selected. Returns error if network cannot be started.
func StopNetwork() errorStop the network thread. Should be called during application shutdown.
func Options() NetworkOptionsGet network options for configuring global FoundationDB behavior.
type Key []byteRepresents a database key as a byte slice. Implements KeyConvertible interface.
Methods:
func (k Key) FDBKey() Key
func (k Key) String() stringFDBKey() - Convert to Key (identity function for Key type)String() - Returns human-readable string representation of the keytype KeyConvertible interface {
FDBKey() Key
}Interface for types that can be converted to database keys. Implemented by Key, subspaces, and tuples.
type Selectable interface {
FDBKeySelector() KeySelector
}Interface for types that can be converted to key selectors. Implemented by Key and KeySelector.
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) KeySelectorCreate key selector for first key strictly greater than the specified key.
func FirstGreaterOrEqual(key KeyConvertible) KeySelectorCreate key selector for first key greater than or equal to the specified key.
func LastLessThan(key KeyConvertible) KeySelectorCreate key selector for last key strictly less than the specified key.
func LastLessOrEqual(key KeyConvertible) KeySelectorCreate key selector for last key less than or equal to the specified key.
Methods:
func (ks KeySelector) FDBKeySelector() KeySelectorConvert 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"))type Range interface {
FDBRangeKeys() (KeyConvertible, KeyConvertible)
FDBRangeKeySelectors() (Selectable, Selectable)
}Interface for types representing key ranges.
type KeyRange struct {
Begin KeyConvertible
End KeyConvertible
}Represents a key range with begin (inclusive) and end (exclusive) boundaries. Implements Range interface.
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"),
}type Database struct {
// Internal fields
}Struct representing a database connection. Implements Transactor and ReadTransactor.
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()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.
func Get(key KeyConvertible) FutureByteSliceRead 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) FutureKeyResolve a key selector to an actual key. Returns a future containing the resolved key.
func GetRange(r Range, options RangeOptions) RangeResultRead a range of key-value pairs. Returns a RangeResult for iteration.
func GetReadVersion() FutureInt64Get the read version used by this transaction.
func GetEstimatedRangeSizeBytes(r ExactRange) FutureInt64Estimate the storage size of the specified range in bytes.
func GetRangeSplitPoints(er ExactRange, chunkSize int64) FutureKeyArrayGet suggested split points for parallelizing operations over the range. chunkSize specifies target size in bytes for each chunk.
func Snapshot() ReadTransactionGet a snapshot view of the transaction. Reads through the snapshot do not add read conflict ranges (snapshot isolation instead of serializable isolation).
func Options() TransactionOptionsGet 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
})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.
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
})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
})func Commit() FutureNilCommit the transaction. Returns a future that completes when commit succeeds or fails.
func OnError(e Error) FutureNilHandle 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) FutureNilWatch 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!")
}()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() FutureKeyGet the versionstamp for the transaction. Returns a future containing the 10-byte versionstamp. Only valid after commit.
func GetApproximateSize() FutureInt64Get 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
})func AddReadConflictRange(er ExactRange) errorManually add a read conflict range for the specified key range.
func AddReadConflictKey(key KeyConvertible) errorManually add a read conflict for a single key.
func AddWriteConflictRange(er ExactRange) errorManually add a write conflict range for the specified key range.
func AddWriteConflictKey(key KeyConvertible) errorManually 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
})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.
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.
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.
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.
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.
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()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.
type RangeIterator struct {
// Internal fields
}Iterator for lazily fetching range results.
Methods:
func (ri *RangeIterator) Advance() boolMove 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.
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)
}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.
type StreamingMode intHint 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,
})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
}
}
}type Transactor interface {
Transact(func(Transaction) (interface{}, error)) (interface{}, error)
}Interface for types that can execute transactional functions with automatic retry. Implemented by Database.
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"))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().
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().
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
})Import: github.com/apple/foundationdb/bindings/go/src/fdb/tuple
The tuple package provides ordered encoding of structured keys.
type Tuple []TupleElementA 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.
func (t Tuple) Pack() []byteEncode 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...)func Unpack(b []byte) (Tuple, error)Decode bytes to a tuple.
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]byteRepresents 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)Import: github.com/apple/foundationdb/bindings/go/src/fdb/subspace
The subspace package provides key prefixing for logical namespaces.
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.
func FromBytes(b []byte) SubspaceCreate a subspace from a raw byte prefix.
func Sub(el ...tuple.TupleElement) SubspaceCreate a subspace from tuple elements.
func Sub(el ...tuple.TupleElement) SubspaceCreate a nested subspace by appending tuple elements.
func Bytes() []byteGet the raw prefix bytes.
func Pack(t tuple.Tuple) fdb.KeyPack 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) boolCheck 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}Import: github.com/apple/foundationdb/bindings/go/src/fdb/directory
The directory package provides dynamic prefix allocation and hierarchical namespacing.
type DirectoryLayer struct {
// Internal fields
}Manages a directory hierarchy for dynamic prefix allocation.
func NewDirectoryLayer(nodeSubspace, contentSubspace subspace.Subspace, allowManualPrefixes bool) DirectoryLayerCreate a new directory layer with custom configuration.
func Root() DirectoryGet the root directory using the default directory layer.
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.
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.
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() []byteGet the layer bytes for this directory.
func GetPath() []stringGet 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 bytespackage 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)
}Always use automatic retry: Prefer Transact() and ReadTransact() over manual transaction management.
Use structured keys: Leverage tuple encoding and subspaces for maintainable key schemas.
Use directories for dynamic prefixes: Directories provide automatic prefix allocation and prevent conflicts.
Handle errors properly: Check for fdb.Error and examine error codes for specific handling.
Use snapshot reads when appropriate: Snapshot reads avoid conflicts for read-heavy workloads.
Monitor transaction size: Use GetApproximateSize() to stay under the 10MB transaction limit.
Set appropriate timeouts: Configure transaction timeouts based on your latency requirements.
Use atomic operations: Prefer atomic operations like Add() over read-modify-write patterns.
Batch operations: Group multiple operations in a single transaction for atomicity and performance.
Use range reads efficiently: Choose appropriate StreamingMode based on expected data size.