Documentation
¶
Index ¶
- Constants
- Variables
- func AbsolutizeFieldTypeNames(fd *descriptorpb.FileDescriptorProto)
- func AsList[T any](ctx context.Context, cursor RecordCursor[T]) ([]T, error)
- func AsListWithContinuation[T any](ctx context.Context, cursor RecordCursor[T]) ([]T, []byte, error)
- func BuildSPFreshIndex(ctx context.Context, db *FDBDatabase, ...) error
- func CheckValidProtoBufCompliantName(name string) error
- func CleanupAllHeartbeats(tx fdb.WritableTransaction, storeSubspace subspace.Subspace, index *Index)
- func ClearStatistics(ctx context.Context, db *FDBDatabase, stats StatisticsSubspace, ...) error
- func DecodeOnceIfReversible(stored string) string
- func DeleteStore(ctx *FDBRecordContext, ss subspace.Subspace) error
- func Filter[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T]
- func Filter2[T any](seq iter.Seq2[T, error], predicate func(T) bool) iter.Seq2[T, error]
- func FindRegisteredMessageType(fullName protoreflect.FullName) protoreflect.MessageType
- func First[T any](ctx context.Context, cursor RecordCursor[T]) (*T, error)
- func ForEach[T any](ctx context.Context, cursor RecordCursor[T], fn func(T) error) error
- func GetCount[T any](ctx context.Context, cursor RecordCursor[T]) (int, error)
- func GroupCountCompanionName(ownerIndexName string) string
- func GroupingSignature(g *GroupingKeyExpression) []byte
- func IsGroupCountCompanionFor(idx *Index, groupingSignature, predicateSignature []byte, ...) bool
- func IsPermutedMinIndex(idx *Index) bool
- func IsRecordTypeExpression(expr KeyExpression) bool
- func KeyExpressionHasRecordTypePrefix(expr KeyExpression) bool
- func Limit[T any](seq iter.Seq[T], n int) iter.Seq[T]
- func LiteralToProtoValue(v any) (*gen.Value, error)
- func LoadIndexStates(tx fdb.ReadTransaction, ss subspace.Subspace) (map[string]IndexState, error)
- func MBRToTuple(m MBR) tuple.Tuple
- func Map[T, R any](seq iter.Seq[T], fn func(T) R) iter.Seq[R]
- func NeedsGroupCountCompanion(idx *Index) bool
- func NewHNSWGraph(storage *hnswStorage, config HNSWConfig) *hnswGraph
- func PermutedMinIgnoringNulls(ctx context.Context, scan OrdinaryIndexScanFunc, indexName string, ...) (tuple.Tuple, error)
- func PredicateSignature(idx *Index) []byte
- func ReadHeartbeats(tx fdb.ReadTransaction, storeSubspace subspace.Subspace, index *Index) ([]*gen.IndexBuildHeartbeat, []string, error)
- func ReadStatisticsAtWithRefusal(ctx context.Context, db *FDBDatabase, stats StatisticsSubspace, ...) (StoreStatistics, StatisticsReadRefusal, int64, error)
- func RebalanceSPFreshIndex(ctx context.Context, db *FDBDatabase, ...) (int, error)
- func Reduce[T any, R any](ctx context.Context, cursor RecordCursor[T], initial R, fn func(R, T) R) (R, error)
- func RefineSPFreshIndex(ctx context.Context, db *FDBDatabase, ...) (int, bool, error)
- func RefineSPFreshIndexAll(ctx context.Context, db *FDBDatabase, ...) (int, error)
- func RegisterFunction(name string, evaluator FunctionEvaluator)
- func RunSPFreshMaintenance(ctx context.Context, db *FDBDatabase, opts SPFreshMaintenanceOptions) error
- func SPFreshAuditTrail(fineID int64) []string
- func SPFreshDebugIntegrity(rtx *FDBRecordContext, store *FDBRecordStore, indexName string, sample int) string
- func SPFreshDebugTopology(rtx *FDBRecordContext, store *FDBRecordStore, indexName string) string
- func SPFreshDisableAudit()
- func SPFreshEnableAudit()
- func SPFreshHasPendingMaintenance(ctx context.Context, db *FDBDatabase, ...) (bool, error)
- func SafeDecoderOver(decoded, verbatim []string) func(string) string
- func SamePredicateSignature(a, b []byte) bool
- func Seq2[T any](cursor RecordCursor[T], ctx context.Context) iter.Seq2[T, error]
- func SerializeVector(vec []float64) []byte
- func ToProtoBufCompliantName(name string) (string, error)
- func ToUserIdentifier(protoIdentifier string) string
- func TranslatePrimaryKeyToValues(pk KeyExpression, normalizeName func(string) string, flowedType values.Type) []values.Value
- func ValidateEvolution(oldMetaData, newMetaData *RecordMetaData) error
- func ValidateHNSWConfig(c HNSWConfig) error
- func ValidateRTreeConfig(config RTreeConfig) error
- func ValidateSPFreshConfig(c SPFreshConfig) error
- func ValidateTags(tags []string) ([]string, error)
- func ValidateTokenizerVersion(t TextTokenizer, version int) error
- func WriteRecordMetaData(meta *RecordMetaData, w io.Writer) error
- type AggregateFunctionNotSupportedError
- type BackendCapabilityError
- type BunchedEntry
- type BunchedMap
- func (m *BunchedMap) Compact(tx fdb.WritableTransaction, ss subspace.Subspace, keyLimit int, ...) ([]byte, error)
- func (m *BunchedMap) ContainsKey(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple) (bool, error)
- func (m *BunchedMap) Get(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple) ([]int, bool, error)
- func (m *BunchedMap) Put(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple, value []int) ([]int, bool, error)
- func (m *BunchedMap) Remove(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple) ([]int, bool, error)
- func (m *BunchedMap) Scan(tx fdb.ReadTransaction, ss subspace.Subspace, continuation []byte, limit int, ...) *BunchedMapIterator
- func (m *BunchedMap) VerifyIntegrity(tx fdb.ReadTransaction, ss subspace.Subspace) error
- type BunchedMapException
- type BunchedMapIterator
- type BunchedMapMultiIterator
- type BunchedMapScanEntry
- type BunchedSerializationError
- type BunchedSerializer
- type BytesContinuation
- type CardinalityFunctionKeyExpression
- type ChildSlot
- type CollectOptions
- type CollectionReport
- type CommitCheckFunc
- type ComparisonKeyFunc
- type CompositeKeyExpression
- func (c *CompositeKeyExpression) ColumnSize() int
- func (c *CompositeKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (c *CompositeKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
- func (c *CompositeKeyExpression) FieldNames() []string
- func (c *CompositeKeyExpression) PackDirect(pk *tuple.Packer, record *FDBStoredRecord[proto.Message], msg proto.Message) bool
- func (c *CompositeKeyExpression) SubKeyExpressions() []KeyExpression
- func (c *CompositeKeyExpression) ToKeyExpression() *gen.KeyExpression
- type ContinuationParseError
- type Counter
- type CounterSnapshot
- type CursorFactory
- type CursorStreamingMode
- type DefaultTextTokenizer
- func (t *DefaultTextTokenizer) MaxVersion() int
- func (t *DefaultTextTokenizer) MinVersion() int
- func (t *DefaultTextTokenizer) Name() string
- func (t *DefaultTextTokenizer) Tokenize(text string, version int, mode TokenizerMode) (TokenIterator, error)
- func (t *DefaultTextTokenizer) TokenizeToList(text string, version int, mode TokenizerMode) ([]string, error)
- func (t *DefaultTextTokenizer) TokenizeToMap(text string, version int, mode TokenizerMode) (map[string][]int, error)
- type DefaultTextTokenizerFactory
- type DimensionsKeyExpression
- func (d *DimensionsKeyExpression) ColumnSize() int
- func (d *DimensionsKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (d *DimensionsKeyExpression) FieldNames() []string
- func (d *DimensionsKeyExpression) SplitIndexEntry(entry tuple.Tuple) (prefix, dims, suffix tuple.Tuple)
- func (d *DimensionsKeyExpression) SuffixSize() int
- func (d *DimensionsKeyExpression) ToKeyExpression() *gen.KeyExpression
- type DirectPacker
- type EmptyKeyExpression
- func (e *EmptyKeyExpression) ColumnSize() int
- func (e *EmptyKeyExpression) Evaluate(_ *FDBStoredRecord[proto.Message], _ proto.Message) ([][]any, error)
- func (e *EmptyKeyExpression) EvaluateFlat(_ *FDBStoredRecord[proto.Message], _ proto.Message) ([]any, error)
- func (e *EmptyKeyExpression) FieldNames() []string
- func (e *EmptyKeyExpression) ToKeyExpression() *gen.KeyExpression
- type EndContinuation
- type EndpointType
- type Event
- type ExecuteProperties
- func (e ExecuteProperties) ClearRowAndTimeLimits() ExecuteProperties
- func (e ExecuteProperties) ClearSkipAndLimit() ExecuteProperties
- func (e ExecuteProperties) GetMaterializationLimit() int
- func (e ExecuteProperties) WithDryRun(dryRun bool) ExecuteProperties
- func (e ExecuteProperties) WithIsolationLevel(level IsolationLevel) ExecuteProperties
- func (e ExecuteProperties) WithMaterializationLimit(limit int) ExecuteProperties
- func (e ExecuteProperties) WithReturnedRowLimit(limit int) ExecuteProperties
- func (e ExecuteProperties) WithScannedBytesLimit(limit int64) ExecuteProperties
- func (e ExecuteProperties) WithScannedRecordsLimit(limit int) ExecuteProperties
- func (e ExecuteProperties) WithSkip(skip int) ExecuteProperties
- func (e ExecuteProperties) WithTimeLimit(limit time.Duration) ExecuteProperties
- type ExecuteState
- func (s *ExecuteState) ChargeMemory(n int64) error
- func (s *ExecuteState) HasMemLimit() bool
- func (s *ExecuteState) IncrementRecursionLevel(id any) int
- func (s *ExecuteState) MemLimit() int64
- func (s *ExecuteState) MemUsed() int64
- func (s *ExecuteState) ReleaseMemory(n int64)
- func (s *ExecuteState) ResetRecursionLevel(id any)
- func (s *ExecuteState) RestoreRecursionLevels(snapshot map[any]int)
- func (s *ExecuteState) SnapshotRecursionLevels() map[any]int
- type FDBDatabase
- func (d *FDBDatabase) CreateTransaction() (fdb.Transaction, error)
- func (d *FDBDatabase) CreateWritableTransaction() (fdb.WritableTransaction, error)
- func (d *FDBDatabase) Env() *dst.Env
- func (d *FDBDatabase) GetStoreStateCache() FDBRecordStoreStateCache
- func (d *FDBDatabase) LocalityGetBoundaryKeys(r fdb.ExactRange, limit int, readVersion int64) ([]fdb.Key, error)
- func (d *FDBDatabase) NewRecordContext(tx fdb.WritableTransaction) *FDBRecordContext
- func (d *FDBDatabase) Run(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, error)
- func (d *FDBDatabase) RunRead(ctx context.Context, fn func(rtx fdb.ReadTransaction) (any, error)) (any, error)
- func (d *FDBDatabase) RunWithVersionstamp(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, []byte, error)
- func (d *FDBDatabase) RunWithWeakReads(ctx context.Context, weak WeakReadSemantics, ...) (any, error)
- func (d *FDBDatabase) SetEnv(env *dst.Env) *FDBDatabase
- func (d *FDBDatabase) SetStoreStateCache(cache FDBRecordStoreStateCache)
- func (d *FDBDatabase) SetTimer(timer *StoreTimer)
- func (d *FDBDatabase) Timer() *StoreTimer
- type FDBDatabaseFactory
- type FDBDatabaseRunner
- func (r *FDBDatabaseRunner) OpenContext(ctx context.Context) (*FDBRecordContext, error)
- func (r *FDBDatabaseRunner) RunWithRetry(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, error)
- func (r *FDBDatabaseRunner) SetContextConfig(config *RecordContextConfig) *FDBDatabaseRunner
- func (r *FDBDatabaseRunner) SetInitialDelay(d time.Duration) *FDBDatabaseRunner
- func (r *FDBDatabaseRunner) SetMaxAttempts(n int) *FDBDatabaseRunner
- func (r *FDBDatabaseRunner) SetMaxDelay(d time.Duration) *FDBDatabaseRunner
- type FDBIndexedRecord
- type FDBMetaDataStore
- func (s *FDBMetaDataStore) LoadRecordMetaDataProto(tx fdb.WritableTransaction) (*gen.MetaData, error)
- func (s *FDBMetaDataStore) LoadRecordMetaDataProtoAtVersion(tx fdb.WritableTransaction, version int32) (*gen.MetaData, error)
- func (s *FDBMetaDataStore) SaveRecordMetaData(tx fdb.WritableTransaction, metaDataProto *gen.MetaData) error
- func (s *FDBMetaDataStore) SetEvolutionValidator(v *MetaDataEvolutionValidator)
- func (s *FDBMetaDataStore) Subspace() subspace.Subspace
- type FDBRecordContext
- func (rc *FDBRecordContext) AddCommitCheck(check CommitCheckFunc)
- func (rc *FDBRecordContext) AddPostCommit(hook PostCommitFunc)
- func (rc *FDBRecordContext) AddReadConflictRange(r fdb.ExactRange) error
- func (rc *FDBRecordContext) AddToLocalVersionCache(versionKey []byte, localVersion int)
- func (rc *FDBRecordContext) AddVersionMutation(mutationType VersionMutationType, versionKey []byte, value []byte)
- func (rc *FDBRecordContext) Cancel()
- func (rc *FDBRecordContext) CheckTransactionSize() error
- func (rc *FDBRecordContext) ClaimLocalVersion() int
- func (rc *FDBRecordContext) Commit() error
- func (rc *FDBRecordContext) CommitWithHooks() error
- func (rc *FDBRecordContext) CommitWithVersionstamp() ([]byte, error)
- func (rc *FDBRecordContext) Context() context.Context
- func (rc *FDBRecordContext) Env() *dst.Env
- func (rc *FDBRecordContext) GetApproximateTransactionSize() (int64, error)
- func (rc *FDBRecordContext) GetConflictingKeys() []fdb.KeyRange
- func (rc *FDBRecordContext) GetLocalVersion(versionKey []byte) (int, bool)
- func (rc *FDBRecordContext) GetMetaDataVersionStamp() ([]byte, error)
- func (rc *FDBRecordContext) GetReadVersion() (int64, error)
- func (rc *FDBRecordContext) HasDirtyStoreState() bool
- func (rc *FDBRecordContext) HasVersionMutations() bool
- func (rc *FDBRecordContext) PutSession(key string, value any)
- func (rc *FDBRecordContext) ReadTransaction(snapshot bool) fdb.ReadTransaction
- func (rc *FDBRecordContext) RemoveLocalVersion(versionKey []byte)
- func (rc *FDBRecordContext) RemoveLocalVersionsInRange(begin, end fdb.Key)
- func (rc *FDBRecordContext) RemoveVersionMutation(versionKey []byte)
- func (rc *FDBRecordContext) RemoveVersionMutationsInRange(begin, end fdb.Key)
- func (rc *FDBRecordContext) Session(key string) any
- func (rc *FDBRecordContext) SetDirtyStoreState(dirty bool)
- func (rc *FDBRecordContext) SetMetaDataVersionStamp()
- func (rc *FDBRecordContext) SetReadVersion(version int64)
- func (rc *FDBRecordContext) SetTimer(timer *StoreTimer)
- func (rc *FDBRecordContext) SetTransactionPriority(priority TransactionPriority) error
- func (rc *FDBRecordContext) Timer() *StoreTimer
- func (rc *FDBRecordContext) Transaction() fdb.WritableTransaction
- func (rc *FDBRecordContext) TransactionID() int64
- func (rc *FDBRecordContext) UpdateVersionMutation(mutationType VersionMutationType, versionKey []byte, value []byte, ...)
- type FDBRecordStore
- func (store *FDBRecordStore) AcquireReadLock(key string)
- func (store *FDBRecordStore) AcquireWriteLock(key string)
- func (store *FDBRecordStore) AddBuildProgress(index *Index, count int64)
- func (store *FDBRecordStore) AddRecordReadConflict(primaryKey tuple.Tuple) error
- func (store *FDBRecordStore) AddRecordWriteConflict(primaryKey tuple.Tuple) error
- func (store *FDBRecordStore) AddUniquenessViolation(index *Index, indexKey tuple.Tuple, primaryKey tuple.Tuple) error
- func (store *FDBRecordStore) AddUniquenessViolationWithExisting(index *Index, indexKey tuple.Tuple, primaryKey tuple.Tuple, ...) error
- func (store *FDBRecordStore) AsBuilder() *StoreBuilder
- func (store *FDBRecordStore) ClearAndMarkIndexWriteOnly(indexName string) (bool, error)
- func (store *FDBRecordStore) ClearHeaderUserField(key string) error
- func (store *FDBRecordStore) ClearStoreLockState() error
- func (store *FDBRecordStore) Context() *FDBRecordContext
- func (store *FDBRecordStore) CopyBuilder(newContext *FDBRecordContext) *StoreBuilder
- func (store *FDBRecordStore) CountRecords(ctx context.Context, low, high tuple.Tuple, ...) (int, error)
- func (store *FDBRecordStore) DeleteAllRecords() error
- func (store *FDBRecordStore) DeleteIndexEntries(index *Index)
- func (store *FDBRecordStore) DeleteIndexEntriesInRange(index *Index, prefix tuple.Tuple) error
- func (store *FDBRecordStore) DeleteRecord(primaryKey tuple.Tuple) (bool, error)
- func (store *FDBRecordStore) DeleteRecordsWhere(prefix tuple.Tuple) error
- func (store *FDBRecordStore) DryRunDeleteRecord(primaryKey tuple.Tuple) (bool, error)
- func (store *FDBRecordStore) DryRunSaveRecord(record proto.Message, existenceCheck RecordExistenceCheck) (*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) Env() *dst.Env
- func (store *FDBRecordStore) EstimateIndexSize(index *Index) (int64, error)
- func (store *FDBRecordStore) EstimateRecordsSize() (int64, error)
- func (store *FDBRecordStore) EstimateRecordsSizeInRange(tupleRange TupleRange) (int64, error)
- func (store *FDBRecordStore) EstimateStoreSize() (int64, error)
- func (store *FDBRecordStore) EvaluateAggregateFunction(ctx context.Context, recordTypeNames []string, fn *IndexAggregateFunction, ...) (tuple.Tuple, error)
- func (store *FDBRecordStore) EvaluateRecordFunction(fn *IndexRecordFunction, record *FDBStoredRecord[proto.Message]) (*int64, error)
- func (store *FDBRecordStore) EvaluateStoreFunction(fn *StoreRecordFunction, record *FDBStoredRecord[proto.Message]) (any, error)
- func (store *FDBRecordStore) FirstUnbuiltRange(index *Index) (*RangeSetRange, error)
- func (store *FDBRecordStore) GetAllIndexStates() map[string]IndexState
- func (store *FDBRecordStore) GetAllIndexStatesMap() map[string]IndexState
- func (store *FDBRecordStore) GetContext() *FDBRecordContext
- func (store *FDBRecordStore) GetDisabledIndexes() []*Index
- func (store *FDBRecordStore) GetEnabledIndexes() []*Index
- func (store *FDBRecordStore) GetEnabledUniversalIndexes() []*Index
- func (store *FDBRecordStore) GetFormatVersion() int32
- func (store *FDBRecordStore) GetHeaderUserField(key string) ([]byte, error)
- func (store *FDBRecordStore) GetIncarnation() (int32, error)
- func (store *FDBRecordStore) GetIndexMaintainer(index *Index) (IndexMaintainer, error)
- func (store *FDBRecordStore) GetIndexState(indexName string) IndexState
- func (store *FDBRecordStore) GetIndexesToBuildSince(version int) []*Index
- func (store *FDBRecordStore) GetKeySizeLimit() int
- func (store *FDBRecordStore) GetMetaData() *RecordMetaData
- func (store *FDBRecordStore) GetMetaDataVersion() int32
- func (store *FDBRecordStore) GetRangeSplitPoints(chunkSize int64) ([]fdb.Key, error)
- func (store *FDBRecordStore) GetReadableIndexes() []*Index
- func (store *FDBRecordStore) GetReadableUniversalIndexes() []*Index
- func (store *FDBRecordStore) GetRecordCount() (int64, error)
- func (store *FDBRecordStore) GetRecordMetaData() *RecordMetaData
- func (store *FDBRecordStore) GetRecordStoreState() *RecordStoreState
- func (store *FDBRecordStore) GetSnapshotRecordCount(countKey tuple.Tuple) (int64, error)
- func (store *FDBRecordStore) GetSnapshotRecordCountForRecordType(recordTypeName string) (int64, error)
- func (store *FDBRecordStore) GetStoreHeader() *gen.DataStoreInfo
- func (store *FDBRecordStore) GetSubspace() subspace.Subspace
- func (store *FDBRecordStore) GetUserVersion() int32
- func (store *FDBRecordStore) GetValueSizeLimit() int
- func (store *FDBRecordStore) GetWriteOnlyIndexes() []*Index
- func (store *FDBRecordStore) IndexSecondarySubspace(index *Index) subspace.Subspace
- func (store *FDBRecordStore) IndexStateSubspace() subspace.Subspace
- func (store *FDBRecordStore) IndexSubspace(index *Index) subspace.Subspace
- func (store *FDBRecordStore) InsertRecord(record proto.Message) (*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) IsCacheable() bool
- func (store *FDBRecordStore) IsIndexDisabled(indexName string) bool
- func (store *FDBRecordStore) IsIndexReadable(indexName string) bool
- func (store *FDBRecordStore) IsIndexReadableUniquePending(indexName string) bool
- func (store *FDBRecordStore) IsIndexScannable(indexName string) bool
- func (store *FDBRecordStore) IsIndexWriteOnly(indexName string) bool
- func (store *FDBRecordStore) IsStateCacheable() bool
- func (store *FDBRecordStore) IsVersionChanged() bool
- func (store *FDBRecordStore) LoadBuildProgress(index *Index) (int64, error)
- func (store *FDBRecordStore) LoadIndexingTypeStamp(index *Index) (*gen.IndexBuildIndexingStamp, error)
- func (store *FDBRecordStore) LoadRecord(primaryKey tuple.Tuple) (*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) LoadRecordVersion(primaryKey tuple.Tuple, snapshot bool) (*FDBRecordVersion, error)
- func (store *FDBRecordStore) MarkIndexDisabled(indexName string) (bool, error)
- func (store *FDBRecordStore) MarkIndexReadable(indexName string) (bool, error)
- func (store *FDBRecordStore) MarkIndexReadableOrUniquePending(indexName string) (bool, error)
- func (store *FDBRecordStore) MarkIndexWriteOnly(indexName string) (bool, error)
- func (store *FDBRecordStore) OverrideLockSaveRecord(record proto.Message, existenceCheck RecordExistenceCheck) (*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) RebuildAllIndexes() error
- func (store *FDBRecordStore) RebuildIndex(index *Index) error
- func (store *FDBRecordStore) RecordExists(primaryKey tuple.Tuple, isolationLevel IsolationLevel) (bool, error)
- func (store *FDBRecordStore) RecordsSubspace() subspace.Subspace
- func (store *FDBRecordStore) ReleaseReadLock(key string)
- func (store *FDBRecordStore) ReleaseWriteLock(key string)
- func (store *FDBRecordStore) ReloadRecordStoreState() error
- func (store *FDBRecordStore) ResolveUniquenessViolation(index *Index, indexKey tuple.Tuple, primaryKey tuple.Tuple) error
- func (store *FDBRecordStore) ResolveUniquenessViolationByDeletion(index *Index, valueKey tuple.Tuple, remainPrimaryKey tuple.Tuple) error
- func (store *FDBRecordStore) SaveIndexingTypeStamp(index *Index, stamp *gen.IndexBuildIndexingStamp) error
- func (store *FDBRecordStore) SaveRecord(record proto.Message) (*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) SaveRecordBatch(records []proto.Message) ([]*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) SaveRecordWithOptions(record proto.Message, existenceCheck RecordExistenceCheck) (*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) ScanIndex(index *Index, scanRange TupleRange, continuation []byte, ...) RecordCursor[*IndexEntry]
- func (store *FDBRecordStore) ScanIndexByType(index *Index, scanType IndexScanType, scanRange TupleRange, ...) RecordCursor[*IndexEntry]
- func (store *FDBRecordStore) ScanIndexRecords(indexName string, scanRange TupleRange, continuation []byte, ...) RecordCursor[*FDBIndexedRecord]
- func (store *FDBRecordStore) ScanRecordKeys(continuation []byte, scanProperties ScanProperties) RecordCursor[tuple.Tuple]
- func (store *FDBRecordStore) ScanRecords(continuation []byte, scanProperties ScanProperties) RecordCursor[*FDBStoredRecord[proto.Message]]
- func (store *FDBRecordStore) ScanRecordsByType(recordTypeName string, continuation []byte, scanProperties ScanProperties) RecordCursor[*FDBStoredRecord[proto.Message]]
- func (store *FDBRecordStore) ScanRecordsInRange(low, high tuple.Tuple, lowEndpoint, highEndpoint EndpointType, ...) RecordCursor[*FDBStoredRecord[proto.Message]]
- func (store *FDBRecordStore) ScanTimeWindowLeaderboard(index *Index, scanType IndexScanType, leaderboardType int, ...) RecordCursor[*IndexEntry]
- func (store *FDBRecordStore) ScanUniquenessViolations(index *Index) ([]UniquenessViolation, error)
- func (store *FDBRecordStore) ScanUniquenessViolationsForValue(index *Index, valueKey tuple.Tuple) ([]UniquenessViolation, error)
- func (store *FDBRecordStore) ScanVectorIndex(index *Index, queryVector []float64, k int, efSearch int, continuation []byte, ...) RecordCursor[*IndexEntry]
- func (store *FDBRecordStore) ScanVectorIndexWithPrefix(index *Index, prefix tuple.Tuple, queryVector []float64, k int, efSearch int, ...) RecordCursor[*IndexEntry]
- func (store *FDBRecordStore) SearchVectorIndex(index *Index, queryVector []float64, k int, efSearch int) ([]VectorSearchResult, error)
- func (store *FDBRecordStore) SearchVectorIndexRecords(ctx context.Context, index *Index, queryVector []float64, k int, efSearch int) ([]*FDBIndexedRecord, error)
- func (store *FDBRecordStore) SearchVectorIndexRecordsWithPrefix(ctx context.Context, index *Index, prefix tuple.Tuple, queryVector []float64, ...) ([]*FDBIndexedRecord, error)
- func (store *FDBRecordStore) SearchVectorIndexWithPrefix(index *Index, prefix tuple.Tuple, queryVector []float64, k int, efSearch int) ([]VectorSearchResult, error)
- func (store *FDBRecordStore) SetFormatVersion(version int32) error
- func (store *FDBRecordStore) SetHeaderUserField(key string, value []byte) error
- func (store *FDBRecordStore) SetStateCacheability(cacheable bool) (bool, error)
- func (store *FDBRecordStore) SetStoreLockState(state gen.DataStoreInfo_StoreLockState_State, reason string) error
- func (store *FDBRecordStore) SetUserVersion(version int32) error
- func (store *FDBRecordStore) Subspace() subspace.Subspace
- func (store *FDBRecordStore) UpdateIncarnation(updater func(current int32) int32) error
- func (store *FDBRecordStore) UpdateRecord(record proto.Message) (*FDBStoredRecord[proto.Message], error)
- func (store *FDBRecordStore) UpdateRecordCountState(newState gen.DataStoreInfo_RecordCountState) error
- func (store *FDBRecordStore) VacuumReadableIndexesBuildData()
- func (store *FDBRecordStore) ValidateIndex(ctx context.Context, index *Index) (*IndexValidationResult, error)
- type FDBRecordStoreStateCache
- type FDBRecordStoreStateCacheEntry
- type FDBRecordVersion
- func CompleteVersionFromBytes(b []byte) (*FDBRecordVersion, error)
- func FirstInDBVersion(dbVersion int64) *FDBRecordVersion
- func FirstInGlobalVersion(globalVersion []byte) (*FDBRecordVersion, error)
- func FromVersionstamp(vs tuple.Versionstamp) *FDBRecordVersion
- func IncompleteVersion(localVersion int) (*FDBRecordVersion, error)
- func LastInDBVersion(dbVersion int64) *FDBRecordVersion
- func LastInGlobalVersion(globalVersion []byte) (*FDBRecordVersion, error)
- func MaxVersion() *FDBRecordVersion
- func MinVersion() *FDBRecordVersion
- func NewCompleteVersion(globalVersion []byte, localVersion int) (*FDBRecordVersion, error)
- func (v *FDBRecordVersion) Equal(other *FDBRecordVersion) bool
- func (v *FDBRecordVersion) GetDBVersion() (int64, error)
- func (v *FDBRecordVersion) GetGlobalVersion() ([]byte, error)
- func (v *FDBRecordVersion) GetLocalVersion() int
- func (v *FDBRecordVersion) IsComplete() bool
- func (v *FDBRecordVersion) Less(other *FDBRecordVersion) bool
- func (v *FDBRecordVersion) Next() (*FDBRecordVersion, error)
- func (v *FDBRecordVersion) Prev() (*FDBRecordVersion, error)
- func (v *FDBRecordVersion) String() string
- func (v *FDBRecordVersion) ToBytes() []byte
- func (v *FDBRecordVersion) ToVersionstamp() (tuple.Versionstamp, error)
- func (v *FDBRecordVersion) WithCommittedVersion(committedVersion []byte) (*FDBRecordVersion, error)
- type FDBStoredRecord
- type FanType
- type FieldKeyExpression
- func (f *FieldKeyExpression) ColumnSize() int
- func (f *FieldKeyExpression) Evaluate(_ *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (f *FieldKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
- func (f *FieldKeyExpression) EvaluateInt64(record *FDBStoredRecord[proto.Message], msg proto.Message) (int64, bool, error)
- func (f *FieldKeyExpression) EvaluateScalar(record *FDBStoredRecord[proto.Message], msg proto.Message) (any, error)
- func (f *FieldKeyExpression) FieldNames() []string
- func (f *FieldKeyExpression) PackDirect(pk *tuple.Packer, _ *FDBStoredRecord[proto.Message], msg proto.Message) bool
- func (f *FieldKeyExpression) ToKeyExpression() *gen.KeyExpression
- type FlatEvaluator
- type FormerIndex
- type FoundSplitOutOfOrderError
- type FoundSplitWithoutStartError
- type FunctionEvaluator
- type FunctionKeyExpression
- func (f *FunctionKeyExpression) Arguments() KeyExpression
- func (f *FunctionKeyExpression) ColumnSize() int
- func (f *FunctionKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (f *FunctionKeyExpression) FieldNames() []string
- func (f *FunctionKeyExpression) Name() string
- func (f *FunctionKeyExpression) ToKeyExpression() *gen.KeyExpression
- type GroupingKeyExpression
- func (g *GroupingKeyExpression) ColumnSize() int
- func (g *GroupingKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (g *GroupingKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
- func (g *GroupingKeyExpression) FieldNames() []string
- func (g *GroupingKeyExpression) GetGroupedCount() int
- func (g *GroupingKeyExpression) GetGroupingCount() int
- func (g *GroupingKeyExpression) ToKeyExpression() *gen.KeyExpression
- type HNSWConfig
- type HNSWStats
- type IncompleteVersionstampError
- type Index
- func NewBitmapValueIndex(name string, rootExpression KeyExpression) *Index
- func NewCountIndex(name string, rootExpression KeyExpression) *Index
- func NewCountNotNullIndex(name string, rootExpression KeyExpression) *Index
- func NewCountUpdatesIndex(name string, rootExpression KeyExpression) *Index
- func NewGroupCountCompanion(idx *Index) (*Index, bool)
- func NewIndex(name string, rootExpression KeyExpression) *Index
- func NewMaxEverLongIndex(name string, rootExpression KeyExpression) *Index
- func NewMaxEverTupleIndex(name string, rootExpression KeyExpression) *Index
- func NewMaxEverVersionIndex(name string, rootExpression KeyExpression) *Index
- func NewMinEverLongIndex(name string, rootExpression KeyExpression) *Index
- func NewMinEverTupleIndex(name string, rootExpression KeyExpression) *Index
- func NewMultidimensionalIndex(name string, rootExpression KeyExpression) *Index
- func NewPermutedMaxIndex(name string, rootExpression KeyExpression, permutedSize int) *Index
- func NewPermutedMinIndex(name string, rootExpression KeyExpression, permutedSize int) *Index
- func NewRankIndex(name string, rootExpression KeyExpression) *Index
- func NewSumIndex(name string, rootExpression KeyExpression) *Index
- func NewTextIndex(name string, rootExpression KeyExpression) *Index
- func NewTimeWindowLeaderboardIndex(name string, rootExpression KeyExpression) *Index
- func NewVectorIndex(name string, rootExpression KeyExpression, numDimensions int) *Index
- func NewVersionIndex(name string, rootExpression KeyExpression) *Index
- func (idx *Index) CanonicalType() string
- func (i *Index) CreatesDuplicates() bool
- func (idx *Index) GetBooleanOption(key string, defaultVal bool) bool
- func (idx *Index) GetPredicateProto() *gen.Predicate
- func (idx *Index) GetReplacedByIndexNames() []string
- func (idx *Index) HasExplicitSubspaceKey() bool
- func (idx *Index) HasFilteringPredicate() bool
- func (idx *Index) HasPredicate() bool
- func (idx *Index) HasPrimaryKeyComponentPositions() bool
- func (idx *Index) HasRowNumberWindowPredicate() bool
- func (idx *Index) IsAtomicMutationIndex() bool
- func (idx *Index) IsClearWhenZero() bool
- func (idx *Index) IsUnique() bool
- func (idx *Index) PrimaryKeyComponentPositions() []int
- func (idx *Index) RowNumberWindowSpec() (*RowNumberWindowSpec, error)
- func (idx *Index) SetClearWhenZero(clear bool) *Index
- func (idx *Index) SetPredicate(p IndexPredicate) *Index
- func (idx *Index) SetPredicateProto(p *gen.Predicate) error
- func (idx *Index) SetSubspaceKey(key any) *Index
- func (idx *Index) SetUnique() *Index
- func (idx *Index) SubspaceTupleKey() any
- func (idx *Index) TrimPrimaryKey(primaryKey tuple.Tuple) (tuple.Tuple, error)
- type IndexAggregateFunction
- func NewCountAggregateFunction(operand KeyExpression) *IndexAggregateFunction
- func NewMaxAggregateFunction(operand KeyExpression) *IndexAggregateFunction
- func NewMaxEverAggregateFunction(operand KeyExpression) *IndexAggregateFunction
- func NewMinAggregateFunction(operand KeyExpression) *IndexAggregateFunction
- func NewMinEverAggregateFunction(operand KeyExpression) *IndexAggregateFunction
- func NewSumAggregateFunction(operand KeyExpression) *IndexAggregateFunction
- type IndexBuildState
- type IndexEntry
- type IndexKeySizeError
- type IndexMaintainer
- type IndexNotBuiltError
- type IndexNotFoundError
- type IndexNotReadableError
- type IndexPredicate
- type IndexRebuildPolicy
- type IndexRecordFunction
- type IndexScanType
- type IndexState
- type IndexValidationEntry
- type IndexValidationResult
- type IndexValueSizeError
- type IndexVersionKind
- type IndexVersionTooNewError
- type IndexingHeartbeat
- type IndexingPolicy
- type IndexingRangeSet
- func (irs *IndexingRangeSet) Clear(tr fdb.WritableTransaction)
- func (irs *IndexingRangeSet) ContainsKey(tr fdb.WritableTransaction, key []byte) (bool, error)
- func (irs *IndexingRangeSet) FirstMissingRange(tr fdb.WritableTransaction) (*RangeSetRange, error)
- func (irs *IndexingRangeSet) InsertRange(tr fdb.WritableTransaction, begin, end []byte, requireEmpty bool) (bool, error)
- func (irs *IndexingRangeSet) IsComplete(tr fdb.WritableTransaction) (bool, error)
- func (irs *IndexingRangeSet) ListMissingRanges(tr fdb.WritableTransaction) ([]RangeSetRange, error)
- func (irs *IndexingRangeSet) ListMissingRangesInBytes(tr fdb.WritableTransaction, begin, end []byte) ([]RangeSetRange, error)
- type Int64Evaluator
- type IntersectionChildResume
- type InvalidNameError
- type IsolationLevel
- type ItemSlot
- type KVCallback
- type KeyExpression
- func Concat(exprs ...KeyExpression) KeyExpression
- func EmptyKey() KeyExpression
- func FanOut(name string) KeyExpression
- func Field(name string) KeyExpression
- func FieldConcatenate(name string) KeyExpression
- func GetNestedExpression(expr KeyExpression) KeyExpression
- func GroupingKeyExpressionOf(g *GroupingKeyExpression) (KeyExpression, bool)
- func KeyExpressionFromProto(expr *gen.KeyExpression) (KeyExpression, error)
- func Nest(parentField string, child KeyExpression) KeyExpression
- func NestFanOut(parentField string, child KeyExpression) KeyExpression
- type KeyExpressionError
- type KeyWithValueExpression
- func (k *KeyWithValueExpression) ColumnSize() int
- func (k *KeyWithValueExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (k *KeyWithValueExpression) FieldNames() []string
- func (k *KeyWithValueExpression) InnerKey() KeyExpression
- func (k *KeyWithValueExpression) SplitEvaluatedKey(fullKey []any) (keyPart []any, valuePart []any)
- func (k *KeyWithValueExpression) SplitPoint() int
- func (k *KeyWithValueExpression) ToKeyExpression() *gen.KeyExpression
- type Kind
- type ListKeyExpression
- func (l *ListKeyExpression) ColumnSize() int
- func (l *ListKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (l *ListKeyExpression) FieldNames() []string
- func (l *ListKeyExpression) GetChildren() []KeyExpression
- func (l *ListKeyExpression) ToKeyExpression() *gen.KeyExpression
- type LiteralKeyExpression
- func (l *LiteralKeyExpression) ColumnSize() int
- func (l *LiteralKeyExpression) Evaluate(_ *FDBStoredRecord[proto.Message], _ proto.Message) ([][]any, error)
- func (l *LiteralKeyExpression) FieldNames() []string
- func (l *LiteralKeyExpression) GetValue() any
- func (l *LiteralKeyExpression) ToKeyExpression() *gen.KeyExpression
- type MBR
- type MemoryLimitExceededError
- type MetaDataError
- type MetaDataEvolutionError
- type MetaDataEvolutionValidator
- type MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) Build() *MetaDataEvolutionValidator
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowDeprecatedFieldRenames(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowFieldRenames(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowIndexRebuilds(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowMissingFormerIndexNames(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowNoSinceVersion(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowNoVersionChange(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowOlderFormerIndexAddedVersion(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowUndeprecatingFields(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetAllowUnsplitToSplit(v bool) *MetaDataEvolutionValidatorBuilder
- func (b *MetaDataEvolutionValidatorBuilder) SetDisallowTypeRenames(v bool) *MetaDataEvolutionValidatorBuilder
- type MetaDataVersionMustIncreaseError
- type MetaDataVersionStampStoreStateCache
- type MetaDataVersionStampStoreStateCacheOption
- type NestingKeyExpression
- type NoNextReason
- type NodeKind
- type OnlineIndexer
- func (oi *OnlineIndexer) BlockIndex(ctx context.Context, blockID string, ttl time.Duration) error
- func (oi *OnlineIndexer) BuildIndex(ctx context.Context) (int64, error)
- func (oi *OnlineIndexer) MarkReadableIfBuilt(ctx context.Context) (bool, error)
- func (oi *OnlineIndexer) QueryIndexingStamps(ctx context.Context) (map[string]*gen.IndexBuildIndexingStamp, error)
- func (oi *OnlineIndexer) UnblockIndex(ctx context.Context, blockID string) error
- type OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) AddTargetIndex(index *Index) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) Build() (*OnlineIndexer, error)
- func (b *OnlineIndexerBuilder) SetAllowUniquePendingState(allow bool) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetDatabase(db *FDBDatabase) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetEnforcedPostTransactionDelay(ms int) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetFormatVersion(version int32) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetIndex(index *Index) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetLeaseLengthMs(ms int64) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetLimit(limit int) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetLogger(logger *slog.Logger) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetMarkReadable(v bool) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetMaxRetries(maxRetries int) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetMetaData(md *RecordMetaData) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetMutualIndexing() *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetMutualIndexingBoundaries(boundaries [][]byte) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetPolicy(policy *IndexingPolicy) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetProgressLogIntervalMillis(ms int64) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetRecordTypes(types ...string) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetRecordsPerSecond(rps int) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetSourceIndex(index *Index) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetSubspace(ss subspace.Subspace) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetTargetIndexes(indexes []*Index) *OnlineIndexerBuilder
- func (b *OnlineIndexerBuilder) SetTimeLimit(d time.Duration) *OnlineIndexerBuilder
- type OrderDirection
- type OrdinaryIndexScanFunc
- type PartlyBuiltError
- type PassThroughRecordStoreStateCache
- type Point
- type PostCommitFunc
- type RTree
- func (rt *RTree) Clear(tx fdb.WritableTransaction) error
- func (rt *RTree) Delete(tx fdb.WritableTransaction, point Point, keySuffix tuple.Tuple) error
- func (rt *RTree) InsertOrUpdate(tx fdb.WritableTransaction, point Point, keySuffix tuple.Tuple, ...) error
- func (rt *RTree) Scan(tx fdb.ReadTransaction, lastHV *big.Int, lastKey tuple.Tuple, ...) ([]ItemSlot, error)
- func (rt *RTree) ScanIterator(tx fdb.ReadTransaction, lastHV *big.Int, lastKey tuple.Tuple, ...) *RTreeIterator
- type RTreeConfig
- type RTreeIterator
- type RangeSet
- func (rs *RangeSet) Clear(tr fdb.WritableTransaction)
- func (rs *RangeSet) Contains(tr fdb.WritableTransaction, key []byte) (bool, error)
- func (rs *RangeSet) InsertRange(tr fdb.WritableTransaction, begin, end []byte, requireEmpty bool) (bool, error)
- func (rs *RangeSet) IsEmpty(tr fdb.WritableTransaction) (bool, error)
- func (rs *RangeSet) MissingRanges(tr fdb.WritableTransaction, begin, end []byte, limit int) ([]RangeSetRange, error)
- type RangeSetEmptyKeyError
- type RangeSetInvertedRangeError
- type RangeSetKeyTooLargeError
- type RangeSetRange
- type RankQuerier
- type RecordAlreadyExistsError
- type RecordContextConfig
- type RecordCoreStorageError
- type RecordCountKeySizeMismatchError
- type RecordCursor
- func Chained[T any](generator func(prev *T) (*T, error), encode func(T) []byte, ...) RecordCursor[T]
- func ConcatCursors[T any](first, second CursorFactory[T], continuation []byte) RecordCursor[T]
- func Dedup[T any](innerFactory CursorFactory[T], equal func(a, b T) bool, pack func(T) []byte, ...) RecordCursor[T]
- func Empty[T any]() RecordCursor[T]
- func Fallback[T any](inner RecordCursor[T], ...) RecordCursor[T]
- func FlatMapPipelined[T, V any](outerFactory CursorFactory[T], innerFactory func(T, []byte) RecordCursor[V], ...) RecordCursor[V]
- func FlatMapPipelinedWithCheck[T, V any](outerFactory CursorFactory[T], innerFactory func(T, []byte) RecordCursor[V], ...) RecordCursor[V]
- func FromList[T any](items []T) RecordCursor[T]
- func FromListWithContinuation[T any](items []T, continuation []byte) RecordCursor[T]
- func InstrumentIndexScanCursor(timer *StoreTimer, inner RecordCursor[*IndexEntry]) RecordCursor[*IndexEntry]
- func Intersection[T any](cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool) RecordCursor[T]
- func IntersectionMulti[T any](cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool) RecordCursor[[]T]
- func IntersectionMultiResume[T any](cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, ...) RecordCursor[[]T]
- func IntersectionResume[T any](cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, ...) RecordCursor[T]
- func LimitRowsCursor[T any](cursor RecordCursor[T], n int) RecordCursor[T]
- func MapCursor[T, R any](cursor RecordCursor[T], fn func(T) R) RecordCursor[R]
- func MapErrCursor[T, R any](cursor RecordCursor[T], fn func(T) (R, error)) RecordCursor[R]
- func NewAutoContinuingCursor[T any](runner *FDBDatabaseRunner, ...) RecordCursor[T]
- func OrElse[T any](primary RecordCursor[T], alternative func() RecordCursor[T]) RecordCursor[T]
- func OrElseWithContinuation[T any](primaryFactory CursorFactory[T], alternativeFactory CursorFactory[T], ...) RecordCursor[T]
- func OuterMergeMultiResume[T any](cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, ...) RecordCursor[[]T]
- func SkipCursor[T any](cursor RecordCursor[T], n int) RecordCursor[T]
- func SkipThenLimit[T any](cursor RecordCursor[T], skip, limit int) RecordCursor[T]
- func Stopped[T any](reason NoNextReason, continuation RecordCursorContinuation) RecordCursor[T]
- type RecordCursorContinuation
- type RecordCursorResult
- func MapResult[T, R any](result RecordCursorResult[T], fn func(T) R) RecordCursorResult[R]
- func NewResultNoNext[T any](reason NoNextReason, continuation RecordCursorContinuation) RecordCursorResult[T]
- func NewResultWithValue[T any](value T, continuation RecordCursorContinuation) RecordCursorResult[T]
- func (r RecordCursorResult[T]) GetContinuation() RecordCursorContinuation
- func (r RecordCursorResult[T]) GetNoNextReason() NoNextReason
- func (r RecordCursorResult[T]) GetValue() T
- func (r RecordCursorResult[T]) HasNext() bool
- func (r RecordCursorResult[T]) HasStoppedBeforeEnd() bool
- func (r RecordCursorResult[T]) WithContinuation(continuation RecordCursorContinuation) RecordCursorResult[T]
- type RecordDeserializationError
- type RecordDoesNotExistError
- type RecordExistenceCheck
- type RecordIndexUniquenessViolationError
- type RecordMetaData
- func (m *RecordMetaData) AmbiguousDeclaredNames() ([]string, bool)
- func (m *RecordMetaData) CommonPrimaryKey() KeyExpression
- func (m *RecordMetaData) CommonPrimaryKeyLength() int
- func (m *RecordMetaData) DeclaresSyntheticRecordTypes() bool
- func (m *RecordMetaData) FileDescriptor() protoreflect.FileDescriptor
- func (m *RecordMetaData) GetAllIndexes() map[string]*Index
- func (m *RecordMetaData) GetFormerIndexes() []*FormerIndex
- func (m *RecordMetaData) GetFormerIndexesSince(version int) []*FormerIndex
- func (m *RecordMetaData) GetIndex(name string) *Index
- func (m *RecordMetaData) GetIndexFromSubspaceKey(key any) *Index
- func (m *RecordMetaData) GetIndexesForRecordType(name string) []*Index
- func (m *RecordMetaData) GetIndexesToBuildSince(version int) []*Index
- func (m *RecordMetaData) GetRecordCountKey() KeyExpression
- func (m *RecordMetaData) GetRecordType(name string) *RecordType
- func (m *RecordMetaData) GetRecordTypeFromRecordTypeKey(key any) *RecordType
- func (m *RecordMetaData) GetSubspaceKeyCounter() int64
- func (m *RecordMetaData) GetUnionDescriptor() protoreflect.MessageDescriptor
- func (m *RecordMetaData) GetUnionFieldForRecordType(rt *RecordType) protoreflect.FieldDescriptor
- func (m *RecordMetaData) GetUniversalIndexes() []*Index
- func (m *RecordMetaData) HasIndexes() bool
- func (m *RecordMetaData) IsSplitLongRecords() bool
- func (m *RecordMetaData) IsStoreRecordVersions() bool
- func (m *RecordMetaData) PrimaryKeyHasRecordTypePrefix() bool
- func (m *RecordMetaData) RecordTypes() map[string]*RecordType
- func (m *RecordMetaData) RecordTypesForIndex(idx *Index) []*RecordType
- func (m *RecordMetaData) SyntheticRecordTypeNames() []string
- func (m *RecordMetaData) ToProto() (*gen.MetaData, error)
- func (m *RecordMetaData) UsesSubspaceKeyCounter() bool
- func (m *RecordMetaData) Version() int
- type RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) AddIndex(recordTypeName string, index *Index) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) AddMultiTypeIndex(recordTypeNames []string, index *Index) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) AddUniversalIndex(index *Index) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) Build() (*RecordMetaData, error)
- func (b *RecordMetaDataBuilder) EnableCounterBasedSubspaceKeys() *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) GetFormerIndexes() []*FormerIndex
- func (b *RecordMetaDataBuilder) GetRecordCountKey() KeyExpression
- func (b *RecordMetaDataBuilder) GetRecordType(name string) *RecordTypeBuilder
- func (b *RecordMetaDataBuilder) GetRecordTypes() map[string]*RecordType
- func (b *RecordMetaDataBuilder) GetSubspaceKeyCounter() int64
- func (b *RecordMetaDataBuilder) GetVersion() int
- func (b *RecordMetaDataBuilder) IsSplitLongRecords() bool
- func (b *RecordMetaDataBuilder) IsStoreRecordVersions() bool
- func (b *RecordMetaDataBuilder) RemoveIndex(indexName string) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetRecordCountKey(key KeyExpression) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetRecords(fd protoreflect.FileDescriptor) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetRecordsSourceProto(fdp *descriptorpb.FileDescriptorProto) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetRecordsWithUnionName(fd protoreflect.FileDescriptor, unionName string) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetSplitLongRecords(split bool) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetStoreRecordVersions(store bool) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetSubspaceKeyCounter(counter int64) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) SetVersion(version int) *RecordMetaDataBuilder
- func (b *RecordMetaDataBuilder) UsesSubspaceKeyCounter() bool
- type RecordSerializationError
- type RecordStoreAlreadyExistsError
- type RecordStoreDoesNotExistError
- type RecordStoreNoInfoButNotEmptyError
- type RecordStoreState
- type RecordStoreStateNotLoadedError
- type RecordType
- func (rt *RecordType) GetAllIndexes() []*Index
- func (rt *RecordType) GetIndexes() []*Index
- func (rt *RecordType) GetMultiTypeIndexes() []*Index
- func (rt *RecordType) GetRecordTypeKey() any
- func (rt *RecordType) HasExplicitRecordTypeKey() bool
- func (rt *RecordType) IsSynthetic() bool
- func (rt *RecordType) PrimaryKeyHasRecordTypePrefix() bool
- type RecordTypeBuilder
- type RecordTypeChangedError
- type RecordTypeKeyExpression
- func (r *RecordTypeKeyExpression) ColumnSize() int
- func (r *RecordTypeKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (r *RecordTypeKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
- func (r *RecordTypeKeyExpression) EvaluateScalar(record *FDBStoredRecord[proto.Message], msg proto.Message) (any, error)
- func (r *RecordTypeKeyExpression) FieldNames() []string
- func (r *RecordTypeKeyExpression) Nest(expr KeyExpression) KeyExpression
- func (r *RecordTypeKeyExpression) PackDirect(pk *tuple.Packer, record *FDBStoredRecord[proto.Message], msg proto.Message) bool
- func (r *RecordTypeKeyExpression) ToKeyExpression() *gen.KeyExpression
- type RecordTypeKeyTypeError
- type RecordTypeKeyUnresolvedError
- type RecordTypeStatistic
- type RowNumberWindowDirection
- type RowNumberWindowSpec
- type SPFreshConfig
- type SPFreshIntegrityReport
- type SPFreshIntegrityViolation
- type SPFreshMaintenanceOptions
- type SPFreshRecallReport
- type SPFreshRefineOptions
- type SPFreshRefineResult
- type SPFreshSweepOptions
- type SPFreshSweepResult
- type SPFreshTenant
- type ScalarEvaluator
- type ScanLimitReachedError
- type ScanLimiterState
- func (s *ScanLimiterState) AddBytesScanned(n int64)
- func (s *ScanLimiterState) AddRecordScanned()
- func (s *ScanLimiterState) AnchorAt(t time.Time)
- func (s *ScanLimiterState) BytesScanned() int64
- func (s *ScanLimiterState) Elapsed() time.Duration
- func (s *ScanLimiterState) RecordsScanned() int
- func (s *ScanLimiterState) StartTime() time.Time
- type ScanProperties
- func (s ScanProperties) GetExecuteProperties() ExecuteProperties
- func (s ScanProperties) IsReverse() bool
- func (s ScanProperties) WithExecuteProperties(props ExecuteProperties) ScanProperties
- func (s ScanProperties) WithReverse(reverse bool) ScanProperties
- func (s ScanProperties) WithStreamingMode(mode CursorStreamingMode) ScanProperties
- type SlidingWindowCorruptionError
- type SlidingWindowDeleteWhereError
- type SplitKeyExpression
- func (s *SplitKeyExpression) ColumnSize() int
- func (s *SplitKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
- func (s *SplitKeyExpression) FieldNames() []string
- func (s *SplitKeyExpression) GetJoined() KeyExpression
- func (s *SplitKeyExpression) GetSplitSize() int
- func (s *SplitKeyExpression) ToKeyExpression() *gen.KeyExpression
- type StaleMetaDataVersionError
- type StartContinuation
- type StatisticsReadRefusal
- type StatisticsSubspace
- type StoreBuilder
- func (b *StoreBuilder) Build() (*FDBRecordStore, error)
- func (b *StoreBuilder) Create() (*FDBRecordStore, error)
- func (b *StoreBuilder) CreateOrOpen() (*FDBRecordStore, error)
- func (b *StoreBuilder) Open() (*FDBRecordStore, error)
- func (b *StoreBuilder) SetAssumeAllIndexesReadable(assume bool) *StoreBuilder
- func (b *StoreBuilder) SetBypassFullStoreLockReason(reason string) *StoreBuilder
- func (b *StoreBuilder) SetContext(ctx *FDBRecordContext) *StoreBuilder
- func (b *StoreBuilder) SetDatabase(db *FDBDatabase) *StoreBuilder
- func (b *StoreBuilder) SetFormatVersion(version int32) *StoreBuilder
- func (b *StoreBuilder) SetIndexRebuildPolicy(policy IndexRebuildPolicy) *StoreBuilder
- func (b *StoreBuilder) SetMetaDataProvider(metaData *RecordMetaData) *StoreBuilder
- func (b *StoreBuilder) SetSkipPossiblyRebuild(skip bool) *StoreBuilder
- func (b *StoreBuilder) SetStoreStateCache(cache FDBRecordStoreStateCache) *StoreBuilder
- func (b *StoreBuilder) SetSubspace(subspace subspace.Subspace) *StoreBuilder
- type StoreExistenceCheck
- type StoreIsFullyLockedError
- type StoreIsLockedForRecordUpdatesError
- type StoreRecordFunction
- type StoreStatistics
- type StoreTimer
- func (t *StoreTimer) Add(other *StoreTimer)
- func (t *StoreTimer) GetCount(event Event) int64
- func (t *StoreTimer) GetCounter(event Event) *Counter
- func (t *StoreTimer) GetTimeNanos(event Event) int64
- func (t *StoreTimer) Increment(event Event)
- func (t *StoreTimer) IncrementBy(event Event, amount int64)
- func (t *StoreTimer) KeysAndValues() map[string]int64
- func (t *StoreTimer) Record(event Event, timeNanos int64)
- func (t *StoreTimer) RecordSince(event Event, startTime time.Time)
- func (t *StoreTimer) RecordSize(event Event, size int64)
- func (t *StoreTimer) Reset()
- func (t *StoreTimer) Snapshot() map[string]*CounterSnapshot
- type SubspaceSplitter
- type SynchronizedSessionLockedError
- type SyntheticRecordTypesNotModeledError
- type TagValidationError
- type TakeoverType
- type TextIndexBunchedSerializer
- func (s *TextIndexBunchedSerializer) CanAppend() bool
- func (s *TextIndexBunchedSerializer) DeserializeEntries(key tuple.Tuple, data []byte) ([]BunchedEntry[tuple.Tuple, []int], error)
- func (s *TextIndexBunchedSerializer) DeserializeKey(data []byte, offset, length int) (tuple.Tuple, error)
- func (s *TextIndexBunchedSerializer) DeserializeKeys(key tuple.Tuple, data []byte) ([]tuple.Tuple, error)
- func (s *TextIndexBunchedSerializer) SerializeEntries(entries []BunchedEntry[tuple.Tuple, []int]) ([]byte, error)
- func (s *TextIndexBunchedSerializer) SerializeEntry(key tuple.Tuple, value []int) ([]byte, error)
- func (s *TextIndexBunchedSerializer) SerializeKey(key tuple.Tuple) []byte
- type TextSubspaceSplitter
- type TextTokenizer
- type TextTokenizerFactory
- type TextTokenizerRegistry
- type TimeLimitExceededError
- type TimeWindowForFunction
- type TimeWindowLeaderboardWindowUpdate
- type TimeWindowRebuild
- type TimeWindowSpec
- type TokenIterator
- type TokenizerMode
- type TransactionPriority
- type TransactionSizeExceededError
- type TransactionSizeWarningError
- type TupleRange
- func TupleRangeAllOf(prefix tuple.Tuple) TupleRange
- func TupleRangeBetween(low, high tuple.Tuple) TupleRange
- func TupleRangeBetweenInclusive(low, high tuple.Tuple) TupleRange
- func TupleRangePrefixString(token string) TupleRange
- func VectorDistanceScanRange(queryVector []float64, k, efSearch int) TupleRange
- func VectorDistanceScanRangeOrdered(queryVector []float64, k, efSearch, cRerank int, prefix tuple.Tuple) TupleRange
- func VectorDistanceScanRangeWithPrefix(queryVector []float64, k, efSearch int, prefix tuple.Tuple) TupleRange
- type TypedFDBRecordStore
- func (ts *TypedFDBRecordStore[T]) AddRecordReadConflict(primaryKey tuple.Tuple) error
- func (ts *TypedFDBRecordStore[T]) AddRecordWriteConflict(primaryKey tuple.Tuple) error
- func (ts *TypedFDBRecordStore[T]) Context() *FDBRecordContext
- func (ts *TypedFDBRecordStore[T]) DeleteAllRecords() error
- func (ts *TypedFDBRecordStore[T]) DeleteRecord(primaryKey tuple.Tuple) (bool, error)
- func (ts *TypedFDBRecordStore[T]) GetRecordCount() (int64, error)
- func (ts *TypedFDBRecordStore[T]) GetSnapshotRecordCount(countKey tuple.Tuple) (int64, error)
- func (ts *TypedFDBRecordStore[T]) InsertRecord(record T) (*FDBStoredRecord[T], error)
- func (ts *TypedFDBRecordStore[T]) LoadRecord(primaryKey tuple.Tuple) (*FDBStoredRecord[T], error)
- func (ts *TypedFDBRecordStore[T]) RecordExists(primaryKey tuple.Tuple, isolationLevel IsolationLevel) (bool, error)
- func (ts *TypedFDBRecordStore[T]) SaveRecord(record T) (*FDBStoredRecord[T], error)
- func (ts *TypedFDBRecordStore[T]) SaveRecordWithOptions(record T, existenceCheck RecordExistenceCheck) (*FDBStoredRecord[T], error)
- func (ts *TypedFDBRecordStore[T]) ScanRecords(continuation []byte, scanProperties ScanProperties) RecordCursor[*FDBStoredRecord[T]]
- func (ts *TypedFDBRecordStore[T]) Subspace() subspace.Subspace
- func (ts *TypedFDBRecordStore[T]) UpdateRecord(record T) (*FDBStoredRecord[T], error)
- type UniquenessViolation
- type UnknownIndexTypeError
- type UnknownOrElseCursorStateError
- type UnknownStoreLockStateError
- type UnsupportedFeatureForFormatVersionError
- type UnsupportedFormatVersionError
- type VectorMetric
- type VectorQuantizer
- type VectorScanBounds
- type VectorSearchResult
- type VersionKeyExpression
- type VersionMutationType
- type WeakReadSemantics
Constants ¶
const ( FunctionNameCount = "count" FunctionNameCountNotNull = "count_not_null" FunctionNameCountUpdates = "count_updates" FunctionNameSum = "sum" FunctionNameMinEver = "min_ever" FunctionNameMaxEver = "max_ever" FunctionNameMin = "min" FunctionNameMax = "max" // RANK aggregate function names. FunctionNameRankForScore = "rank_for_score" FunctionNameScoreForRank = "score_for_rank" FunctionNameScoreForRankElseSkip = "score_for_rank_else_skip" FunctionNameCountDistinct = "count_distinct" // BITMAP_VALUE aggregate function name. FunctionNameBitmapValue = "bitmap_value" )
Aggregate function name constants matching Java's FunctionNames.
const ( CollateFuncJRE = "collate_jre" CollateFuncICU = "collate_icu" )
Collation function names matching Java's CollateFunctionKeyExpressionFactory. Both JRE and ICU variants are registered since Go uses golang.org/x/text/collate (CLDR-based, similar to ICU).
NOTE: Collation key bytes are NOT wire-compatible with Java's. Java uses java.text.CollationKey.toByteArray() (JRE) or com.ibm.icu.text.CollationKey.toByteArray() (ICU), whose binary formats are Java/ICU-version-specific. Go's collation keys use golang.org/x/text's CLDR-based format. This means: - Go can read/write its own collated indexes correctly - Go preserves collated index definitions during metadata round-trip - Go CANNOT share collated indexes with Java (different sort key bytes)
const ( CollateStrengthPrimary = 0 // Base form only (ignores case and accents) CollateStrengthSecondary = 1 // Base form + accents (case-insensitive) CollateStrengthTertiary = 2 // Base form + accents + case )
Collation strength levels matching Java's Collator.PRIMARY/SECONDARY/TERTIARY.
const ( // StoreInfoKey is the subspace key for store metadata StoreInfoKey = 0 // RecordKey is the subspace key for storing records RecordKey = 1 // IndexKey is the subspace key for storing indexes IndexKey = 2 // IndexSecondarySpaceKey is the subspace key for secondary index data IndexSecondarySpaceKey = 3 // RecordCountKey is the subspace key for record counts RecordCountKey = 4 // IndexStateSpaceKey is the subspace key for index state IndexStateSpaceKey = 5 // IndexRangeSpaceKey is the subspace key for index ranges IndexRangeSpaceKey = 6 // IndexUniquenessViolationsKey is the subspace key for uniqueness violations IndexUniquenessViolationsKey = 7 // RecordVersionKey is the subspace key for record versions RecordVersionKey = 8 // IndexBuildSpaceKey is the subspace key for index building IndexBuildSpaceKey = 9 // IndexSlidingWindowSpaceKey is the subspace key for a sliding-window // (top-N) index's bookkeeping: the per-partition entry list and the // count/boundary metadata that decide which records are inside the window // and therefore present in the wrapped vector index. // Matches Java's FDBRecordStoreKeyspace.INDEX_SLIDING_WINDOW_SPACE. // // Java keeps this separate from the SECONDARY space deliberately — its own // comment says "to avoid collisions with delegate index types that also use // the secondary subspace (e.g. rank, permuted min/max, text)" — and Go now // writes here for the same reason, from slidingWindowIndexMaintainer, which // decorates a VECTOR index carrying a row-number window predicate. // // Note the time-window LEADERBOARD index is a different type and does NOT use // this space in either engine: Java's TimeWindowLeaderboardIndexMaintainer // uses getSecondarySubspace() at every call site, which is what Go does too. IndexSlidingWindowSpaceKey = 10 )
Subspace keys used by the Record Layer to organize data within FDB. These MUST match the Java implementation for compatibility. Verified against Java: FDBRecordStoreKeyspace.java (enum values 0-10).
The enum is Java's to EXTEND — it is @API(UNSTABLE) and has grown before — so every value it defines is reserved here even when Go writes nothing to it. An unreserved prefix is one nothing is guarding: the next feature that wants a place to put bytes inside a record store would take it and collide with a Java release. TestRecordStoreKeyspaceMatchesJava pins the whole set.
const ( IndexTypeValue = "value" IndexTypeCount = "count" IndexTypeCountNotNull = "count_not_null" IndexTypeCountUpdates = "count_updates" IndexTypeSum = "sum" IndexTypeMaxEverLong = "max_ever_long" IndexTypeMinEverLong = "min_ever_long" IndexTypeMaxEverTuple = "max_ever_tuple" IndexTypeMinEverTuple = "min_ever_tuple" IndexTypeRank = "rank" IndexTypeVersion = "version" IndexTypeMaxEverVersion = "max_ever_version" IndexTypePermutedMin = "permuted_min" IndexTypePermutedMax = "permuted_max" IndexTypeBitmapValue = "bitmap_value" IndexTypeText = "text" IndexTypeTimeWindowLeaderboard = "time_window_leaderboard" IndexTypeMultidimensional = "multidimensional" IndexTypeVector = "vector" // IndexTypeVectorSPFresh is the Go-only FDB-native vector index (RFC-094): // SPANN centroid + posting-list layout with two-level routing and SPFresh // incremental rebalancing. Java has no counterpart; deployments sharing // metadata with Java apps must keep this index out of shared metadata (a // Java app fails maintainer lookup for the unknown type). Records remain // fully Java-readable — the index writes only under its own subspace. IndexTypeVectorSPFresh = "vector_spfresh" // IndexTypeMinEver and IndexTypeMaxEver are the DEPRECATED bare spellings // that predate the _long/_tuple split. Java still accepts them and says // exactly why it cannot stop: "Deprecated for new usage, but this can't // really be removed because old meta-data might include it" // (IndexTypes.java:67-81). They are declared here for the same reason — // Java-authored metadata on a shared cluster may carry them, and this port // has to READ that metadata correctly. // // Java resolves each to its _LONG behaviour UNCONDITIONALLY: // getAtomicMutation returns MIN_EVER_LONG for `MIN_EVER_LONG || MIN_EVER` and // MAX_EVER_LONG for `MAX_EVER_LONG || MAX_EVER` // (AtomicMutationIndexMaintainer.java:100-106). There is no dependence on the // key type, and the doc comment on IndexTypes.MIN_EVER says the same thing // declaratively — "Compatible name for MIN_EVER_LONG". // // Never WRITE these. New metadata uses the _long or _tuple spelling; these // exist so old and Java-authored metadata resolves to the right maintainer // instead of falling off the end of a switch. IndexTypeMinEver = "min_ever" IndexTypeMaxEver = "max_ever" )
Index type constants matching Java's IndexTypes.
const ( IndexOptionUnique = "unique" IndexOptionClearWhenZero = "clearWhenZero" IndexOptionReplacedByPrefix = "replacedBy" IndexOptionBitmapValueEntrySize = "bitmapValueEntrySize" // TEXT index options matching Java's IndexOptions. IndexOptionTextTokenizerName = "textTokenizerName" IndexOptionTextTokenizerVersion = "textTokenizerVersion" IndexOptionTextAddAggressiveConflictRanges = "textAddAggressiveConflictRanges" IndexOptionTextOmitPositions = "textOmitPositions" // Runtime-only index option, always safe to change. // Matches Java's IndexOptions.ALLOWED_FOR_QUERY_OPTION. IndexOptionAllowedForQuery = "allowedForQuery" )
Index option keys matching Java's IndexOptions.
const ( IndexOptionRTreeMaxM = "rtreeMaximumM" IndexOptionRTreeMinM = "rtreeMinimumM" IndexOptionRTreeSplitS = "rtreeSplitS" // IndexOptionRTreeStorage controls the node storage strategy. // Matches Java's IndexOptions.RTREE_STORAGE. IndexOptionRTreeStorage = "rtreeStorage" // IndexOptionRTreeStoreHilbertValues controls whether Hilbert values are stored. // Matches Java's IndexOptions.RTREE_STORE_HILBERT_VALUES. IndexOptionRTreeStoreHilbertValues = "rtreeStoreHilbertValues" // IndexOptionRTreeUseNodeSlotIndex controls whether a node slot index is maintained. // Matches Java's IndexOptions.RTREE_USE_NODE_SLOT_INDEX. IndexOptionRTreeUseNodeSlotIndex = "rtreeUseNodeSlotIndex" )
R-tree index option keys for configuring the Hilbert R-tree.
const ( OrderFuncAscNullsFirst = "order_asc_nulls_first" OrderFuncAscNullsLast = "order_asc_nulls_last" OrderFuncDescNullsFirst = "order_desc_nulls_first" OrderFuncDescNullsLast = "order_desc_nulls_last" )
Order function names matching Java's OrderFunctionKeyExpressionFactory. Each name maps to a TupleOrdering.Direction encoding strategy.
const ( IndexOptionRankNLevels = "rankNLevels" IndexOptionRankHashFunction = "rankHashFunction" IndexOptionRankCountDuplicates = "rankCountDuplicates" )
Index option keys for RANK indexes. Matches Java's IndexOptions.RANK_*.
const ( FunctionNameRank = "rank" FunctionNameTimeWindowRank = "time_window_rank" FunctionNameTimeWindowRankAndEntry = "time_window_rank_and_entry" )
Record function name constants matching Java's FunctionNames.
const ( // VersionBytes is the total size of a record version. VersionBytes = 12 // GlobalVersionBytes is the size of the FDB versionstamp portion. GlobalVersionBytes = 10 // LocalVersionBytes is the size of the local version counter. LocalVersionBytes = 2 )
const ( MaxRecordContextTags = 5 MaxRecordContextTagLen = 16 )
Java's tag limits (FDBRecordContextConfig.java:661-672). These are STRICTER than the FDB client's own 5/255 (TagThrottle.actor.cpp:35-39): the record layer caps a tag at 16 characters, so a tag the client would accept can still be rejected here. Validation happens at config time, as in Java, so a bad tag fails before any transaction is opened rather than mid-commit.
const ( // IsolationLevelSnapshot uses snapshot reads, which see a consistent view of the database // at the time the transaction started. Snapshot reads do not conflict with writes. // // Java equivalent: SNAPSHOT IsolationLevelSnapshot IsolationLevel = iota // IsolationLevelSerializable uses serializable reads, which participate in conflict detection. // Serializable reads will cause conflicts if another transaction writes to the same keys. // // Java equivalent: SERIALIZABLE IsolationLevelSerializable // Legacy aliases for backwards compatibility SnapshotIsolation = IsolationLevelSnapshot SerializableIsolation = IsolationLevelSerializable )
const ( // IndexOptionSPFreshNumDimensions is the vector dimensionality. Required. IndexOptionSPFreshNumDimensions = "spfreshNumDimensions" // IndexOptionSPFreshMetric is the distance metric (EUCLIDEAN_METRIC, // COSINE_METRIC, DOT_PRODUCT_METRIC — same names the HNSW index accepts). IndexOptionSPFreshMetric = "spfreshMetric" // IndexOptionSPFreshLmax is the posting-list split threshold in entries. // Sized so one posting fits a single range-reply (REPLY_BYTE_LIMIT = 80 KB). IndexOptionSPFreshLmax = "spfreshLmax" // IndexOptionSPFreshLminRatio divides Lmax to produce the merge threshold. IndexOptionSPFreshLminRatio = "spfreshLminRatio" // IndexOptionSPFreshCellTarget is the fine-centroids-per-cell build target; // sized so one L2 cell load fits a single range-reply. IndexOptionSPFreshCellTarget = "spfreshCellTarget" // IndexOptionSPFreshCellMax is the coarse-split threshold in fine centroids. IndexOptionSPFreshCellMax = "spfreshCellMax" // IndexOptionSPFreshReplication is the closure replication cap r. IndexOptionSPFreshReplication = "spfreshReplication" // IndexOptionSPFreshAlpha is the RNG closure threshold: keep centroid c_i of // the r nearest iff dist(v,c_i) <= alpha * dist(v,c_1). Must be > 1.0 or // only the nearest centroid is ever admitted (effective r=1). IndexOptionSPFreshAlpha = "spfreshAlpha" // IndexOptionSPFreshKn is the NPA reassignment neighborhood (centroids). IndexOptionSPFreshKn = "spfreshKn" // IndexOptionSPFreshBuildAssignCells is the bulk-build wave-B assignment // width w_b (RFC-099): how many nearest coarse cells supply candidate fine // centroids when assigning an imported vector. Build-time only — it changes // which fine a vector is assigned to, never the on-disk format. Must be ≥ // the query probe width so build assignments are query-reachable. IndexOptionSPFreshBuildAssignCells = "spfreshBuildAssignCells" // IndexOptionSPFreshCooldownSec is the post-split merge cooldown. IndexOptionSPFreshCooldownSec = "spfreshCooldownSec" // IndexOptionSPFreshRaBitQNumExBits is the RaBitQ extended-bits parameter // for posting residual codes. IndexOptionSPFreshRaBitQNumExBits = "spfreshRaBitQNumExBits" // IndexOptionSPFreshSidecar enables the fp16 SIDECAR subspace. Default // true — and currently REQUIRED: the sidecar is not just the query // re-rank source, every rebalancer lifecycle reads it (split 2-means, // chunked drain, merge drain, GC re-home), so disabling it would brick // maintenance permanently. ValidateSPFreshConfig rejects false until a // source-record fallback exists for all of those paths. The option stays // (the wire layout reserves the choice); only the value is constrained. IndexOptionSPFreshSidecar = "spfreshSidecar" )
SPFresh index options (RFC-094 §10). All structural options are immutable for an existing index — enforced by the metadata-evolution validator — because the lifecycle invariants (topology, posting sizes, closure replication) are derived from them. Runtime knobs (probe width w, k_c, ε, re-rank C, refresh interval, rebalancer pacing) are deliberately NOT index options: they are query/maintenance-time parameters and are never stored.
const ( FunctionNameTimeWindowCount = "time_window_count" FunctionNameScoreForTimeWindowRank = "score_for_time_window_rank" FunctionNameScoreForTimeWindowRankElseSkip = "score_for_time_window_rank_else_skip" FunctionNameTimeWindowRankForScore = "time_window_rank_for_score" )
Aggregate function name constants for TIME_WINDOW_LEADERBOARD.
const AllTimeLeaderboardType = 0
AllTimeLeaderboardType is the type value for the all-time leaderboard. Matches Java's TimeWindowLeaderboard.ALL_TIME_LEADERBOARD_TYPE.
const DefaultCollectScannedBytesLimit int64 = 16 << 20
DefaultCollectScannedBytesLimit is the per-batch read bound when CollectOptions.ScannedBytesLimit is zero. Exported for the same reason as DefaultCollectTimeLimit. Generous enough that an ordinary batch never reaches it, small enough that a batch of split multi-hundred-KB records stops long before the time limit would have to.
const DefaultCollectTimeLimit = 3 * time.Second
DefaultCollectTimeLimit is the per-batch time bound when CollectOptions.TimeLimit is zero. It leaves room under FDB's 5s transaction limit for the read-version fetch and the commit around the scan itself.
Exported so an operator-facing description of collection can RENDER the bound rather than restate it: a help text carrying a hand-typed "3s" goes stale the first time this changes, and says so to the one reader who cannot check it.
const DefaultMaterializationLimit = 100_000
const DefaultTextTokenizerName = "default"
DefaultTextTokenizerName is the name of the default tokenizer.
const FunctionNameCardinality = "cardinality"
FunctionNameCardinality is the registry name for the CARDINALITY() key expression. Matches Java's FunctionNames.CARDINALITY ("cardinality") byte for byte — the proto Function.name written for a cardinality-keyed index is identical across engines, so a Go-written cardinality index round-trips wire-compatibly with Java.
const (
FunctionNameVersion = "version"
)
Store function name constants matching Java's FunctionNames.
const GlobalMinVersion = 0
GlobalMinVersion is the absolute minimum tokenizer version. All tokenizers should begin at this version. Matches Java's TextTokenizer.GLOBAL_MIN_VERSION.
const GroupCountCompanionSuffix = "__GROUP_COUNT"
GroupCountCompanionSuffix is reserved on user-supplied index names. The DDL derives a companion COUNT(*) index's name by appending it to the owning index's name, so the name is deterministic: two stores built from the same DDL must contain the same stored bytes, which a randomized or counter-based name would break.
Reserving it narrows the DDL surface relative to Java, which accepts any name. That is deliberate and is the lesser of two evils: without reservation, create-if-absent could collide with a pre-existing user index that carries the derived name but a different structure, and the user would see a duplicate-name error at schema-creation time rather than at the point they chose the name.
The reservation applies at CREATE ONLY, never at load. A schema that already contains an index whose name ends with the suffix — written by Java, or by an older Go binary — must open and read normally. Companion matching is structural and the name carries no semantic weight, so such a name is inert at read time and there is nothing to reject; rejecting at load would let this design render an existing Java-written schema unreadable.
const IndexOptionHNSWEfConstruction = "hnswEfConstruction"
IndexOptionHNSWEfConstruction specifies the search factor used during index construction. Matches Java's IndexOptions.HNSW_EF_CONSTRUCTION.
const IndexOptionHNSWEfRepair = "hnswEfRepair"
IndexOptionHNSWEfRepair specifies the search factor used during repair operations. Matches Java's IndexOptions.HNSW_EF_REPAIR.
const IndexOptionHNSWM = "hnswM"
IndexOptionHNSWM specifies the connectivity factor M for the HNSW graph. Matches Java's IndexOptions.HNSW_M.
const IndexOptionHNSWMMax = "hnswMMax"
IndexOptionHNSWMMax specifies the maximum number of connections for non-zero layers. Matches Java's IndexOptions.HNSW_M_MAX.
const IndexOptionHNSWMMax0 = "hnswMMax0"
IndexOptionHNSWMMax0 specifies the maximum number of connections for layer 0. Matches Java's IndexOptions.HNSW_M_MAX_0.
const IndexOptionHNSWMaintainStatsProbability = "hnswMaintainStatsProbability"
IndexOptionHNSWMaintainStatsProbability controls the probability of maintaining stats. Runtime-only option, safe to change without rebuild. Matches Java's IndexOptions.HNSW_MAINTAIN_STATS_PROBABILITY.
const IndexOptionHNSWMaxNumConcurrentDeleteFromLayer = "hnswMaxNumConcurrentDeleteFromLayer"
IndexOptionHNSWMaxNumConcurrentDeleteFromLayer controls the maximum number of concurrent layer deletions during deletion of a record. Stored for Java round-trip compatibility. Matches Java's IndexOptions.HNSW_MAX_NUM_CONCURRENT_DELETE_FROM_LAYER.
const IndexOptionHNSWMaxNumConcurrentNeighborhoodFetches = "hnswMaxNumConcurrentNeighborhoodFetches"
IndexOptionHNSWMaxNumConcurrentNeighborhoodFetches controls the maximum number of concurrent neighborhood fetches during insert when neighbors are pruned. Stored for Java round-trip compatibility. Matches Java's IndexOptions.HNSW_MAX_NUM_CONCURRENT_NEIGHBORHOOD_FETCHES.
const IndexOptionHNSWMaxNumConcurrentNodeFetches = "hnswMaxNumConcurrentNodeFetches"
IndexOptionHNSWMaxNumConcurrentNodeFetches controls the maximum number of concurrent node fetches during search and modification operations. In Go's synchronous model this is not used for concurrency control, but is stored for Java round-trip compatibility. Matches Java's IndexOptions.HNSW_MAX_NUM_CONCURRENT_NODE_FETCHES.
const IndexOptionHNSWRaBitQNumExBits = "hnswRaBitQNumExBits"
IndexOptionHNSWRaBitQNumExBits specifies the number of extra bits for RaBitQ. Matches Java's IndexOptions.HNSW_RABITQ_NUM_EX_BITS.
const IndexOptionHNSWSampleVectorStatsProbability = "hnswSampleVectorStatsProbability"
IndexOptionHNSWSampleVectorStatsProbability controls the probability of sampling vector stats. Runtime-only option, safe to change without rebuild. Matches Java's IndexOptions.HNSW_SAMPLE_VECTOR_STATS_PROBABILITY.
const IndexOptionHNSWStatsThreshold = "hnswStatsThreshold"
IndexOptionHNSWStatsThreshold specifies the minimum number of vectors for stats. Runtime-only option, safe to change without rebuild. Matches Java's IndexOptions.HNSW_STATS_THRESHOLD.
const IndexOptionHNSWUseInlining = "hnswUseInlining"
IndexOptionHNSWUseInlining controls whether vector data is inlined into the HNSW node. Matches Java's IndexOptions.HNSW_USE_INLINING.
const IndexOptionHNSWUseRaBitQ = "hnswUseRaBitQ"
IndexOptionHNSWUseRaBitQ enables RaBitQ quantization for approximate nearest neighbor. Matches Java's IndexOptions.HNSW_USE_RABITQ.
const IndexOptionPermutedSize = "permutedSize"
IndexOptionPermutedSize specifies how many trailing grouping fields are permuted to after the value in the secondary index subspace. Matches Java's IndexOptions.PERMUTED_SIZE_OPTION.
const IndexOptionVectorExtendCandidates = "hnswExtendCandidates"
IndexOptionVectorExtendCandidates controls whether the candidate set is extended with neighbors-of-neighbors during neighbor selection (2nd-degree exploration). Matches Java's IndexOptions.HNSW_EXTEND_CANDIDATES.
const IndexOptionVectorKeepPrunedConnections = "hnswKeepPrunedConnections"
IndexOptionVectorKeepPrunedConnections controls whether pruned candidates are added back to fill up to M neighbors when the heuristic selection produces too few. Matches Java's IndexOptions.HNSW_KEEP_PRUNED_CONNECTIONS.
const IndexOptionVectorMetric = "hnswMetric"
IndexOptionVectorMetric specifies the distance metric. Matches Java's IndexOptions.HNSW_METRIC.
const IndexOptionVectorNumDimensions = "hnswNumDimensions"
IndexOptionVectorNumDimensions specifies the number of vector dimensions. Matches Java's IndexOptions.HNSW_NUM_DIMENSIONS.
const StatisticsFormatVersion = 1
StatisticsFormatVersion is written with every entry so a reader can refuse a layout it does not understand rather than misparse one. Bump it when the tuple below changes shape; readers reject anything they do not recognise.
Variables ¶
var ( CountSWItemAddedToWindowFilling = Event{"sw_item_added_to_window_filling", "item added to window while filling up", KindCount} CountSWItemAddedToEntriesOnly = Event{"sw_item_added_to_entries_only", "item worse than boundary added to entries", KindCount} CountSWDeleteUntracked = Event{"sw_delete_untracked", "delete called for untracked record", KindCount} CountSWOverflowEntryDeleted = Event{"sw_overflow_entry_deleted", "overflow entry deleted from entries", KindCount} CountSWWindowEntryDeleted = Event{"sw_window_entry_deleted", "in-window non-boundary entry deleted", KindCount} CountSWItemPromotedFromOverflow = Event{"sw_item_promoted_from_overflow", "item promoted from overflow into window", KindCount} CountSWWindowShrunkNoOverflow = Event{"sw_window_shrunk_no_overflow", "window shrunk: no overflow available for re-election", KindCount} CountSWPartitionEmptied = Event{"sw_partition_emptied", "partition emptied (no entries remain)", KindCount} CountSWEvictedRecordMissing = Event{"sw_evicted_record_missing", "boundary record could not be loaded for eviction", KindCount} CountSWPromotedRecordMissing = Event{"sw_promoted_record_missing", "overflow record could not be loaded for promotion", KindCount} CountSWPreemptiveDeleteWriteOnly = Event{"sw_preemptive_delete_write_only", "preemptive delete during write-only index build", KindCount} CountSWPartitionCleared = Event{"sw_partition_cleared", "partition cleared via deleteWhere", KindCount} EventSWEvictAndReplace = Event{"sw_evict_and_replace", "evict boundary and insert better entry", KindTimed} EventSWReElectFromOverflow = Event{"sw_re_elect_from_overflow", "re-elect overflow entry into window", KindTimed} EventSWBoundaryRescanAfterEvict = Event{"sw_boundary_rescan_after_evict", "rescan to locate new boundary after eviction", KindTimed} EventSWBoundaryRescanAfterDelete = Event{"sw_boundary_rescan_after_delete", "rescan to locate new boundary after boundary delete", KindTimed} EventSWDelegateInsert = Event{"sw_delegate_insert", "insert into the delegate index", KindTimed} EventSWDelegateDelete = Event{"sw_delegate_delete", "delete from the delegate index", KindTimed} SizeSWWindowCount = Event{"sw_window_count", "window count after update", KindSizeDistribution} )
Instrumentation for the sliding window, matching Java's SlidingWindowIndexMaintainer.SlidingWindowCounter / SlidingWindowEvent / SlidingWindowSizeEvent enums (:722-792) name for name.
var ( // Query path. EventSPFreshSearch = Event{"spfresh_search", "SPFresh Search", KindTimed} // Probed/pruned: the Eq.(3) pruning decomposition per search — probed // lists cost range reads, pruned ones were skipped. CountSPFreshPostingsProbed = Event{"spfresh_postings_probed", "SPFresh Postings Probed", KindCount} CountSPFreshPostingsPruned = Event{"spfresh_postings_pruned", "SPFresh Postings Pruned", KindCount} CountSPFreshEntriesScanned = Event{"spfresh_entries_scanned", "SPFresh Entries Scanned", KindCount} CountSPFreshRerankReads = Event{"spfresh_rerank_reads", "SPFresh Rerank Reads", KindCount} CountSPFreshStarvationWiden = Event{"spfresh_starvation_widenings", "SPFresh Starvation Widenings", KindCount} CountSPFreshForwardFollows = Event{"spfresh_forward_follows", "SPFresh Forward Follows", KindCount} // Phase 2 reached: the VBASE relaxed-monotonicity termination (M_q^s > R_q) // latched during a one-shot search's traversal — the recently-traversed cells // no longer beat the running k-th best (RFC-156 Phase A). PURE TELEMETRY on // the one-shot wrapper path: nothing consults f.phase2 as a stop signal (it // does not truncate the exact horizon). The resumable Phase B/C streaming // cursor does NOT consult phase2 — it terminates on the relaxed-monotonicity // EMISSION BARRIER plus the budget/exhaustion caps (spfresh_stream.go), and // it never calls refreshPhase2, so this counter NEVER increments on a streaming // query (the SHARED searchInit probe still feeds observe(), but the streaming // WIDEN bursts gate it off — scoreCells, f.reranked==nil — since those queues // are dead weight once nothing will read phase2). CountSPFreshPhase2Reached = Event{"spfresh_phase2_reached", "SPFresh Phase 2 Reached", KindCount} // Capped posting reads: a search's posting fetch returned exactly the // 4×Lmax+1 cap — the posting is PAST the split-dispatch envelope and its // tail is invisible to queries. Nonzero means a split trigger was lost // (the read path re-files it; see CountSPFreshReadPathSplitFiles). CountSPFreshCappedPostingReads = Event{"spfresh_capped_posting_reads", "SPFresh Capped Posting Reads", KindCount} // Split tasks re-filed from the read path after a capped read found an // over-envelope posting with no pending split. CountSPFreshReadPathSplitFiles = Event{"spfresh_readpath_split_files", "SPFresh Read-Path Split Files", KindCount} // Stream widen batches: each demand-driven widening step of the RFC-156 // Phase C ordered-stream cursor (a batch of ε-pruned/re-routed cells admitted // in d2 order because the consumer above drained the finalized prefix and // pulled for more). Batched, never one-cell-serial. CountSPFreshStreamWiden = Event{"spfresh_stream_widenings", "SPFresh Stream Widenings", KindCount} // Filtered truncation: the RFC-156 Phase C ordered-stream cursor hit its // budget cap (max cells probed / max candidates) BEFORE the consumer was // satisfied, and returned NoNextReason.ScanLimitReached + a positional // continuation rather than a silent < k. This is telemetry IN ADDITION to the // reason (RFC-156 §C) — the reason is the contract, this counts // how often the budget bound a filtered KNN. CountSPFreshFilteredTruncated = Event{"spfresh_filtered_truncated", "SPFresh Filtered Truncations", KindCount} // Write path. EventSPFreshInsert = Event{"spfresh_insert", "SPFresh Insert", KindTimed} CountSPFreshInsertFenceReads = Event{"spfresh_insert_fence_reads", "SPFresh Insert Fence Reads", KindCount} CountSPFreshInsertReplicas = Event{"spfresh_insert_replicas", "SPFresh Insert Replicas", KindCount} CountSPFreshStaleRouteRetry = Event{"spfresh_stale_route_retries", "SPFresh Stale Route Retries", KindCount} // Maintenance (rebalancer / sweeper). CountSPFreshSplits = Event{"spfresh_splits", "SPFresh Splits", KindCount} CountSPFreshMerges = Event{"spfresh_merges", "SPFresh Merges", KindCount} CountSPFreshCSplits = Event{"spfresh_csplits", "SPFresh Coarse Splits", KindCount} CountSPFreshNPAs = Event{"spfresh_npas", "SPFresh NPA Reassignments", KindCount} CountSPFreshZombieCleans = Event{"spfresh_zombie_cleans", "SPFresh Zombie Cleanups", KindCount} CountSPFreshCSplitDefers = Event{"spfresh_csplit_defers", "SPFresh Coarse Split Deferrals", KindCount} CountSPFreshLeaseSkips = Event{"spfresh_lease_skips", "SPFresh Lease Skips", KindCount} // Assignment refinement (RFC-104) fleet pass: vectors re-routed against the // converged topology, and tenants whose cursor wrapped a full cycle moving // nothing. Moves trending to zero while Converged rises = the fleet has // recovered ingest recall-drift and is quiescing; sustained nonzero Moves = // ongoing drift (e.g. a steady fast-ingest tenant) the refinement loop is // absorbing. CountSPFreshRefineMoves = Event{"spfresh_refine_moves", "SPFresh Refinement Moves", KindCount} CountSPFreshRefineConverged = Event{"spfresh_refine_converged", "SPFresh Refinement Converged Tenants", KindCount} // Task handler errors in a rebalance pass: the pass SKIPS the failed // task and continues (a poisoned task at the deterministic queue head // must not starve everything behind it), then surfaces the joined // errors. Nonzero here with a stable queue depth = a poisoned task; the // runbook's "task queue growing" playbook keys off it. CountSPFreshTaskErrors = Event{"spfresh_task_errors", "SPFresh Task Errors", KindCount} )
SPFresh instrumentation events, recorded into the context's StoreTimer — the same FDBStoreTimer idiom every other index uses (the TEXT index's InstrumentedBunchedMap is the precedent). StoreTimer methods are nil-receiver-safe, so an uninstrumented context costs one nil check per site and SPFresh internals thread the timer unconditionally.
Timed events record nanoseconds; counts record occurrences or sized quantities. These are the operator-facing signals the index needs in production: query cost decomposition (probed/pruned/scanned/reranked), write-path health (fence reads, replicas, stale-route retries), and maintenance progress (per-kind lifecycle actions, zombie cleanups, lease skips). Scrape via StoreTimer.Snapshot().
var ( EventSaveRecord = Event{"save_record", "Save Record", KindTimed} EventLoadRecord = Event{"load_record", "Load Record", KindTimed} EventDeleteRecord = Event{"delete_record", "Delete Record", KindTimed} EventCommit = Event{"commit", "Commit", KindTimed} EventGetReadVersion = Event{"get_read_version", "Get Read Version", KindTimed} EventScanRecords = Event{"scan_records", "Scan Records", KindTimed} EventScanIndex = Event{"scan_index", "Scan Index", KindTimed} EventOpenStore = Event{"open_store", "Open Store", KindTimed} EventRebuildIndex = Event{"rebuild_index", "Rebuild Index", KindTimed} )
Standard timed events — matching Java's FDBStoreTimer.Events.
EventOpenStore is the one entry with no Java Events counterpart: Java splits store opening into Counts.OPEN_CONTEXT (FDBStoreTimer.java:510) plus the timed Events.CHECK_VERSION (:198) and Events.LOAD_RECORD_STORE_STATE (:103). Go times the whole open as one event.
var ( CountSaveRecordKey = Event{"save_record_key", "Save Record Key", KindCount} CountSaveRecordKeyBytes = Event{"save_record_key_bytes", "Save Record Key Bytes", KindSize} CountSaveRecordValueBytes = Event{"save_record_value_bytes", "Save Record Value Bytes", KindSize} CountDeleteRecordKey = Event{"delete_record_key", "Delete Record Key", KindCount} CountDeleteRecordKeyBytes = Event{"delete_record_key_bytes", "Delete Record Key Bytes", KindSize} CountReads = Event{"reads", "Reads", KindCount} CountWrites = Event{"writes", "Writes", KindCount} CountBytesRead = Event{"bytes_read", "Bytes Read", KindSize} CountBytesWritten = Event{"bytes_written", "Bytes Written", KindSize} // Index-level count events — matching Java's FDBStoreTimer.Counts for index ops. // Used by InstrumentedBunchedMap (TEXT index) and other index maintainers. CountSaveIndexKey = Event{"save_index_key", "Save Index Key", KindCount} CountSaveIndexKeyBytes = Event{"save_index_key_bytes", "Save Index Key Bytes", KindSize} CountSaveIndexValueBytes = Event{"save_index_value_bytes", "Save Index Value Bytes", KindSize} CountLoadIndexKey = Event{"load_index_key", "Load Index Key", KindCount} CountLoadIndexKeyBytes = Event{"load_index_key_bytes", "Load Index Key Bytes", KindSize} CountLoadIndexValueBytes = Event{"load_index_value_bytes", "Load Index Value Bytes", KindSize} CountDeleteIndexKey = Event{"delete_index_key", "Delete Index Key", KindCount} CountDeleteIndexKeyBytes = Event{"delete_index_key_bytes", "Delete Index Key Bytes", KindSize} CountDeleteIndexValueBytes = Event{"delete_index_value_bytes", "Delete Index Value Bytes", KindSize} )
Standard count events — matching Java's FDBStoreTimer.Counts. The KindSize entries are the ones whose Java constant is declared with isSize()==true.
var ( // OrderAscNullsFirst: ascending order, nulls sort first (default tuple behavior). OrderAscNullsFirst = OrderDirection{/* contains filtered or unexported fields */} // OrderAscNullsLast: ascending order, nulls sort last (0xFE encoding). OrderAscNullsLast = OrderDirection{/* contains filtered or unexported fields */} // OrderDescNullsFirst: descending order, nulls sort first. OrderDescNullsFirst = OrderDirection{/* contains filtered or unexported fields */} // OrderDescNullsLast: descending order, nulls sort last. OrderDescNullsLast = OrderDirection{/* contains filtered or unexported fields */} )
The four order directions matching Java's TupleOrdering.Direction enum values.
var TupleRangeAll = TupleRange{ LowEndpoint: EndpointTypeTreeStart, HighEndpoint: EndpointTypeTreeEnd, }
TupleRangeAll covers all entries in the index. Matches Java's TupleRange.ALL.
Functions ¶
func AbsolutizeFieldTypeNames ¶
func AbsolutizeFieldTypeNames(fd *descriptorpb.FileDescriptorProto)
AbsolutizeFieldTypeNames is the exported form of absolutizeFieldTypeNames, for builders that retain a Java-shaped (relative-name) proto but need a protodesc-buildable clone.
IT TAKES NO DEPENDENCY SET, and that is deliberate rather than an oversight mirroring the unexported form's variadic tail -- the question is worth answering here because the sole caller (pkg/relational/core/metadata's buildFileDescriptor) holds two protoreflect.FileDescriptors two lines before calling this and visibly does not pass them.
It does not need to. That caller sets fd.Dependency to `tuple_fields.proto` and `record_metadata_options.proto`, both of which are generated Go and therefore in protoregistry.GlobalFiles, so absolutizeFieldTypeNames resolves and seeds them through the global-registry loop -- the same route stored metadata takes for the dependencies defaultExcludedDependencies strips. Threading them in explicitly as well would seed the identical symbols twice.
A caller whose dependencies are NOT globally registered must use the unexported form and pass them, or the walk will not see their types.
func AsList ¶
func AsList[T any](ctx context.Context, cursor RecordCursor[T]) ([]T, error)
AsList collects all records from the cursor into a slice
func AsListWithContinuation ¶
func AsListWithContinuation[T any](ctx context.Context, cursor RecordCursor[T]) ([]T, []byte, error)
AsListWithContinuation collects all records from the cursor into a slice and returns the final continuation bytes for pagination. Returns nil continuation when the source is exhausted. This is the common pattern for paginated APIs: drain page, return token.
func BuildSPFreshIndex ¶
func BuildSPFreshIndex(ctx context.Context, db *FDBDatabase, storeBuilder func(*FDBRecordContext) (*FDBRecordStore, error), indexName string, seed int64) error
BuildSPFreshIndex bulk-builds an SPFresh index over the store's existing records (RFC-094 §8) and flips it readable. The §8 step order is the foreground-interleaving contract: the COARSE table commits BEFORE the assignment scan, so every record save thereafter can route itself (UpdateWhileWriteOnly stages or goes live by cellfin state), and every record saved before it is covered by the assignment scan's later read versions. Double coverage (a save the scan also reads) is harmless — staging writes are idempotent Sets on the same key.
func CheckValidProtoBufCompliantName ¶
CheckValidProtoBufCompliantName validates that name is a legal protobuf identifier. See protoname.CheckValidProtoBufCompliantName.
func CleanupAllHeartbeats ¶
func CleanupAllHeartbeats(tx fdb.WritableTransaction, storeSubspace subspace.Subspace, index *Index)
CleanupAll removes ALL heartbeats for an index. Used during index rebuild or full clear operations.
func ClearStatistics ¶
func ClearStatistics( ctx context.Context, db *FDBDatabase, stats StatisticsSubspace, storeSubspace subspace.Subspace, tags ...string, ) error
ClearStatistics removes a store's statistics.
func DecodeOnceIfReversible ¶
DecodeOnceIfReversible decodes a stored name to its SQL identifier only when the result provably re-encodes. See protoname.DecodeOnceIfReversible.
func DeleteStore ¶
func DeleteStore(ctx *FDBRecordContext, ss subspace.Subspace) error
DeleteStore completely removes all data in a store subspace. Matches Java's FDBRecordStore.deleteStore(context, subspace).
func FindRegisteredMessageType ¶
func FindRegisteredMessageType(fullName protoreflect.FullName) protoreflect.MessageType
FindRegisteredMessageType returns the message type registered for fullName in the process-global protobuf registry (protoregistry.GlobalTypes) — the GENERATED Go type (e.g. *gen.Order) — or nil when the name is not registered (a dynamic, metadata-built schema type). This is the same registry-first policy Build applies to record-type message factories above: a caller that rebuilds a proto value from serialized bytes must prefer the generated type so the restored value has the SAME concrete Go type as a freshly-read record, falling back to dynamicpb over metadata descriptors only for dynamic schemas (where fresh records are dynamicpb too).
func First ¶
func First[T any](ctx context.Context, cursor RecordCursor[T]) (*T, error)
First returns the first element from a cursor, or nil if empty. Matches Java's RecordCursor.first().
func GetCount ¶
GetCount returns the number of elements in a cursor by consuming it. Matches Java's RecordCursor.getCount().
func GroupCountCompanionName ¶
GroupCountCompanionName derives the companion COUNT(*) index's name from the name of the aggregate index it serves.
func GroupingSignature ¶
func GroupingSignature(g *GroupingKeyExpression) []byte
GroupingSignature returns a normalized, deterministic encoding of an index's grouping key expression. Two aggregate indexes group identically iff their signatures are byte-equal, which is what makes companion discovery structural (RFC-209 §5.2) rather than a stored reference.
The encoding is the grouping key expression's proto with proto2 defaults cleared, marshalled deterministically — the same normalization the wire conformance test applies before comparing Go's index metadata against Java's. Clearing defaults matters because Java materializes fields Go leaves unset, so a Java-written index and a Go-written one can describe the same grouping with different bytes.
Returns nil when no signature can be derived; callers must treat nil as "no companion match", never as "matches everything".
func IsGroupCountCompanionFor ¶
func IsGroupCountCompanionFor(idx *Index, groupingSignature, predicateSignature []byte, recordTypeNames []string, md *RecordMetaData) bool
IsGroupCountCompanionFor reports whether idx is a COUNT(*) index that can act as the group-existence companion of an index with the given grouping signature and predicate signature, over the given record types.
Structural only: the name is never consulted, so a companion created by an older binary under a different name, or declared by the user, matches just as well as one this binary would emit.
func IsPermutedMinIndex ¶
IsPermutedMinIndex reports whether idx is the MIN flavour of the permuted index, the only one whose stored extremum can be a NULL that hides real values. Callers use it to keep the repair off the MAX flavour, where a stored NULL is the correct answer.
func IsRecordTypeExpression ¶
func IsRecordTypeExpression(expr KeyExpression) bool
IsRecordTypeExpression checks if a key expression starts with record type
func KeyExpressionHasRecordTypePrefix ¶
func KeyExpressionHasRecordTypePrefix(expr KeyExpression) bool
KeyExpressionHasRecordTypePrefix is the exported form of the per-expression prefix check. Used by the SQL layer's covering-index pushdown to decide how to slice a primary-key tuple (first element is the record-type key when true).
func LiteralToProtoValue ¶
LiteralToProtoValue serializes a Go literal into the key-expression Value proto encoding — Java's LiteralKeyExpression.toProtoValue (LiteralKeyExpression.java:176-197). Exported for the index-predicate producer (RFC-202 S5): a SimpleComparison's operand is stored in exactly this encoding (IndexComparison.java:253).
func LoadIndexStates ¶
func LoadIndexStates(tx fdb.ReadTransaction, ss subspace.Subspace) (map[string]IndexState, error)
LoadIndexStates reads a record store's index-state map from a READ transaction, without opening the store. Only states that differ from the default are stored, so an absent index is READABLE — the same contract FDBRecordStore.GetIndexState applies (and Java's RecordStoreState).
It exists because the QUERY PLANNER needs index states before any store is open: Java assembles its planner's readable-index view from the store state it already holds (PlanContext.java:236-247), while Go plans from metadata alone and reaches FDB only at execution. Opening a full store just to read four bytes per exceptional index would pull in the header, the metadata version check and the store lock; this reads the one range it needs.
func MBRToTuple ¶
MBRToTuple serializes an MBR to a flat tuple [low0, ..., lowN-1, high0, ..., highN-1]. Matches Java's ChildSlot MBR serialization.
func NeedsGroupCountCompanion ¶
NeedsGroupCountCompanion reports whether idx is a GROUPED aggregate index whose own key set can neither prove nor disprove that a group exists, so it needs a companion COUNT(*) to answer correctly (RFC-209 §5.2).
SUM and COUNT(col) qualify: a stored zero is indistinguishable from a vacated group, and an all-NULL group has no entry at all. A COUNT(*) index does not — it is its own oracle (§5.3(a)). MIN/MAX do not — they keep a real per-record entry that the record's deletion removes. The UNGROUPED spelling does not — its single group exists whether or not the table has rows (§5.4).
func NewHNSWGraph ¶
func NewHNSWGraph(storage *hnswStorage, config HNSWConfig) *hnswGraph
NewHNSWGraph creates a new HNSW graph.
func PermutedMinIgnoringNulls ¶
func PermutedMinIgnoringNulls( ctx context.Context, scan OrdinaryIndexScanFunc, indexName string, groupKey tuple.Tuple, valueStart, valueEnd int, callerProps ExecuteProperties, ) (tuple.Tuple, error)
PermutedMinIgnoringNulls returns the smallest NON-NULL value of one group of a PERMUTED_MIN index, or nil when the group holds no non-NULL value at all (in which case SQL MIN is genuinely NULL).
It reads the index's ORDINARY subspace, whose entries are (grouping..., grouped..., primaryKey...) in key order. Every NULL-valued entry of the group shares the prefix (groupKey..., NULL), so an exclusive low endpoint on that prefix seeks past the whole NULL run in one operation — the answer is then the first entry returned, whatever the group's NULL count.
groupKey is the group in ORIGINAL column order (not the permuted order the secondary subspace stores). valueStart/valueEnd bound the aggregated columns within an ordinary entry's key.
func PredicateSignature ¶
PredicateSignature returns a normalized, deterministic encoding of an index's sparse (WHERE) predicate, or nil for a dense index.
A companion must count exactly the rows the owning aggregate index summed. A dense COUNT(*) over a SPARSE SUM lists groups the owner never saw, so driving the merge from it invents groups; a sparse COUNT(*) whose predicate differs from the owner's does the same for a different set. Comparing the serialized predicate is the only structural way to tell those apart, since the predicate is exactly what changes which rows the maintainer wrote.
RFC-209 §5.2 defines the structural match on the grouping key alone. That is incomplete for sparse indexes; this file therefore matches on grouping key AND predicate. The RFC's rationale (matching is structural, never a stored reference) is untouched — the predicate is itself stored structure.
Programmatic Go predicates have no proto and therefore no signature; they return a distinct opaque marker so they can never compare equal to a dense index nor to any serialized predicate.
func ReadHeartbeats ¶
func ReadHeartbeats(tx fdb.ReadTransaction, storeSubspace subspace.Subspace, index *Index) ([]*gen.IndexBuildHeartbeat, []string, error)
ReadHeartbeats reads all heartbeats for an index. Useful for diagnostics.
func ReadStatisticsAtWithRefusal ¶
func ReadStatisticsAtWithRefusal( ctx context.Context, db *FDBDatabase, stats StatisticsSubspace, storeSubspace subspace.Subspace, tags ...string, ) (StoreStatistics, StatisticsReadRefusal, int64, error)
ReadStatisticsAt is ReadStatistics plus the cluster version the read was taken at, from the SAME transaction.
The freshness gate needs both, and taking them separately costs a second round-trip on every uncached plan — for two numbers that are only meaningful relative to each other. Reading them together also removes a real (if narrow) window in which the entry could be replaced between the two reads, which would compare one run's stamp against a version drawn after another run.
func RebalanceSPFreshIndex ¶
func RebalanceSPFreshIndex(ctx context.Context, db *FDBDatabase, storeBuilder func(*FDBRecordContext) (*FDBRecordStore, error), indexName string) (int, error)
RebalanceSPFreshIndex drains the index's task queue to quiescence: scan, act, repeat until a round acts on nothing (splits enqueue NPA follow-ups, so multiple rounds are normal). Bounded against pathological re-triggering. Returns the total number of lifecycle actions taken.
func Reduce ¶
func Reduce[T any, R any](ctx context.Context, cursor RecordCursor[T], initial R, fn func(R, T) R) (R, error)
Reduce folds all cursor values into a single result using the given function. Matches Java's RecordCursor.reduce().
func RefineSPFreshIndex ¶
func RefineSPFreshIndex(ctx context.Context, db *FDBDatabase, storeBuilder func(*FDBRecordContext) (*FDBRecordStore, error), indexName string, budget int) (int, bool, error)
RefineSPFreshIndex runs ONE budgeted refinement pass over the index (RFC-104): it advances the persistent round-robin cursor by up to `budget` vectors, re-routing each against the current topology and moving the stale ones to recover the closure replication fast ingest never fired. It does NOT drain to quiescence — the deployment runs it on its own cadence (a refinement loop beside the rebalancer loop). Returns (moves, cycleConverged): cycleConverged is true when this call wrapped the cursor AND the whole cycle since the last wrap moved nothing — the signal a caller uses to back off a converged tenant. It is NOT merely "this pass reached the end": a budgeted pass whose tail moves zero does not imply the cycle's earlier passes did.
func RefineSPFreshIndexAll ¶
func RefineSPFreshIndexAll(ctx context.Context, db *FDBDatabase, storeBuilder func(*FDBRecordContext) (*FDBRecordStore, error), indexName string) (int, error)
RefineSPFreshIndexAll is the exported one-shot validation entry (refine every vector once). Production callers use the budgeted RefineSPFreshIndex.
func RegisterFunction ¶
func RegisterFunction(name string, evaluator FunctionEvaluator)
RegisterFunction registers a named function evaluator in the global registry. Call this before building metadata that uses the function.
func RunSPFreshMaintenance ¶
func RunSPFreshMaintenance(ctx context.Context, db *FDBDatabase, opts SPFreshMaintenanceOptions) error
RunSPFreshMaintenance runs the maintenance loop until ctx is canceled, then returns nil. It does an immediate sweep on entry (so a freshly-started worker makes progress without waiting a full interval), then sweeps on SweepInterval and refines on RefineInterval. Per-pass results/errors flow to OnSweep / OnRefine; nothing here fails the loop. With no tenants it is a quiet no-op loop (each pass returns an empty result), so it is safe to start before the tenant list is populated.
func SPFreshAuditTrail ¶
SPFreshAuditTrail returns the recorded trail for a fineID.
func SPFreshDebugIntegrity ¶
func SPFreshDebugIntegrity(rtx *FDBRecordContext, store *FDBRecordStore, indexName string, sample int) string
SPFreshDebugIntegrity samples up to `sample` pks evenly from the index's OWN membership rows (no assumption about pk shape) and reports, for each, whether every membership target holds the posting entry and what state the target centroid is in. Diagnostics only: it streams the membership keyspace (O(index) reads) — never call it on a production write path.
func SPFreshDebugTopology ¶
func SPFreshDebugTopology(rtx *FDBRecordContext, store *FDBRecordStore, indexName string) string
SPFreshDebugTopology dumps an index's coarse/fine topology summary (benchmark/operational diagnostics).
func SPFreshDisableAudit ¶
func SPFreshDisableAudit()
SPFreshDisableAudit turns the audit log off and releases its memory. Flag first, then the map: a concurrent spfreshAudit that already passed the flag check still finds a (stale, discarded) map under the mutex.
func SPFreshEnableAudit ¶
func SPFreshEnableAudit()
SPFreshEnableAudit turns on the centroid audit log (diagnostics).
func SPFreshHasPendingMaintenance ¶
func SPFreshHasPendingMaintenance(ctx context.Context, db *FDBDatabase, storeBuilder func(*FDBRecordContext) (*FDBRecordStore, error), indexName string) (bool, error)
SPFreshHasPendingMaintenance reports whether the index has any pending maintenance task rows: one snapshot generation read + one limit-1 snapshot range read — the cheap probe that lets a sweeper skip idle tenants without paying a full task scan. Un-bootstrapped indexes have no work by definition.
func SafeDecoderOver ¶
SafeDecoderOver returns one decoding policy for a whole rendered output. See protoname.SafeDecoderOver.
func SamePredicateSignature ¶
SamePredicateSignature reports whether two predicate signatures denote the same row population. Two opaque markers are NOT equal: an unserializable predicate is unmatchable in principle, so it must decline against everything including another one.
func SerializeVector ¶
SerializeVector encodes a float64 vector into the on-disk byte format the HNSW vector index reads (RealVector.fromBytes). Exported so callers/tests can populate a record's vector column.
func ToProtoBufCompliantName ¶
ToProtoBufCompliantName escapes a user identifier into a protobuf-compliant name. See protoname.ToProtoBufCompliantName.
func ToUserIdentifier ¶
ToUserIdentifier reverses ToProtoBufCompliantName. See protoname.ToUserIdentifier.
func TranslatePrimaryKeyToValues ¶
func TranslatePrimaryKeyToValues( pk KeyExpression, normalizeName func(string) string, flowedType values.Type, ) []values.Value
TranslatePrimaryKeyToValues translates a common primary-key KeyExpression into a flat []values.Value that encodes STRUCTURE — record-type-key prefixes (RecordTypeValue) and completely resolved ordinal paths — the Go analog of Java's ScalarTranslationVisitor.translateKeyExpression used by PrimaryKeyProperty.visitIndexPlan (RFC-189 B3).
PK identity must compare by STRUCTURE, not by bare column names: Field("ID") and Concat(RecordTypeKey(), Field("ID")) share the flat name list ["ID"] but are DIFFERENT primary keys, and conflating them lets ImplementDistinctUnionRule dedup two union legs that must both survive (dropped rows — the exact hazard the by-name M5 was reverted for). The structural translation makes them unequal under values.ValuesStructurallyEqual.
Returns nil if any component is not translatable (fan-out, version, function, or any unrecognized key), or if flowedType cannot resolve the complete path — fail-safe: the property then abstains, disabling the dedup optimization rather than risking a wrong one. Field names are request metadata only; every published FieldValue is rooted in one exact QOV and carries the ordinal path resolved against flowedType. normalizeName maps a raw protobuf field name into the caller's namespace (the SQL layer uppercases; a nil transform means identity). The translated field names MUST live in the SAME namespace as the plan's ordering/column values or values.ValuesStructurallyEqual never matches and the dedup silently never fires (the field-casing mismatch that made the structural common-PK inert).
func ValidateEvolution ¶
func ValidateEvolution(oldMetaData, newMetaData *RecordMetaData) error
ValidateEvolution is a convenience function using the default (strictest) validator.
func ValidateHNSWConfig ¶
func ValidateHNSWConfig(c HNSWConfig) error
ValidateHNSWConfig validates the HNSW configuration. Matches Java's Config validation.
func ValidateRTreeConfig ¶
func ValidateRTreeConfig(config RTreeConfig) error
ValidateRTreeConfig validates the R-tree configuration parameters. Checks: MinM >= 1, MaxM >= 2, SplitS >= 1, NumDimensions >= 1, and S * MaxM >= (S+1) * MinM (split/fuse ratio constraint).
func ValidateSPFreshConfig ¶
func ValidateSPFreshConfig(c SPFreshConfig) error
ValidateSPFreshConfig enforces the invariants the RFC-094 lifecycle and sizing arguments depend on. Called by the maintainer at construction; a violation is a config error, never a silently degraded index.
func ValidateTags ¶
ValidateTags applies Java's setTags checks in Java's order — the COUNT first, then each tag's length (FDBRecordContextConfig.java:662-669). The order is observable: an over-long tag in an over-large set reports the count error. Note this is the opposite of the FDB client's TagSet::addTag, which checks length first because it validates one tag at a time rather than a whole set.
Returns the deduplicated tag set; Java's Set<String> collapses duplicates before the size check, so ("a","a","b") is two tags, not three.
func ValidateTokenizerVersion ¶
func ValidateTokenizerVersion(t TextTokenizer, version int) error
ValidateTokenizerVersion checks that the given version is within the tokenizer's supported range. Returns an error if out of bounds. Matches Java's TextTokenizer.validateVersion().
func WriteRecordMetaData ¶
func WriteRecordMetaData(meta *RecordMetaData, w io.Writer) error
WriteRecordMetaData serializes a RecordMetaData to the given writer in the canonical `com.apple.foundationdb.record.RecordMetaDataProto.MetaData` wire format — the same bytes FDBMetaDataStore writes into FDB.
Intended for apps with programmatic metadata that want to ship a .pb artifact alongside their binaries so operator tooling (e.g. `frl --meta-file`) can introspect the store without adopting FDBMetaDataStore. Typical use:
func main() {
meta := buildMyMetaData() // normal RecordMetaDataBuilder
f, err := os.Create("meta.pb")
// ... error handling ...
if err := recordlayer.WriteRecordMetaData(meta, f); err != nil { … }
}
The serialized MetaData includes the embedded `records` FileDescriptorProto and its transitive `dependencies`, so consumers don't need out-of-band access to the app's .proto files to decode records.
Types ¶
type AggregateFunctionNotSupportedError ¶
AggregateFunctionNotSupportedError is Java's AggregateFunctionNotSupportedException (thrown by FDBRecordStore.evaluateAggregateFunction, FDBRecordStore.java:2409-2412) — no readable, queryable index over the requested record types can evaluate the function.
It is a distinct type because callers branch on it: Java's IndexBuildState.loadIndexBuildStateAsync catches exactly this exception to report "total unknown" and lets every other failure propagate (IndexBuildState.java:76-82).
func (*AggregateFunctionNotSupportedError) Error ¶
func (e *AggregateFunctionNotSupportedError) Error() string
type BackendCapabilityError ¶
type BackendCapabilityError struct {
Op string // the unavailable operation, e.g. "CreateTransaction"
}
BackendCapabilityError is returned when an operation is not supported on the configured fdb backend. The libfdb_c escape hatch (RFC-109) drives the Run / RunRead gold path, standalone transactions (CreateWritableTransaction — used by the FDBDatabaseRunner and SQL BeginTx), and LocalityGetBoundaryKeys (online MUTUAL indexing) all through backend interfaces, so those work on libfdb_c. Only the pure-Go-typed CreateTransaction (which returns the concrete fdb.Transaction) is pure-Go-only in v1; it — and any operation a custom transactor genuinely can't provide — fail fast with this error.
func (*BackendCapabilityError) Error ¶
func (e *BackendCapabilityError) Error() string
type BunchedEntry ¶
BunchedEntry is a key-value pair in a BunchedMap.
type BunchedMap ¶
type BunchedMap struct {
// contains filtered or unexported fields
}
BunchedMap is a FoundationDB-backed map that bunches close keys together. Wire-compatible with Java's com.apple.foundationdb.map.BunchedMap.
Currently specialized for TEXT index use (K = tuple.Tuple, V = []int).
When a StoreTimer is set, BunchedMap instruments all writes, deletes, and range reads with index-level counters matching Java's InstrumentedBunchedMap.
func NewBunchedMap ¶
func NewBunchedMap(bunchSize int) *BunchedMap
NewBunchedMap creates a new BunchedMap with the given bunch size.
func NewInstrumentedBunchedMap ¶
func NewInstrumentedBunchedMap(bunchSize int, timer *StoreTimer) *BunchedMap
NewInstrumentedBunchedMap creates a BunchedMap with instrumentation enabled. Matches Java's InstrumentedBunchedMap which wraps BunchedMap with timer hooks.
func (*BunchedMap) Compact ¶
func (m *BunchedMap) Compact(tx fdb.WritableTransaction, ss subspace.Subspace, keyLimit int, continuation []byte) ([]byte, error)
Compact repacks entries in the map to minimize the number of FDB keys used. Each call processes up to keyLimit FDB keys (0 = all keys) and returns a continuation token for multi-transaction compaction. Returns (nil, nil) when compaction is complete. Matches Java's BunchedMap.compact().
func (*BunchedMap) ContainsKey ¶
func (m *BunchedMap) ContainsKey(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple) (bool, error)
ContainsKey checks if a key exists in the map. Matches Java's BunchedMap.containsKey().
func (*BunchedMap) Get ¶
func (m *BunchedMap) Get(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple) ([]int, bool, error)
Get retrieves the value associated with a key from the map. Returns (value, true, nil) if found, (nil, false, nil) if not found. Always adds a read conflict key on the map key for serializability, matching Java's BunchedMap.get() which takes TransactionContext.
func (*BunchedMap) Put ¶
func (m *BunchedMap) Put(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple, value []int) ([]int, bool, error)
Put inserts or updates a key-value pair in the map. Returns (oldValue, true, nil) if the key already existed, (nil, false, nil) if new. Matches Java's BunchedMap.put().
func (*BunchedMap) Remove ¶
func (m *BunchedMap) Remove(tx fdb.WritableTransaction, ss subspace.Subspace, key tuple.Tuple) ([]int, bool, error)
Remove removes a key from the map. Returns (oldValue, true, nil) if found and removed, (nil, false, nil) if not found. Matches Java's BunchedMap.remove().
func (*BunchedMap) Scan ¶
func (m *BunchedMap) Scan(tx fdb.ReadTransaction, ss subspace.Subspace, continuation []byte, limit int, reverse bool) *BunchedMapIterator
Scan iterates over all entries in a single BunchedMap within the given subspace. Supports continuation, limit, and reverse scan. Matches Java's BunchedMap.scan().
func (*BunchedMap) VerifyIntegrity ¶
func (m *BunchedMap) VerifyIntegrity(tx fdb.ReadTransaction, ss subspace.Subspace) error
VerifyIntegrity checks that all signpost keys and entries within bunches are in sorted order. Returns nil if the map is consistent. Matches Java's BunchedMap.verifyIntegrity().
type BunchedMapException ¶
type BunchedMapException struct {
Message string
}
BunchedMapException is the error type for BunchedMap operations.
func (*BunchedMapException) Error ¶
func (e *BunchedMapException) Error() string
type BunchedMapIterator ¶
type BunchedMapIterator struct {
// contains filtered or unexported fields
}
BunchedMapIterator iterates over a single BunchedMap's entries. Matches Java's BunchedMapIterator.
func (*BunchedMapIterator) Err ¶
func (it *BunchedMapIterator) Err() error
Err returns the first error encountered during iteration, if any.
func (*BunchedMapIterator) GetContinuation ¶
func (it *BunchedMapIterator) GetContinuation() []byte
GetContinuation returns a continuation token for resuming the scan.
func (*BunchedMapIterator) HasNext ¶
func (it *BunchedMapIterator) HasNext() bool
HasNext returns true if there are more entries.
func (*BunchedMapIterator) Next ¶
func (it *BunchedMapIterator) Next() *bunchedEntry
Next returns the next entry.
type BunchedMapMultiIterator ¶
type BunchedMapMultiIterator struct {
// contains filtered or unexported fields
}
BunchedMapMultiIterator iterates over multiple BunchedMaps within a parent subspace. Entries are returned sorted first by subspace, then by key within subspace. Streams from FDB lazily — only one bunch is in memory at a time. Matches Java's BunchedMapMultiIterator.
func NewBunchedMapMultiIterator ¶
func NewBunchedMapMultiIterator( tx fdb.ReadTransaction, parentSubspace subspace.Subspace, splitter SubspaceSplitter, beginBytes, endBytes []byte, continuation []byte, limit int, reverse bool, serializer *TextIndexBunchedSerializer, ) *BunchedMapMultiIterator
NewBunchedMapMultiIterator creates a multi-map iterator. Streams from FDB lazily — only one bunch in memory at a time.
func NewBunchedMapMultiIteratorWithCallback ¶
func NewBunchedMapMultiIteratorWithCallback( tx fdb.ReadTransaction, parentSubspace subspace.Subspace, splitter SubspaceSplitter, beginBytes, endBytes []byte, continuation []byte, limit int, callback KVCallback, reverse bool, serializer *TextIndexBunchedSerializer, ) *BunchedMapMultiIterator
NewBunchedMapMultiIteratorWithCallback creates a multi-map iterator with a per-KV callback for byte tracking. The callback fires once per raw FDB key-value pair read, before deserialization. Matches Java's scanMulti() with Consumer<KeyValue> callback parameter.
func (*BunchedMapMultiIterator) Cancel ¶
func (it *BunchedMapMultiIterator) Cancel()
Cancel stops the iterator.
func (*BunchedMapMultiIterator) Err ¶
func (it *BunchedMapMultiIterator) Err() error
Err returns the first error encountered during iteration, if any.
func (*BunchedMapMultiIterator) GetContinuation ¶
func (it *BunchedMapMultiIterator) GetContinuation() []byte
GetContinuation returns a continuation token for resuming the scan. Returns nil if the scan is exhausted.
func (*BunchedMapMultiIterator) HasNext ¶
func (it *BunchedMapMultiIterator) HasNext() bool
HasNext returns true if there are more entries to return.
func (*BunchedMapMultiIterator) Next ¶
func (it *BunchedMapMultiIterator) Next() *BunchedMapScanEntry
Next returns the next entry and advances the iterator.
type BunchedMapScanEntry ¶
type BunchedMapScanEntry struct {
Subspace subspace.Subspace
SubspaceTag tuple.Tuple
Key tuple.Tuple
Value []int
}
BunchedMapScanEntry is a single entry from a multi-map scan. Contains the entry data plus the subspace it belongs to.
type BunchedSerializationError ¶
BunchedSerializationError is returned when bunched map serialization/deserialization fails.
func (*BunchedSerializationError) Error ¶
func (e *BunchedSerializationError) Error() string
type BunchedSerializer ¶
type BunchedSerializer[K any, V any] interface { SerializeKey(key K) []byte SerializeEntry(key K, value V) ([]byte, error) SerializeEntries(entries []BunchedEntry[K, V]) ([]byte, error) DeserializeKey(data []byte, offset, length int) (K, error) DeserializeEntries(key K, data []byte) ([]BunchedEntry[K, V], error) DeserializeKeys(key K, data []byte) ([]K, error) CanAppend() bool }
BunchedSerializer serializes keys and values for BunchedMap storage. Keys must serialize in a way that preserves sort order (unsigned lexicographic). Matches Java's com.apple.foundationdb.map.BunchedSerializer interface.
type BytesContinuation ¶
type BytesContinuation struct {
// contains filtered or unexported fields
}
BytesContinuation is a simple continuation that wraps a byte array
func NewBytesContinuation ¶
func NewBytesContinuation(b []byte) *BytesContinuation
NewBytesContinuation creates a BytesContinuation with the given bytes. A nil bytes value means end-of-cursor (IsEnd returns true).
func (*BytesContinuation) IsEnd ¶
func (c *BytesContinuation) IsEnd() bool
IsEnd returns true if this is an end continuation
func (*BytesContinuation) ToBytes ¶
func (c *BytesContinuation) ToBytes() ([]byte, error)
ToBytes returns the continuation bytes
type CardinalityFunctionKeyExpression ¶
type CardinalityFunctionKeyExpression struct {
FunctionKeyExpression
}
CardinalityFunctionKeyExpression is the root key expression of a CARDINALITY() index. It counts the argument array's elements to produce the single key column. Ports Java's CardinalityFunctionKeyExpression:
- getMinArguments()==getMaxArguments()==1, getColumnSize()==1
- createsDuplicates()==false (a count is single-valued — see createsDuplicates)
- evaluateMessage's two protobuf fast paths (plain repeated field, nullable wrapper) plus the materialize-and-count fallback for deeper nestings.
It embeds the generic FunctionKeyExpression so it serialises to the identical proto (Function{name:"cardinality", arguments:…}) and reuses FieldNames / ColumnSize / Name / Arguments. Only Evaluate is overridden to add the fast paths; the result is identical to the registry fallback either way.
func CardinalityExpr ¶
func CardinalityExpr(arguments KeyExpression) *CardinalityFunctionKeyExpression
CardinalityExpr builds a CARDINALITY() index root over the given argument key expression. The argument is field("arr", Concatenate) for a plain array column, or field("arr").nest(field("values", Concatenate)) for a Java-written nullable-array wrapper. Mirrors Java's function("cardinality", field("arr", …)).
func (*CardinalityFunctionKeyExpression) Evaluate ¶
func (c *CardinalityFunctionKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate applies Java's two protobuf fast paths against the record message, falling back to materialize-and-count for shapes the fast paths do not recognise (deeper nesting, the null cases).
Fast path 1 — nullable-array wrapper: the argument is field("wrapper").nest(field("values", Concatenate)). If the wrapper message is present, count its "values" field directly (a present wrapper with zero elements is a non-null empty array → 0). If absent, the array is NULL → fall through to the materialized null result.
Fast path 2 — plain repeated field: the argument is field("arr", Concatenate). Count the repeated field directly (Message.getRepeatedFieldCount). A zero count keys 0, NOT NULL: a plain repeated field is the NOT NULL array's storage shape, and an empty one is [] whose cardinality is 0. NULL keys arise only where the array itself can be absent — an absent wrapper, or a null parent on a deeper nesting — both of which reach the materialized fallback.
type ChildSlot ¶
type ChildSlot struct {
SmallestHV *big.Int
SmallestKey tuple.Tuple
LargestHV *big.Int
LargestKey tuple.Tuple
ChildID []byte
ChildMBR MBR
}
ChildSlot is an intermediate node slot referencing a child node.
type CollectOptions ¶
type CollectOptions struct {
// BatchSize is the maximum number of records scanned per transaction.
// Collection is continuation-driven, so a large store costs many small
// transactions rather than one big one.
//
// It is a ROW bound and therefore NOT what keeps a transaction inside FDB's
// 5s limit: a record can be a hundred bytes or, split across KV pairs,
// hundreds of kilobytes, so a fixed row count is anywhere from ~100KB to
// hundreds of megabytes of reading. TimeLimit and ScannedBytesLimit are the
// bounds that hold whatever the records weigh; a batch ends at whichever of
// the three comes first.
BatchSize int
// MaxRecordsPerType ABORTS the collection as soon as any one record type
// exceeds this many rows. Nothing is stored, and the report names the type
// that blew the budget. Zero means no cap.
//
// Abort rather than skip-and-continue, because skipping cannot produce a
// usable outcome. A type with no entry fails the reader's schema-wide
// completeness gate, so the OTHER types' counts are refused along with it —
// the old behaviour bought a full scan and an unusable result, which is
// strictly worse than not collecting. Aborting reaches the same end state
// having read a bounded prefix, and says which type to look at.
//
// It also cannot bound work any other way: collection is a SINGLE PASS over
// all records (a per-type scan needs a record-type-prefixed primary key,
// which not every layout has), so there is no way to keep scanning while
// skipping one type's rows.
MaxRecordsPerType int64
// TimeLimit bounds how long ONE scan transaction spends reading before it
// stops and hands back a continuation. Zero means DefaultCollectTimeLimit.
//
// This, not BatchSize, is what keeps a transaction inside FDB's 5s limit.
// BatchSize bounds ROWS, and a row is not a fixed number of bytes.
TimeLimit time.Duration
// ScannedBytesLimit bounds how many bytes ONE scan transaction reads before
// it stops and hands back a continuation. Zero means
// DefaultCollectScannedBytesLimit.
//
// Both bounds are drivable from a test, and neither is a wall-clock bound:
// every elapsed-time decision goes through ScanLimiterState.Elapsed, which is
// env.Since, so TimeLimit runs on the simulation clock when one is installed.
// An earlier version of this comment claimed TimeLimit was nondeterministic
// and used that to justify leaving its arm undriven -- the claim was false and
// the gap it excused was real; both arms now have a test.
ScannedBytesLimit int64
// Tags are FDB transaction tags applied to EVERY transaction this collection
// opens — each scan batch and the replacing write.
//
// EmbeddedConnection.CollectStatistics OVERWRITES this with the connection's
// own tags: at that layer the connection owns them, and a caller passing
// CollectOptions should not have to know they exist. Callers of this package
// directly (the fleet fan-out, tests) set it themselves and it is honoured.
//
// Threaded explicitly rather than wrapped around the database, because a
// wrapper has to reconstruct an *FDBDatabase and this package's copy-method
// gate forbids the field-by-field form for good reason: the first attempt
// dropped env, which silently swaps a persisted timestamp's seeded clock for
// the wall clock. A parameter is visible at every call site; a dropped field
// is visible nowhere.
Tags []string
}
CollectOptions tunes a collection run.
type CollectionReport ¶
type CollectionReport struct {
// Collected is the per-type statistics written.
Collected map[string]RecordTypeStatistic
// Skipped maps a record type to why it has NO statistic. Present so a
// caller can tell "not collected" from "collected as zero" — the two are
// different facts and only one of them is a table with no rows.
Skipped map[string]string
// RecordsScanned is the total records read across all types.
RecordsScanned int64
}
CollectionReport describes one run.
func CollectStatistics ¶
func CollectStatistics( ctx context.Context, db *FDBDatabase, storeBuilder func(*FDBRecordContext) (*FDBRecordStore, error), stats StatisticsSubspace, opts CollectOptions, ) (*CollectionReport, error)
CollectStatistics scans a record store and writes per-record-type counts into stats -- exact for a store at rest; see RecordTypeStatistic for what concurrent primary-key moves do to the total.
It is an OFFLINE maintenance job, not a query path: it reads every record. The signature mirrors RebalanceSPFreshIndex so it composes with the maintainers already in this library.
Counting is a SINGLE PASS over all records, tallying by type, rather than one scan per type. That is deliberate: a per-type scan is only cheaper when the primary key carries a record-type prefix, and this must work for every store layout, including the ones that do not. One pass is uniform and correct everywhere.
type CommitCheckFunc ¶
type CommitCheckFunc func() error
CommitCheckFunc is a pre-commit check that runs before the transaction commits. If it returns an error, the commit is aborted. Matches Java's CommitCheckAsync interface.
type ComparisonKeyFunc ¶
ComparisonKeyFunc extracts a comparison key from a cursor element. The returned tuple is used for merge ordering via FDB's order-preserving tuple encoding. Matches Java's KeyedMergeCursorState.comparisonKeyFunction: there a key-extraction failure propagates as a RecordCoreException through the cursor's future chain — an error to the caller, never a crash — so the Go closure carries an error return, which advance() surfaces as the child cursor's error.
type CompositeKeyExpression ¶
type CompositeKeyExpression struct {
// contains filtered or unexported fields
}
CompositeKeyExpression combines multiple key expressions
func (*CompositeKeyExpression) ColumnSize ¶
func (c *CompositeKeyExpression) ColumnSize() int
ColumnSize returns the sum of all child column sizes.
func (*CompositeKeyExpression) Evaluate ¶
func (c *CompositeKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate computes the Cartesian product of all child expression results. Matches Java's ThenKeyExpression which crosses children:
child0 returns [[1], [2]] child1 returns [[a], [b]] result = [[1,a], [1,b], [2,a], [2,b]]
For the common case where each child returns exactly one tuple, the result is a single tuple that is the concatenation of all child tuples — identical to the old flat-append behavior.
func (*CompositeKeyExpression) EvaluateFlat ¶
func (c *CompositeKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
EvaluateFlat returns the single concatenated tuple directly, avoiding the outer [][]any wrapper. Only valid when no child uses fan-out. Saves 1 alloc per child (no [][]any) + 1 alloc for the result (no outer wrapper).
func (*CompositeKeyExpression) FieldNames ¶
func (c *CompositeKeyExpression) FieldNames() []string
FieldNames returns all field names from component expressions
func (*CompositeKeyExpression) PackDirect ¶
func (c *CompositeKeyExpression) PackDirect(pk *tuple.Packer, record *FDBStoredRecord[proto.Message], msg proto.Message) bool
PackDirect encodes all child fields directly into a Packer. Returns false if any child can't be directly packed.
func (*CompositeKeyExpression) SubKeyExpressions ¶
func (c *CompositeKeyExpression) SubKeyExpressions() []KeyExpression
SubKeyExpressions returns the child key expressions in key order. Mirrors Java's ThenKeyExpression.getChildren(); used by callers that need to inspect the composite's structure (e.g. tagging which columns are function-keyed). The returned slice is the live backing slice — callers must not mutate it.
func (*CompositeKeyExpression) ToKeyExpression ¶
func (c *CompositeKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes a CompositeKeyExpression (ThenKeyExpression) to proto. Matches Java's ThenKeyExpression.toKeyExpression().
type ContinuationParseError ¶
ContinuationParseError is returned when continuation bytes fail to parse as their wrapper proto. Matches Java's RecordCoreException("error parsing continuation") with the "raw_bytes" log info key (e.g. OrElseCursor's constructor, RecordCursor.fromList): a corrupt continuation is a caller error and must surface, never be silently treated as a fresh start.
Message overrides the default "error parsing continuation" text for the Java classes whose RecordCoreException wording differs (ConcatCursor uses "Error parsing ConcatCursor continuation", DedupCursor uses "Error parsing continuation"). Leave empty for the common wording.
func (*ContinuationParseError) Error ¶
func (e *ContinuationParseError) Error() string
func (*ContinuationParseError) Unwrap ¶
func (e *ContinuationParseError) Unwrap() error
type Counter ¶
type Counter struct {
// contains filtered or unexported fields
}
Counter tracks an occurrence count plus a cumulative value. Matches Java's StoreTimer.Counter (StoreTimer.java:408-517), including which of the two fields carries the payload for each Kind:
- KindTimed: Count() is occurrences, CumulativeValue() is total nanoseconds.
- KindCount / KindSize: Count() carries everything (occurrences, or a byte total for KindSize) and CumulativeValue() stays 0.
The second bullet is the non-obvious one, and it is Java's: Counter.increment(int) adds to `count` alone (StoreTimer.java:484-487), which is why Java can use `getTimeNanos() == 0` as a proof that an event is a counter rather than a timer (RecordLayerMetricCollector.java:90).
All operations are goroutine-safe.
func (*Counter) CumulativeValue ¶
CumulativeValue returns the sum of all recorded values.
func (*Counter) Increment ¶
Increment adds amount to the occurrence count, leaving the cumulative value untouched — Java's Counter.increment (StoreTimer.java:484-487). For a KindSize event the byte total therefore accumulates in Count(), which is where Java keeps it too (getKeysAndValues emits a size Count as a plain `_count` key, StoreTimer.java:754).
type CounterSnapshot ¶
CounterSnapshot is an immutable point-in-time snapshot of a Counter. Matches Java's StoreTimerSnapshot.CounterSnapshot (StoreTimerSnapshot.java:179-226).
Event is carried alongside the numbers because the numbers are not self-describing: without the Kind, a consumer cannot tell whether Count is occurrences or bytes, nor whether CumulativeValue is a duration or meaningless. Java recovers that from the map key's static type; Go carries it.
type CursorFactory ¶
type CursorFactory[T any] func(continuation []byte) RecordCursor[T]
CursorFactory creates a cursor from an optional continuation. nil continuation means start from the beginning.
type CursorStreamingMode ¶
type CursorStreamingMode int
CursorStreamingMode controls how FDB fetches data
const ( // StreamingModeSmall fetches small amounts at a time StreamingModeSmall CursorStreamingMode = iota // StreamingModeMedium fetches medium amounts at a time StreamingModeMedium // StreamingModeLarge fetches large amounts at a time StreamingModeLarge // StreamingModeSerial fetches one at a time StreamingModeSerial // StreamingModeWantAll fetches as much as possible StreamingModeWantAll // StreamingModeIterator is the default iterator mode StreamingModeIterator )
func (CursorStreamingMode) ToFDB ¶
func (m CursorStreamingMode) ToFDB() fdb.StreamingMode
ToFDB converts to FDB's StreamingMode
type DefaultTextTokenizer ¶
type DefaultTextTokenizer struct{}
DefaultTextTokenizer is the default tokenizer for full-text indexes. It splits text using Unicode word boundary rules, normalizes to NFKD, case-folds to lowercase, and strips diacritical marks. Matches Java's com.apple.foundationdb.record.provider.common.text.DefaultTextTokenizer.
func DefaultTextTokenizerInstance ¶
func DefaultTextTokenizerInstance() *DefaultTextTokenizer
DefaultTextTokenizerInstance returns the singleton default tokenizer.
func (*DefaultTextTokenizer) MaxVersion ¶
func (t *DefaultTextTokenizer) MaxVersion() int
MaxVersion returns the same as MinVersion (only one version exists).
func (*DefaultTextTokenizer) MinVersion ¶
func (t *DefaultTextTokenizer) MinVersion() int
MinVersion returns 0 (GLOBAL_MIN_VERSION).
func (*DefaultTextTokenizer) Name ¶
func (t *DefaultTextTokenizer) Name() string
Name returns "default".
func (*DefaultTextTokenizer) Tokenize ¶
func (t *DefaultTextTokenizer) Tokenize(text string, version int, mode TokenizerMode) (TokenIterator, error)
Tokenize returns an iterator over tokens from the input text. Returns an error if the version is out of bounds. The tokenization process:
- Segment text into words using Unicode word boundary rules (matching Java's BreakIterator.getWordInstance(Locale.ROOT))
- NFKD normalize each segment
- Filter segments that don't contain any letter or digit
- Lowercase and strip combining marks (\p{M})
func (*DefaultTextTokenizer) TokenizeToList ¶
func (t *DefaultTextTokenizer) TokenizeToList(text string, version int, mode TokenizerMode) ([]string, error)
TokenizeToList returns all tokens as a list.
func (*DefaultTextTokenizer) TokenizeToMap ¶
func (t *DefaultTextTokenizer) TokenizeToMap(text string, version int, mode TokenizerMode) (map[string][]int, error)
TokenizeToMap returns a map from token to list of positions.
type DefaultTextTokenizerFactory ¶
type DefaultTextTokenizerFactory struct{}
DefaultTextTokenizerFactory creates DefaultTextTokenizer instances.
func (*DefaultTextTokenizerFactory) GetTokenizer ¶
func (f *DefaultTextTokenizerFactory) GetTokenizer() TextTokenizer
func (*DefaultTextTokenizerFactory) Name ¶
func (f *DefaultTextTokenizerFactory) Name() string
type DimensionsKeyExpression ¶
type DimensionsKeyExpression struct {
WholeKey KeyExpression
PrefixSize int
DimensionsSize int
}
DimensionsKeyExpression splits a key expression into prefix, dimensions, and suffix. Used by MULTIDIMENSIONAL indexes to separate grouping, spatial, and key-suffix components. Matches Java's DimensionsKeyExpression.
func Dimensions ¶
func Dimensions(wholeKey KeyExpression, prefixSize, dimensionsSize int) *DimensionsKeyExpression
Dimensions creates a DimensionsKeyExpression.
func (*DimensionsKeyExpression) ColumnSize ¶
func (d *DimensionsKeyExpression) ColumnSize() int
ColumnSize returns the column size of the whole key.
func (*DimensionsKeyExpression) Evaluate ¶
func (d *DimensionsKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate delegates to the whole key expression.
func (*DimensionsKeyExpression) FieldNames ¶
func (d *DimensionsKeyExpression) FieldNames() []string
FieldNames delegates to the whole key.
func (*DimensionsKeyExpression) SplitIndexEntry ¶
func (d *DimensionsKeyExpression) SplitIndexEntry(entry tuple.Tuple) (prefix, dims, suffix tuple.Tuple)
SplitIndexEntry splits an evaluated index entry tuple into prefix, dimensions, and suffix.
func (*DimensionsKeyExpression) SuffixSize ¶
func (d *DimensionsKeyExpression) SuffixSize() int
SuffixSize returns the number of suffix columns (after prefix + dimensions).
func (*DimensionsKeyExpression) ToKeyExpression ¶
func (d *DimensionsKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes to proto.
type DirectPacker ¶
type DirectPacker interface {
PackDirect(pk *tuple.Packer, record *FDBStoredRecord[proto.Message], msg proto.Message) bool
}
DirectPacker can encode field values directly into a Packer without any boxing.
type EmptyKeyExpression ¶
type EmptyKeyExpression struct{}
EmptyKeyExpression produces an empty tuple — used for ungrouped record counting. When used as a recordCountKey, a single total count is maintained.
func (*EmptyKeyExpression) ColumnSize ¶
func (e *EmptyKeyExpression) ColumnSize() int
ColumnSize returns 0 — an empty expression produces no tuple elements.
func (*EmptyKeyExpression) Evaluate ¶
func (e *EmptyKeyExpression) Evaluate(_ *FDBStoredRecord[proto.Message], _ proto.Message) ([][]any, error)
Evaluate returns one empty tuple (no key components).
func (*EmptyKeyExpression) EvaluateFlat ¶
func (e *EmptyKeyExpression) EvaluateFlat(_ *FDBStoredRecord[proto.Message], _ proto.Message) ([]any, error)
EvaluateFlat returns empty (no elements to append).
func (*EmptyKeyExpression) FieldNames ¶
func (e *EmptyKeyExpression) FieldNames() []string
FieldNames returns no field names.
func (*EmptyKeyExpression) ToKeyExpression ¶
func (e *EmptyKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes an EmptyKeyExpression to proto. Matches Java's EmptyKeyExpression.toKeyExpression().
type EndContinuation ¶
type EndContinuation struct{}
EndContinuation represents the end of a cursor's iteration. INVARIANT: Only valid when NoNextReason is SourceExhausted. Matches Java's RecordCursorEndContinuation.
func (*EndContinuation) IsEnd ¶
func (c *EndContinuation) IsEnd() bool
IsEnd always returns true for end continuations
func (*EndContinuation) ToBytes ¶
func (c *EndContinuation) ToBytes() ([]byte, error)
ToBytes always returns nil for end continuations
type EndpointType ¶
type EndpointType int
EndpointType represents how to treat range endpoints in scans
const ( // EndpointTypeTreeStart indicates the start of the entire tree EndpointTypeTreeStart EndpointType = iota // EndpointTypeTreeEnd indicates the end of the entire tree EndpointTypeTreeEnd // EndpointTypeRangeInclusive includes the endpoint in the range EndpointTypeRangeInclusive // EndpointTypeRangeExclusive excludes the endpoint from the range EndpointTypeRangeExclusive // EndpointTypeContinuation indicates continuation from a previous scan EndpointTypeContinuation // EndpointTypePrefixString for prefix-string-based ranges. // When used, the tuple is packed and the trailing null byte (string // terminator in FDB tuple encoding) is stripped. For the low // endpoint the stripped bytes are used directly. For the high // endpoint the stripped bytes are strinc'd (trailing 0xFF bytes are // removed, then the last byte is incremented). // Matches Java's EndpointType.PREFIX_STRING. EndpointTypePrefixString )
type Event ¶
type Event struct {
Name string // machine-readable, e.g. "save_record"
Title string // human-readable, e.g. "Save Record"
Kind Kind // how the counter's fields are to be read
}
Event represents a measurable instrumentation event. Matches Java's FDBStoreTimer.Events / FDBStoreTimer.Counts.
type ExecuteProperties ¶
type ExecuteProperties struct {
// IsolationLevel for the execution
IsolationLevel IsolationLevel
// ReturnedRowLimit is the maximum number of records to return
// 0 or negative means no limit
ReturnedRowLimit int
// ScannedRecordsLimit is the maximum number of records to scan
// 0 or negative means no limit
ScannedRecordsLimit int
// ScannedBytesLimit is the maximum number of bytes to scan
// 0 or negative means no limit
ScannedBytesLimit int64
// TimeLimit is the maximum time for the operation
// Zero duration means no limit
TimeLimit time.Duration
// DefaultCursorStreamingMode is the default streaming mode for cursors
DefaultCursorStreamingMode CursorStreamingMode
// FailOnScanLimitReached determines if hitting scan limits should fail the operation
FailOnScanLimitReached bool
// Skip is the number of records to skip before returning results.
// Matches Java's ExecuteProperties.getSkip().
Skip int
// MaterializationLimit caps the number of rows that may be buffered
// in memory by operators that materialize an entire relation (NLJ
// inner, UNION buffered, recursive CTE levels). Zero means use
// DefaultMaterializationLimit.
MaterializationLimit int
// State is the statement-scoped mutable counter object (RFC-130) — a
// Go-only extension (the statement-wide in-memory buffering byte budget;
// Java has no memory-specific SQLSTATE or ExecuteState field for this) that
// borrows the SAME reference-holding PATTERN Java's ExecuteState uses
// (a pointer inside the otherwise value-copied ExecuteProperties), but is
// NOT a content port of Java's ExecuteState — see ScanState below for the
// field that actually corresponds structurally to Java's ExecuteState
// (the RecordScanLimiter/ByteScanLimiter pair). It is a POINTER, so every
// value-copy of ExecuteProperties (the WithX helpers, ClearSkipAndLimit,
// per-operator innerProps) shares ONE counter and none of them reset it —
// the statement-wide memory byte budget survives all inner-plan resets
// structurally, which is the whole point. It is always minted once per
// statement (never nil) where the statement's ExecuteProperties is first
// built; the "no budget" case is memLimit<=0, NOT a nil State, so a missed
// accumulation site charges an unlimited counter rather than silently
// no-oping. None of the WithX helpers below clear it: they copy the value
// struct, which copies the pointer.
State *ExecuteState
// ScanState is the execution-scoped mutable counter set (scanned records,
// scanned bytes, start-of-execution time) that ScannedRecordsLimit /
// ScannedBytesLimit / TimeLimit are checked against — the type that
// actually corresponds structurally to Java's ExecuteState
// (ExecuteState.java: the RecordScanLimiter + ByteScanLimiter pair), named
// ScanLimiterState in Go only because the name ExecuteState was already
// taken by the unrelated Go-only RFC-130 type above (State's doc comment).
// Do not read the two fields' similar shape as the SAME Java concept split
// two ways — State has no Java analog at all; ScanState is the one with a
// direct Java counterpart. Like State, ScanState is a POINTER shared by
// every value-copy of ExecuteProperties, so every leg of an IN-join/
// IN-union (which recurses via ClearSkipAndLimit, never a fresh
// DefaultExecuteProperties) charges the SAME counters — see
// ScanLimiterState's doc comment for the hang this fixes. UNLIKE State,
// ScanState is page/transaction-scoped, not statement-scoped: it is minted
// fresh by EVERY call to DefaultExecuteProperties (never nil from that
// constructor, matching Java's @Nonnull ExecuteState), and
// paginatingRows.executeProps() calls DefaultExecuteProperties exactly once
// per page, INSIDE the retried transaction closure — so every retry
// attempt and every page gets its own honest budget, matching Java's
// CursorLimitManager being rebuilt from a fresh FDBRecordContext each
// attempt. A raw ExecuteProperties struct literal leaves ScanState nil,
// and every leaf cursor falls back to a private per-cursor instance in
// that case — identical to the pre-fix behavior.
ScanState *ScanLimiterState
// DryRun, when true, makes data-modification execution validate and PREVIEW
// each mutation via the store's DryRun* primitives instead of staging a real
// write — Java's ExecuteProperties.setDryRun / isDryRun(). Statement-scoped:
// it is sourced from the SQL OPTIONS (DRY RUN) clause carried on
// paginatingRows, never from a connection option (a connection-scoped flag
// would go sticky across pooled statements).
DryRun bool
}
ExecuteProperties holds properties that pertain to an entire execution
func DefaultExecuteProperties ¶
func DefaultExecuteProperties() ExecuteProperties
DefaultExecuteProperties returns properties with sensible defaults. Mints a fresh ScanState every call (never nil) — matching Java's ExecuteProperties.Builder.build(), which always constructs an ExecuteState (@Nonnull) even when no limit is configured (ExecuteProperties.java:598-608). Every caller of DefaultExecuteProperties (directly or via ForwardScan/ ReverseScan) therefore gets its OWN counter set, shared with every downstream copy of the returned value (WithX helpers, ClearSkipAndLimit, IN-join/IN-union leg recursion) but never with a DIFFERENT top-level call — exactly the per-execution-attempt scope CursorLimitManager gets from a fresh FDBRecordContext per transaction.
func DefaultExecutePropertiesIn ¶
func DefaultExecutePropertiesIn(env *dst.Env) ExecuteProperties
DefaultExecutePropertiesIn is DefaultExecuteProperties with its scan/time budget anchored on env's clock. A nil env is production (wall clock) and is exactly what DefaultExecuteProperties passes, so the two are byte-identical outside a simulation.
It exists as a sibling rather than as a signature change because DefaultExecuteProperties has ~900 call sites and only ONE of them arms a time limit under simulation — the SQL page loop. Threading an env through the other 899 would be churn that obscures the one edit that matters.
func (ExecuteProperties) ClearRowAndTimeLimits ¶
func (e ExecuteProperties) ClearRowAndTimeLimits() ExecuteProperties
ClearRowAndTimeLimits returns a copy with row limit and time limit cleared. Matches Java's ExecuteProperties.clearRowAndTimeLimits().
func (ExecuteProperties) ClearSkipAndLimit ¶
func (e ExecuteProperties) ClearSkipAndLimit() ExecuteProperties
ClearSkipAndLimit returns a copy with skip and row limit cleared. Matches Java's ExecuteProperties.clearSkipAndLimit().
func (ExecuteProperties) GetMaterializationLimit ¶
func (e ExecuteProperties) GetMaterializationLimit() int
GetMaterializationLimit returns the effective materialization limit, falling back to DefaultMaterializationLimit when zero.
func (ExecuteProperties) WithDryRun ¶
func (e ExecuteProperties) WithDryRun(dryRun bool) ExecuteProperties
WithDryRun returns a copy with the dry-run flag set. Java's ExecuteProperties.setDryRun.
func (ExecuteProperties) WithIsolationLevel ¶
func (e ExecuteProperties) WithIsolationLevel(level IsolationLevel) ExecuteProperties
WithIsolationLevel returns a copy with the specified isolation level
func (ExecuteProperties) WithMaterializationLimit ¶
func (e ExecuteProperties) WithMaterializationLimit(limit int) ExecuteProperties
WithMaterializationLimit returns a copy with the specified materialization limit.
func (ExecuteProperties) WithReturnedRowLimit ¶
func (e ExecuteProperties) WithReturnedRowLimit(limit int) ExecuteProperties
WithReturnedRowLimit returns a copy with the specified row limit
func (ExecuteProperties) WithScannedBytesLimit ¶
func (e ExecuteProperties) WithScannedBytesLimit(limit int64) ExecuteProperties
WithScannedBytesLimit returns a copy with the specified scanned bytes limit.
func (ExecuteProperties) WithScannedRecordsLimit ¶
func (e ExecuteProperties) WithScannedRecordsLimit(limit int) ExecuteProperties
WithScannedRecordsLimit returns a copy with the specified scanned records limit.
func (ExecuteProperties) WithSkip ¶
func (e ExecuteProperties) WithSkip(skip int) ExecuteProperties
WithSkip returns a copy with the specified skip count.
func (ExecuteProperties) WithTimeLimit ¶
func (e ExecuteProperties) WithTimeLimit(limit time.Duration) ExecuteProperties
WithTimeLimit returns a copy with the specified time limit
type ExecuteState ¶
type ExecuteState struct {
// contains filtered or unexported fields
}
ExecuteState holds the mutable, statement-scoped counters for a single statement execution. It mirrors Java's com.apple.foundationdb.record.ExecuteState (ExecuteState.java:44-47): the counters live in a small mutable object held BY REFERENCE inside the otherwise value-copied ExecuteProperties, so every value-copy of the properties (the WithX helpers, ClearSkipAndLimit, per-operator innerProps) shares one counter and none of them reset it. Statement-wide survival is therefore STRUCTURAL — exactly as in Java, where clearSkipAndLimit (:240-245) preserves the ExecuteState for free because it only zeroes skip/rowLimit.
RFC-130 minted the memory byte budget that bounds in-memory buffering operators (the row-count MaterializationLimit cannot stop 100k LARGE rows from OOMing). recursionLevels below is a second, unrelated statement-scoped counter set that reuses the same by-reference survival pattern for a different purpose (see its own doc comment). The scan/byte/time counters Go currently tracks per-cursor are the correct future home here too, to fully match Java — out of scope for RFC-130, noted for the divergence ledger.
Concurrency: the executor is single-threaded per statement (zero goroutine launches in pkg/recordlayer/query/executor — pinned by package_invariant_test.go), so ChargeMemory/IncrementRecursionLevel need no mutex/atomic. If a future parallel-union breaks that invariant the pinned test fires and the counters move to atomic / a mutex.
func NewExecuteState ¶
func NewExecuteState(memLimit int64) *ExecuteState
NewExecuteState mints a fresh statement-scoped state with the given memory byte limit. A limit <= 0 means unlimited (no budget). The state is ALWAYS minted once per statement — never nil — so a missed accumulation site charges an unlimited counter (a no-op charge) rather than silently no-oping via a nil receiver, which would make a missed wiring an invisible bypass instead of a visible (if unbounded) charge.
func (*ExecuteState) ChargeMemory ¶
func (s *ExecuteState) ChargeMemory(n int64) error
ChargeMemory adds n bytes to the statement's running memory total and returns a *MemoryLimitExceededError if the total then exceeds the budget.
A nil receiver or a non-positive memLimit means "no budget" and is a no-op (memUsed is still accumulated for an active budget, but a <=0 limit short- circuits before touching the counter so the unlimited path stays free). The charge is applied BEFORE the check, so the error carries the would-be total — the buffer that breaches the budget is never kept by the caller, which errors out instead of appending.
func (*ExecuteState) HasMemLimit ¶
func (s *ExecuteState) HasMemLimit() bool
HasMemLimit reports whether a positive memory budget is active. Callers MUST gate any expensive byte-estimate computation (e.g. the per-row proto Size() walk in estimateQueryResultBytes) on this, so the default/unlimited path pays nothing — RFC-130's zero-overhead-when-off invariant. nil receiver or memLimit<=0 → false.
func (*ExecuteState) IncrementRecursionLevel ¶
func (s *ExecuteState) IncrementRecursionLevel(id any) int
IncrementRecursionLevel bumps and returns the level count tracked under id.
This is the STATEMENT-scoped half of the streaming level-union recursive CTE's cycle guard: RecordQueryRecursiveLevelUnionPlan's UNION ALL arm is a pure streaming cursor with no fixpoint/dedup (Java has none either — this cap is a Go-only safety extension), so a cyclic self-referential CTE only terminates via a hard recursion-depth cap. That cap must count LEVELS FOR THE WHOLE STATEMENT, but the streaming cursor itself is rebuilt fresh on every page (a new *recursiveUnionCursor per fetchPage, per the SQL layer's "no cursor persists across transactions" architecture) — a counter living on the cursor resets to zero every page and a cyclic CTE that pages mid-recursion would never trip it. ExecuteState is the vehicle already used for exactly this shape of problem (RFC-130's memory budget): a pointer the SQL layer mints ONCE per statement (cascades_generator.go's paginatingRows.execState) and threads into every page's ExecuteProperties.State, so it survives the per-page cursor rebuild structurally.
id anchors the count to one INVOCATION of a recursive construct — the caller (recursiveUnionCursor) passes a key combining the recursive-CTE plan node's own pointer (stable across every page of one statement execution: the SQL layer rebuilds the cursor hierarchy each page but reuses the same plan tree) with a branch scope identifying which concurrently-live invocation this is, when more than one can execute the same plan pointer at once (a sorted RecordQueryInUnionPlan runs one cursor per IN value, merged in lockstep — see recursionInvocationKey's doc comment in recursive_union_cursor.go for why plan pointer alone is not a safe key). ExecuteState itself doesn't interpret id beyond map-key equality; it just needs to be stable across one invocation's own resumes and distinct across concurrently-live invocations, whatever shape the caller builds it in. Two independent recursive CTEs in the same statement get INDEPENDENT budgets (distinct plan pointers, hence distinct keys), matching the eager recursion arms' own per-call-local bound rather than sharing one statement-wide total.
SCOPE, stated exactly: the guard covers one *ExecuteState's lifetime, i.e. one Execute() call / one statement execution — cascades_generator.go mints a fresh ExecuteState per Execute and never reuses one across statements or connections. A continuation resumed by a DIFFERENT statement execution cannot inherit the count (there is no such thing today: Go's SQL layer rejects caller-supplied continuations outright, see cascadesPlan.Execute, so this is not a live gap, just an honest boundary of the mechanism).
A nil receiver returns 0 on every call — it cannot persist anything, by construction. This is a Go-only safety cap, not an RFC-130 resource budget, so callers must not treat a nil ExecuteState as "no cap": the caller (recursiveUnionCursor.checkDepth) always combines this with its own per-cursor-instance counter and uses whichever is larger, so a nil State still bounds runaway growth within one page/cursor lifetime — identical to the pre-fix behavior — even though it can no longer see across pages.
func (*ExecuteState) MemLimit ¶
func (s *ExecuteState) MemLimit() int64
MemLimit returns the configured memory byte budget (<= 0 == unlimited).
func (*ExecuteState) MemUsed ¶
func (s *ExecuteState) MemUsed() int64
MemUsed returns the bytes charged against this state so far. Test/diagnostic accessor; production code never reads it.
func (*ExecuteState) ReleaseMemory ¶
func (s *ExecuteState) ReleaseMemory(n int64)
ReleaseMemory returns n previously ChargeMemory'd bytes to the statement budget. The budget bounds LIVE buffered bytes: a buffer that outlives its cursor by round-tripping through a continuation is re-charged at resume injection, so the producing cursor must release its charges at teardown — otherwise a multi-page statement re-accounts the same buffer once per page and a compliant query trips the limit merely by crossing page boundaries. Callers release exactly what they charged; nil receiver / no budget is a no-op mirroring ChargeMemory.
func (*ExecuteState) ResetRecursionLevel ¶
func (s *ExecuteState) ResetRecursionLevel(id any)
ResetRecursionLevel zeroes (deletes) the level count tracked under id. The caller uses this at two distinct moments with the same effect — freeing an entry that must not linger — for different reasons:
- At the start of a FRESH invocation (continuation==nil at cursor construction), to guard against a stale entry from a prior invocation that shared this exact id and somehow didn't clean up via (2). Without this, a recursive CTE nested in a correlated subquery — re-invoked once per outer row (recursive_union_cursor.go's newRecursiveUnionCursor is called fresh, continuation==nil, from flatMapCursor.OnNext for every outer row — see its doc comment) and getting the SAME id every row, since sequential invocations aren't distinguished by branch scope — could have its count over-accumulate across invocations instead of starting each at zero. A resume of an in-flight invocation (paging mid-recursion) always carries a non-nil continuation and must NOT reset, or the original bug (a cyclic recursion that pages mid-recursion streaming forever because its counter resets every page) returns.
- When an invocation ENDS — naturally (source exhausted, no further continuation) or by aborting (the depth cap itself firing) — so a statement driving many sequential or concurrent invocations doesn't accumulate unbounded dead map entries for ids that will never be touched again. See recursiveUnionCursor.OnNext and checkDepth for where each fires.
A nil receiver or a never-populated map is a no-op — nothing to reset.
func (*ExecuteState) RestoreRecursionLevels ¶
func (s *ExecuteState) RestoreRecursionLevels(snapshot map[any]int)
RestoreRecursionLevels puts the recursion-level counts back to a snapshot taken by SnapshotRecursionLevels, discarding anything counted since. A nil snapshot restores the empty state — which is the correct meaning, not a no-op: it is what a snapshot taken before the first level was counted says.
Restoring rather than subtracting is deliberate: an attempt may have both incremented some ids and RESET others (checkDepth frees an entry when an invocation ends or aborts), so only wholesale replacement returns the map to what the retried work will re-derive.
func (*ExecuteState) SnapshotRecursionLevels ¶
func (s *ExecuteState) SnapshotRecursionLevels() map[any]int
SnapshotRecursionLevels copies the recursion-level counts so a caller that is about to run a RETRYABLE unit of work can restore them if that work is re-executed. Returns nil when there is nothing tracked (the overwhelmingly common case — no recursive CTE in the statement), which RestoreRecursionLevels handles as "restore to empty".
WHY ONLY THIS MEMBER. ExecuteState's two mutable members answer different questions and therefore roll back differently:
- memUsed is a LIVE-OCCUPANCY gauge, not a running total. Every charge has a matching release on teardown (boundedBuffer.charged → ReleaseMemory, chargeReleasingCursor.Close), and the SQL layer's page closure closes its result set on the way out of a failed attempt as well as a successful one. A re-executed attempt therefore returns the gauge to its own entry value without help, and rolling it back HERE would be wrong twice over: it would double-release what teardown already released, and it would discard charges belonging to buffers that are still live because they outlive the page. Statement-cumulative by design, deliberately not rolled back.
- recursionLevels is a POSITION: it counts how far into a resumable recursion this statement has walked, and a resumed cursor deliberately does NOT reset it (newRecursiveUnionCursor only resets on a nil continuation, or a cyclic CTE that pages mid-recursion would never trip the cap). That is exactly what makes it unsafe under re-execution — an attempt that walked k levels and then failed leaves those k counted, and the re-execution walks the same k again. A finite CTE approaching the cap then fails with a depth error it did not earn. Position, so it rolls back with the rest of the page's position.
A member added later belongs on one of those two sides, and the question to ask is not "is it a counter" but "does re-executing the work that moved it move it again": if yes it is position and belongs here.
type FDBDatabase ¶
type FDBDatabase struct {
// contains filtered or unexported fields
}
FDBDatabase provides access to the underlying FoundationDB database or tenant and manages transaction execution with retry logic. This is the Record Layer equivalent of Java's FDBDatabase.
The transactor field can be either an fdb.Database or fdb.Tenant, both of which implement the fdb.Transactor interface. This allows transparent support for both regular database operations and tenant-isolated operations.
func NewFDBDatabase ¶
func NewFDBDatabase(db fdb.Database) *FDBDatabase
NewFDBDatabase creates a new FDBDatabase wrapping the core FDB database
func NewFDBDatabaseFromTenant ¶
func NewFDBDatabaseFromTenant(tenant fdb.Tenant) *FDBDatabase
NewFDBDatabaseFromTenant creates a new FDBDatabase wrapping an FDB tenant for tenant-isolated operations. All operations will be scoped to the tenant's keyspace.
func NewFDBDatabaseWithBackend ¶
func NewFDBDatabaseWithBackend(backend fdb.BackendDatabase) *FDBDatabase
NewFDBDatabaseWithBackend creates an FDBDatabase driven by a build-selected fdb backend (RFC-109) — e.g. the libfdb_c escape hatch, opened via fdbclient.Open (which a build tag points at the pure-Go or libfdb_c client). The backend drives the Run / RunRead gold path (record save/load, query, index maintenance) through the Transactor interface.
The concrete-db slot is left empty for a non-pure-Go backend. Standalone transactions go through CreateWritableTransaction and locality through LocalityGetBoundaryKeys — both delegate to the backend's own interface-returning methods, so explicit transactions, the FDBDatabaseRunner, AND online MUTUAL indexing all work on libfdb_c. The one remaining concrete-only path is the pure-Go-typed CreateTransaction (it returns the concrete fdb.Transaction a non-pure-Go backend cannot build), which stays pure-Go-only in v1 and fails fast with BackendCapabilityError (not a nil panic) — the same scope boundary the RFC draws around tenants.
func NewFDBDatabaseWithTransactor ¶
func NewFDBDatabaseWithTransactor(transactor fdb.Transactor, db fdb.Database) *FDBDatabase
NewFDBDatabaseWithTransactor creates a new FDBDatabase with a custom Transactor. The transactor is used for Run()/RunWithVersionstamp() (transaction execution), while the db is used for CreateTransaction() (direct transaction creation). This enables wrapping the transactor for fault injection, tracing, or middleware.
func (*FDBDatabase) CreateTransaction ¶
func (d *FDBDatabase) CreateTransaction() (fdb.Transaction, error)
CreateTransaction creates a new transaction without retry logic. This is primarily used for testing scenarios where manual transaction control is needed, such as testing isolation levels with concurrent transactions. For tenant-isolated databases, the transaction will be scoped to the tenant's keyspace.
func (*FDBDatabase) CreateWritableTransaction ¶
func (d *FDBDatabase) CreateWritableTransaction() (fdb.WritableTransaction, error)
CreateWritableTransaction creates a standalone, non-retry transaction as the backend-agnostic WritableTransaction interface. Unlike CreateTransaction (which returns the concrete pure-Go fdb.Transaction and is therefore pure-Go-only), this works on ANY backend — including the libfdb_c escape hatch — so the SQL engine's database/sql explicit transactions (BeginTx / COMMIT, which span multiple driver calls and so can't use the closure-based Run gold path) are not silently pure-Go-only. Prefer this over CreateTransaction wherever a concrete pure-Go handle isn't specifically required.
func (*FDBDatabase) Env ¶
func (d *FDBDatabase) Env() *dst.Env
Env returns the database's DST environment, or nil (which the *dst.Env accessors treat as production). Nil-safe on the receiver, like FDBRecordContext.Env: an accessor whose whole contract is "nil means production" must not be the one call in the chain that panics.
func (*FDBDatabase) GetStoreStateCache ¶
func (d *FDBDatabase) GetStoreStateCache() FDBRecordStoreStateCache
GetStoreStateCache returns the current store state cache. Matches Java's FDBDatabase.getStoreStateCache().
func (*FDBDatabase) LocalityGetBoundaryKeys ¶
func (d *FDBDatabase) LocalityGetBoundaryKeys(r fdb.ExactRange, limit int, readVersion int64) ([]fdb.Key, error)
LocalityGetBoundaryKeys returns the FDB shard boundary keys within r, working on both the pure-Go and libfdb_c backends (the online MUTUAL indexer uses them to partition the keyspace into fragments for concurrent building). It's a read of the \xff/keyServers system range — byte-identical on the pure-Go and libfdb_c clients against the same cluster — so mutual indexing parallelizes on either backend. A handle that can't provide it (a tenant-backed FDBDatabase, or a custom transactor) returns BackendCapabilityError; callers that want graceful degradation (1 fragment) treat an error as "no boundaries".
Unlike CreateWritableTransaction there is no tenant branch: shard boundaries are a cluster-wide property of the keyServers map, independent of any tenant.
func (*FDBDatabase) NewRecordContext ¶
func (d *FDBDatabase) NewRecordContext(tx fdb.WritableTransaction) *FDBRecordContext
NewRecordContext wraps an externally-created FDB transaction in a context that inherits everything this database gives the contexts it opens itself: the DST environment and the StoreTimer. It is the form every caller holding an *FDBDatabase should use — SQL's explicit BeginTx→COMMIT path among them.
The point is that per-database state is threaded in ONE place. NewFDBRecordContext takes the fields one by one, which is why env was silently dropped on the explicit-transaction path until someone noticed; adding the timer as a second such parameter would have set up the identical failure for instrumentation, where the symptom is even quieter (a metric that reads zero looks exactly like a workload that did nothing).
func (*FDBDatabase) Run ¶
func (d *FDBDatabase) Run(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, error)
Run executes a function within a transaction with automatic retry handling. Before committing, flushes any queued versionstamp mutations. Matches Java's FDBRecordContext.commitAsync() behavior.
func (*FDBDatabase) RunRead ¶
func (d *FDBDatabase) RunRead(ctx context.Context, fn func(rtx fdb.ReadTransaction) (any, error)) (any, error)
RunRead executes a read-only function with automatic retry but no commit. Uses ReadTransact under the hood — no write conflict ranges, no commit round-trip. Suitable for statistics, metadata reads, or any read-only operation where a full read-write transaction would waste a commit.
ctx bounds the read-retry loop + backoff when the transactor supports it (fdb.CtxReadTransactor); the entry check also returns early if already cancelled.
func (*FDBDatabase) RunWithVersionstamp ¶
func (d *FDBDatabase) RunWithVersionstamp(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, []byte, error)
RunWithVersionstamp is like Run but also returns the committed versionstamp. Use this when you need the versionstamp after commit (e.g. for record versioning). Returns (result, versionstamp, error). Versionstamp is nil for read-only transactions.
func (*FDBDatabase) RunWithWeakReads ¶
func (d *FDBDatabase) RunWithWeakReads(ctx context.Context, weak WeakReadSemantics, fn func(rtx *FDBRecordContext) (any, error)) (any, error)
RunWithWeakReads is like Run but applies weak read semantics to the transaction. If IsCausalReadRisky is set, the transaction reads from any replica. Matches Java's FDBDatabase.openContext(config, timer, weakReadSemantics, ...).
func (*FDBDatabase) SetEnv ¶
func (d *FDBDatabase) SetEnv(env *dst.Env) *FDBDatabase
SetEnv installs the DST environment inherited by every context this database opens. A simulation driver calls this with dst.NewSim(seed) right after constructing the database (typically over a SimFDB backend); production leaves it unset. Returns d for chaining.
func (*FDBDatabase) SetStoreStateCache ¶
func (d *FDBDatabase) SetStoreStateCache(cache FDBRecordStoreStateCache)
SetStoreStateCache sets the cache used for store state across transactions. Matches Java's FDBDatabase.setStoreStateCache().
func (*FDBDatabase) SetTimer ¶
func (d *FDBDatabase) SetTimer(timer *StoreTimer)
SetTimer installs the StoreTimer that every context this database opens will record into, replacing any previous one. Passing nil disables instrumentation.
Matches Java's FDBDatabaseRunner.setTimer / FDBRecordContextConfig.Builder.setTimer (FDBDatabaseRunner.java:112-119, FDBRecordContextConfig.java:357-368): the timer is a caller-supplied object whose lifetime and scope the caller chooses, never something the database owns or creates for you. Contexts already open keep the timer they were built with — the read happens once at context construction, as in Java.
func (*FDBDatabase) Timer ¶
func (d *FDBDatabase) Timer() *StoreTimer
Timer returns the StoreTimer installed by SetTimer, or nil when the database is uninstrumented. Matches Java's FDBDatabaseRunner.getTimer (FDBDatabaseRunner.java:105-110).
type FDBDatabaseFactory ¶
type FDBDatabaseFactory struct {
// StoreStateCacheFactory creates a store state cache for each new database.
// If nil, PassThroughStoreStateCache is used.
StoreStateCacheFactory func() FDBRecordStoreStateCache
// contains filtered or unexported fields
}
FDBDatabaseFactory caches FDBDatabase instances by cluster file path. Thread-safe. Matches Java's FDBDatabaseFactory.getDatabase(clusterFile).
func NewFDBDatabaseFactory ¶
func NewFDBDatabaseFactory() *FDBDatabaseFactory
NewFDBDatabaseFactory creates a factory for caching database instances.
func (*FDBDatabaseFactory) GetDatabase ¶
func (f *FDBDatabaseFactory) GetDatabase(clusterFile string) (*FDBDatabase, error)
GetDatabase returns a cached FDBDatabase for the given cluster file path. Creates a new one on first call for each unique path. Matches Java's FDBDatabaseFactory.getDatabase(clusterFile).
type FDBDatabaseRunner ¶
type FDBDatabaseRunner struct {
// MaxAttempts is the maximum number of retry attempts (default 10).
MaxAttempts int
// InitialDelay is the initial delay between retries (default 10ms).
InitialDelay time.Duration
// MaxDelay is the maximum delay between retries (default 1s).
MaxDelay time.Duration
// ContextConfig is applied to each transaction.
ContextConfig *RecordContextConfig
// contains filtered or unexported fields
}
FDBDatabaseRunner provides configurable retry logic for FDB transactions. Matches Java's FDBDatabaseRunnerImpl.
func NewFDBDatabaseRunner ¶
func NewFDBDatabaseRunner(db *FDBDatabase) *FDBDatabaseRunner
NewFDBDatabaseRunner creates a runner with default settings.
func (*FDBDatabaseRunner) OpenContext ¶
func (r *FDBDatabaseRunner) OpenContext(ctx context.Context) (*FDBRecordContext, error)
OpenContext creates a new FDBRecordContext with a fresh transaction, applying the runner's context configuration. Matches Java's FDBDatabaseRunner.openContext(). The caller is responsible for committing or cancelling the transaction.
func (*FDBDatabaseRunner) RunWithRetry ¶
func (r *FDBDatabaseRunner) RunWithRetry(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, error)
RunWithRetry executes fn with configurable retry logic and exponential backoff. Retries on FDB retryable errors (conflict, etc.) up to MaxAttempts times. Non-retryable errors are returned immediately. Matches Java's FDBDatabaseRunnerImpl.run().
func (*FDBDatabaseRunner) SetContextConfig ¶
func (r *FDBDatabaseRunner) SetContextConfig(config *RecordContextConfig) *FDBDatabaseRunner
SetContextConfig sets the transaction context configuration.
func (*FDBDatabaseRunner) SetInitialDelay ¶
func (r *FDBDatabaseRunner) SetInitialDelay(d time.Duration) *FDBDatabaseRunner
SetInitialDelay sets the initial retry delay.
func (*FDBDatabaseRunner) SetMaxAttempts ¶
func (r *FDBDatabaseRunner) SetMaxAttempts(n int) *FDBDatabaseRunner
SetMaxAttempts sets the maximum retry attempts.
func (*FDBDatabaseRunner) SetMaxDelay ¶
func (r *FDBDatabaseRunner) SetMaxDelay(d time.Duration) *FDBDatabaseRunner
SetMaxDelay sets the maximum retry delay.
type FDBIndexedRecord ¶
type FDBIndexedRecord struct {
IndexEntry *IndexEntry
Record *FDBStoredRecord[proto.Message]
}
FDBIndexedRecord wraps a record that was found via an index scan. Contains both the index entry used to locate the record and the record itself. Matches Java's com.apple.foundationdb.record.provider.foundationdb.FDBIndexedRecord.
type FDBMetaDataStore ¶
type FDBMetaDataStore struct {
// contains filtered or unexported fields
}
FDBMetaDataStore stores and retrieves RecordMetaData from FDB. The metadata is stored as a serialized protobuf at a well-known key, enabling runtime schema evolution without application redeployment. Matches Java's FDBMetaDataStore.
func NewFDBMetaDataStore ¶
func NewFDBMetaDataStore(ss subspace.Subspace) *FDBMetaDataStore
NewFDBMetaDataStore creates a metadata store at the given subspace. The evolution validator defaults to the strictest configuration, matching Java's `evolutionValidator = MetaDataEvolutionValidator.getDefaultInstance()`.
func (*FDBMetaDataStore) LoadRecordMetaDataProto ¶
func (s *FDBMetaDataStore) LoadRecordMetaDataProto(tx fdb.WritableTransaction) (*gen.MetaData, error)
LoadRecordMetaDataProto loads the current MetaData proto from FDB. Returns nil if no metadata has been stored. Uses SplitHelper for wire compatibility with Java's FDBMetaDataStore. Matches Java's FDBMetaDataStore.loadRecordMetaData().
func (*FDBMetaDataStore) LoadRecordMetaDataProtoAtVersion ¶
func (s *FDBMetaDataStore) LoadRecordMetaDataProtoAtVersion(tx fdb.WritableTransaction, version int32) (*gen.MetaData, error)
LoadRecordMetaDataProtoAtVersion loads a historical version of the metadata. Returns nil if the version doesn't exist. Uses SplitHelper for wire compatibility with Java's FDBMetaDataStore.
func (*FDBMetaDataStore) SaveRecordMetaData ¶
func (s *FDBMetaDataStore) SaveRecordMetaData(tx fdb.WritableTransaction, metaDataProto *gen.MetaData) error
SaveRecordMetaData saves a MetaData proto to FDB, with the full validation Java runs in the same transaction — this is NOT a raw persist. In order (matching Java's FDBMetaDataStore.saveAndSetCurrent):
- the new proto must build into a RecordMetaData;
- if metadata is already stored: the new version must be strictly greater (MetaDataVersionMustIncreaseError otherwise), the evolution validator must pass old → new, and the old serialized bytes are archived at HISTORY_KEY_PREFIX + oldVersion;
- the new metadata is written at CURRENT_KEY.
Because all of this happens inside the caller's transaction, FDB conflict detection serializes concurrent evolvers — two racing saves against the same old version cannot both commit.
Uses SplitHelper for wire compatibility with Java's FDBMetaDataStore, which stores metadata with split support (unsplit suffix 0).
func (*FDBMetaDataStore) SetEvolutionValidator ¶
func (s *FDBMetaDataStore) SetEvolutionValidator(v *MetaDataEvolutionValidator)
SetEvolutionValidator replaces the validator SaveRecordMetaData runs against the currently stored metadata. Matches Java's FDBMetaDataStore.setEvolutionValidator().
func (*FDBMetaDataStore) Subspace ¶
func (s *FDBMetaDataStore) Subspace() subspace.Subspace
Subspace returns the subspace this metadata store uses.
type FDBRecordContext ¶
type FDBRecordContext struct {
// contains filtered or unexported fields
}
func NewFDBRecordContext ¶
func NewFDBRecordContext(tx fdb.WritableTransaction, env *dst.Env) *FDBRecordContext
NewFDBRecordContext wraps an externally-created FDB transaction — the path SQL's explicit BeginTx→COMMIT takes, plus direct-transaction-control tests.
env is REQUIRED rather than defaulted, and that is the point. This is the sixth construction site of an FDBRecordContext; the other five (Run/RunAsync/ReadOnly in this file and the two in runner.go) all thread d.env, and this one silently did not. The consequence was that every explicit transaction ran with env==nil — production seams, wall clock, crypto/rand — even under a fully seeded simulation environment. That is precisely the path an explicit-COMMIT semantics RFC needs to replay, so it was the one path the seam did not cover. A default here would reintroduce the same silence; passing nil is allowed but has to be written down.
Callers holding an *FDBDatabase should NOT call this — call db.NewRecordContext(tx), which threads every piece of per-database state at once. Enumerating the fields at each call site is what let env go unthreaded here in the first place, and a second such field (the StoreTimer) would have repeated it exactly.
func (*FDBRecordContext) AddCommitCheck ¶
func (rc *FDBRecordContext) AddCommitCheck(check CommitCheckFunc)
AddCommitCheck registers a pre-commit check function. All checks run before the transaction commits. If any returns an error, the commit is aborted with that error. Goroutine-safe via commitMu (matches Java's synchronized blocks). Matches Java's FDBRecordContext.addCommitCheck(CommitCheckAsync).
func (*FDBRecordContext) AddPostCommit ¶
func (rc *FDBRecordContext) AddPostCommit(hook PostCommitFunc)
AddPostCommit registers a post-commit callback. All callbacks run after the transaction successfully commits. Goroutine-safe via commitMu (matches Java's synchronized blocks). Matches Java's FDBRecordContext.addPostCommit(PostCommit).
func (*FDBRecordContext) AddReadConflictRange ¶
func (rc *FDBRecordContext) AddReadConflictRange(r fdb.ExactRange) error
AddReadConflictRange adds a read conflict range and tracks it for diagnostics. Goroutine-safe via conflictMu (FDB transaction is already goroutine-safe).
func (*FDBRecordContext) AddToLocalVersionCache ¶
func (rc *FDBRecordContext) AddToLocalVersionCache(versionKey []byte, localVersion int)
AddToLocalVersionCache caches a local version for a version key within this transaction. Goroutine-safe via versionMu. Matches Java's FDBRecordContext.addToLocalVersionCache().
func (*FDBRecordContext) AddVersionMutation ¶
func (rc *FDBRecordContext) AddVersionMutation(mutationType VersionMutationType, versionKey []byte, value []byte)
AddVersionMutation queues a versionstamp mutation to be applied at commit. mutationType selects SET_VERSIONSTAMPED_KEY or SET_VERSIONSTAMPED_VALUE. The key or value (depending on type) must include the versionstamp placeholder bytes. Goroutine-safe via versionMu. Matches Java's FDBRecordContext.addVersionMutation(MutationType, key, value).
func (*FDBRecordContext) Cancel ¶
func (rc *FDBRecordContext) Cancel()
Cancel cancels the transaction
func (*FDBRecordContext) CheckTransactionSize ¶
func (rc *FDBRecordContext) CheckTransactionSize() error
CheckTransactionSize checks the approximate transaction size against the configured warning and error thresholds. Returns TransactionSizeExceededError if the error threshold is exceeded, TransactionSizeWarningError if the warning threshold is exceeded (once per transaction), or nil.
func (*FDBRecordContext) ClaimLocalVersion ¶
func (rc *FDBRecordContext) ClaimLocalVersion() int
ClaimLocalVersion atomically claims the next local version number. Goroutine-safe via atomic.Int32 (matches Java's AtomicInteger.getAndIncrement()).
func (*FDBRecordContext) Commit ¶
func (rc *FDBRecordContext) Commit() error
Commit commits the transaction.
Records EventCommit, as every commit path must. Java has ONE commit method (FDBRecordContext.commitAsync) and it records the event unconditionally (FDBRecordContext.java:513-533); Go splits that method three ways — here, CommitWithHooks and CommitWithVersionstamp — and a split where only one arm records turns the metric into a function of which API the caller happened to pick. Only CommitWithVersionstamp recorded, which is why explicit SQL transactions committed on every COMMIT statement and reported none.
func (*FDBRecordContext) CommitWithHooks ¶
func (rc *FDBRecordContext) CommitWithHooks() error
CommitWithHooks runs pre-commit checks, flushes pending version mutations, commits the FDB transaction, and runs post-commit callbacks. Use this instead of Commit() when the context was created manually (not via Run()).
The EventCommit span starts before the pre-commit checks and ends when the commit resolves, which is Java's interval — its startTimeNanos is taken at the first line of commitAsync, ahead of runCommitChecks, and the post-commit hooks are chained after the event is recorded (FDBRecordContext.java:478, :513-533).
func (*FDBRecordContext) CommitWithVersionstamp ¶
func (rc *FDBRecordContext) CommitWithVersionstamp() ([]byte, error)
CommitWithVersionstamp commits the transaction, first running pre-commit checks, then flushing all queued versionstamp mutations. Returns the committed versionstamp (10 bytes) or nil for read-only transactions / no versionstamp mutations. Runs post-commit hooks after successful commit. Matches Java's FDBRecordContext.commitAsync() which always runs checks and hooks.
func (*FDBRecordContext) Context ¶
func (rc *FDBRecordContext) Context() context.Context
Context returns the Go context
func (*FDBRecordContext) Env ¶
func (rc *FDBRecordContext) Env() *dst.Env
Env returns the DST environment for this context (Clock + Randomness + Buggify), inherited from the FDBDatabase. Never nil in the sense that matters: the returned *dst.Env may be nil, and the *dst.Env accessors (Now/Read/Fault) treat nil as production. Use this at every persisted-byte site instead of time.Now / crypto.rand so a simulation run is byte-reproducible.
func (*FDBRecordContext) GetApproximateTransactionSize ¶
func (rc *FDBRecordContext) GetApproximateTransactionSize() (int64, error)
GetApproximateTransactionSize returns the approximate size in bytes of the transaction's mutations so far. Useful for monitoring proximity to FDB's 10MB transaction size limit. Matches Java's FDBRecordContext.getApproximateTransactionSize().
func (*FDBRecordContext) GetConflictingKeys ¶
func (rc *FDBRecordContext) GetConflictingKeys() []fdb.KeyRange
GetConflictingKeys attempts to identify conflicting keys after a commit failure. Reads the transaction's read conflict ranges. This is a best-effort diagnostic tool. Goroutine-safe via conflictMu. Matches Java's FDBRecordContext.reportConflictingKeys() (diagnostic, not exact).
func (*FDBRecordContext) GetLocalVersion ¶
func (rc *FDBRecordContext) GetLocalVersion(versionKey []byte) (int, bool)
GetLocalVersion retrieves a cached local version for the given key. Returns (localVersion, true) if found, (0, false) otherwise. Goroutine-safe via versionMu.
func (*FDBRecordContext) GetMetaDataVersionStamp ¶
func (rc *FDBRecordContext) GetMetaDataVersionStamp() ([]byte, error)
GetMetaDataVersionStamp reads the metadata version stamp at snapshot isolation. Returns nil if the stamp was written in this transaction (dirty) or doesn't exist. On ACCESSED_UNREADABLE errors (FDB code 1036), marks the stamp as dirty and returns nil. Goroutine-safe via atomic.Bool + goroutine-safe FDB transaction. Matches Java's FDBRecordContext.getMetaDataVersionStampAsync().
func (*FDBRecordContext) GetReadVersion ¶
func (rc *FDBRecordContext) GetReadVersion() (int64, error)
GetReadVersion returns the transaction's read version. Matches Java's FDBRecordContext.getReadVersion().
func (*FDBRecordContext) HasDirtyStoreState ¶
func (rc *FDBRecordContext) HasDirtyStoreState() bool
HasDirtyStoreState returns true if any store state was modified in this transaction. When true, cached store state should not be used. Goroutine-safe via atomic.Bool. Matches Java's FDBRecordContext.hasDirtyStoreState().
func (*FDBRecordContext) HasVersionMutations ¶
func (rc *FDBRecordContext) HasVersionMutations() bool
HasVersionMutations returns true if there are pending version mutations. Goroutine-safe via versionMu.
func (*FDBRecordContext) PutSession ¶
func (rc *FDBRecordContext) PutSession(key string, value any)
PutSession stores a transaction-scoped value under key. Matches Java's FDBRecordContext session storage; values die with the context.
func (*FDBRecordContext) ReadTransaction ¶
func (rc *FDBRecordContext) ReadTransaction(snapshot bool) fdb.ReadTransaction
ReadTransaction returns the transaction a READ should go through for the given isolation: the snapshot view (no read conflict ranges) when snapshot is true, the plain transaction (conflict-tracking) otherwise.
This is the ONE place the snapshot/serializable choice is made, so that "serializable" is a property of the mechanism rather than of each leaf remembering to ask. Java has exactly this method — FDBRecordContext.readTransaction(boolean) (FDBRecordContext.java:660-666) — and every Java leaf resolves through it with the same expression: context.readTransaction(scanProperties.getExecuteProperties() .getIsolationLevel().isSnapshot()) (KeyValueCursorBase.java:358, VectorIndexMaintainer.java:201-202, TextIndexMaintainer.java:542, RankIndexMaintainer.java:292).
A leaf that calls Transaction().Snapshot() directly instead is not making a local choice — it is silently overriding the caller's isolation, which reads as isolated and commits as non-serializable.
func (*FDBRecordContext) RemoveLocalVersion ¶
func (rc *FDBRecordContext) RemoveLocalVersion(versionKey []byte)
RemoveLocalVersion removes a cached local version entry. Goroutine-safe via versionMu.
func (*FDBRecordContext) RemoveLocalVersionsInRange ¶
func (rc *FDBRecordContext) RemoveLocalVersionsInRange(begin, end fdb.Key)
RemoveLocalVersionsInRange removes all cached local versions whose key falls in [begin, end). Goroutine-safe via versionMu. Matches Java's FDBRecordContext.removeLocalVersionRange().
func (*FDBRecordContext) RemoveVersionMutation ¶
func (rc *FDBRecordContext) RemoveVersionMutation(versionKey []byte)
RemoveVersionMutation removes a queued version mutation. Goroutine-safe via versionMu.
func (*FDBRecordContext) RemoveVersionMutationsInRange ¶
func (rc *FDBRecordContext) RemoveVersionMutationsInRange(begin, end fdb.Key)
RemoveVersionMutationsInRange removes all queued version mutations whose key falls in [begin, end). Goroutine-safe via versionMu. Matches Java's FDBRecordContext.removeVersionMutationRange().
func (*FDBRecordContext) Session ¶
func (rc *FDBRecordContext) Session(key string) any
Session returns the transaction-scoped value stored under key, or nil. Matches Java's FDBRecordContext.getSession.
func (*FDBRecordContext) SetDirtyStoreState ¶
func (rc *FDBRecordContext) SetDirtyStoreState(dirty bool)
SetDirtyStoreState marks that store state was modified in this transaction. Goroutine-safe via atomic.Bool. Matches Java's FDBRecordContext.setDirtyStoreState().
func (*FDBRecordContext) SetMetaDataVersionStamp ¶
func (rc *FDBRecordContext) SetMetaDataVersionStamp()
SetMetaDataVersionStamp schedules a SET_VERSIONSTAMPED_VALUE mutation on the metadata version key. After commit, this key will contain the commit versionstamp, which invalidates any cached store state entries with older stamps. Goroutine-safe via atomic.Bool + goroutine-safe FDB transaction. Matches Java's FDBRecordContext.setMetaDataVersionStamp().
func (*FDBRecordContext) SetReadVersion ¶
func (rc *FDBRecordContext) SetReadVersion(version int64)
SetReadVersion sets the transaction's read version explicitly. Matches Java's FDBRecordContext.setReadVersion().
func (*FDBRecordContext) SetTimer ¶
func (rc *FDBRecordContext) SetTimer(timer *StoreTimer)
SetTimer sets the instrumentation timer for this context. Goroutine-safe via atomic.Pointer. Matches Java's FDBRecordContext.setTimer().
func (*FDBRecordContext) SetTransactionPriority ¶
func (rc *FDBRecordContext) SetTransactionPriority(priority TransactionPriority) error
SetTransactionPriority sets the priority for this transaction. Matches Java's FDBRecordContext applying FDBTransactionPriority.
func (*FDBRecordContext) Timer ¶
func (rc *FDBRecordContext) Timer() *StoreTimer
Timer returns the instrumentation timer for this context, or nil if not set. Goroutine-safe via atomic.Pointer. Matches Java's FDBRecordContext.getTimer(). Nil-safe on the receiver, for the same reason FDBRecordContext.Env is: every StoreTimer method tolerates a nil timer, so "no instrumentation" is a supported state all the way down — and an accessor at the head of that chain must not be the one call in it that panics. Call sites are of the form store.context.Timer().RecordSince(...), where the nil check would otherwise have to be repeated at each one.
func (*FDBRecordContext) Transaction ¶
func (rc *FDBRecordContext) Transaction() fdb.WritableTransaction
Transaction returns the underlying FDB transaction
func (*FDBRecordContext) TransactionID ¶
func (rc *FDBRecordContext) TransactionID() int64
TransactionID returns a unique ID for this record context. Useful for logging and tracing. Matches Java's FDBRecordContext transaction ID.
func (*FDBRecordContext) UpdateVersionMutation ¶
func (rc *FDBRecordContext) UpdateVersionMutation(mutationType VersionMutationType, versionKey []byte, value []byte, merge func(oldValue, newValue []byte) []byte)
UpdateVersionMutation queues or updates a versionstamp mutation with a merge function. If a mutation for the same key already exists, the merge function decides which value to keep. Goroutine-safe via versionMu. Matches Java's FDBRecordContext.updateVersionMutation(MutationType, key, value, BiFunction).
type FDBRecordStore ¶
type FDBRecordStore struct {
// contains filtered or unexported fields
}
FDBRecordStore provides record storage operations within a transaction context. This is the main struct for storing and retrieving records.
func (*FDBRecordStore) AcquireReadLock ¶
func (store *FDBRecordStore) AcquireReadLock(key string)
func (*FDBRecordStore) AcquireWriteLock ¶
func (store *FDBRecordStore) AcquireWriteLock(key string)
lockRegistry delegation — matches Java's LockRegistry on FDBRecordContext.
func (*FDBRecordStore) AddBuildProgress ¶
func (store *FDBRecordStore) AddBuildProgress(index *Index, count int64)
AddBuildProgress atomically increments the records-scanned counter for an index build. Matches Java's IndexingBase.tieredMergeAndCommit() → MutationType.ADD at IndexingSubspaces.indexBuildScannedRecordsSubspace().
func (*FDBRecordStore) AddRecordReadConflict ¶
func (store *FDBRecordStore) AddRecordReadConflict(primaryKey tuple.Tuple) error
AddRecordReadConflict adds a read conflict range for the given primary key. This ensures that if another transaction modifies this record before this transaction commits, this transaction will fail with a conflict error.
Java equivalent: FDBRecordStore.addRecordReadConflict(Tuple primaryKey) Java location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/FDBRecordStore.java:1222
func (*FDBRecordStore) AddRecordWriteConflict ¶
func (store *FDBRecordStore) AddRecordWriteConflict(primaryKey tuple.Tuple) error
AddRecordWriteConflict adds a write conflict range for the given primary key. This ensures that if another transaction reads this record before this transaction commits, that transaction will fail with a conflict error.
Java equivalent: FDBRecordStore.addRecordWriteConflict(Tuple primaryKey) Java location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/FDBRecordStore.java:1228
func (*FDBRecordStore) AddUniquenessViolation ¶
func (store *FDBRecordStore) AddUniquenessViolation(index *Index, indexKey tuple.Tuple, primaryKey tuple.Tuple) error
AddUniquenessViolation records a uniqueness violation for the given index. Used during WRITE_ONLY index builds when a uniqueness conflict is detected. Stores empty bytes as the value (no cross-reference to conflicting PK). Use AddUniquenessViolationWithExisting to store the conflicting PK in the value.
func (*FDBRecordStore) AddUniquenessViolationWithExisting ¶
func (store *FDBRecordStore) AddUniquenessViolationWithExisting(index *Index, indexKey tuple.Tuple, primaryKey tuple.Tuple, existingKey tuple.Tuple) error
AddUniquenessViolationWithExisting records a uniqueness violation with the conflicting PK. Matches Java's StandardIndexMaintainer.addUniquenessViolation(valueKey, primaryKey, existingKey). When existingKey is non-nil, its packed bytes are stored as the FDB value. When existingKey is nil, empty bytes are stored.
func (*FDBRecordStore) AsBuilder ¶
func (store *FDBRecordStore) AsBuilder() *StoreBuilder
AsBuilder creates a new StoreBuilder pre-configured with this store's subspace, metadata, and index rebuild policy. Uses the same context. Matches Java's FDBRecordStore.asBuilder().
func (*FDBRecordStore) ClearAndMarkIndexWriteOnly ¶
func (store *FDBRecordStore) ClearAndMarkIndexWriteOnly(indexName string) (bool, error)
ClearAndMarkIndexWriteOnly clears all index data and sets state to WRITE_ONLY. Used to start a fresh index rebuild. Matches Java's FDBRecordStore.clearAndMarkIndexWriteOnly().
func (*FDBRecordStore) ClearHeaderUserField ¶
func (store *FDBRecordStore) ClearHeaderUserField(key string) error
ClearHeaderUserField removes a user-defined field from the store header. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.clearHeaderUserField().
func (*FDBRecordStore) ClearStoreLockState ¶
func (store *FDBRecordStore) ClearStoreLockState() error
ClearStoreLockState removes the lock state from the store header. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.clearStoreLockStateAsync().
func (*FDBRecordStore) Context ¶
func (store *FDBRecordStore) Context() *FDBRecordContext
Context returns the record context this store is using
func (*FDBRecordStore) CopyBuilder ¶
func (store *FDBRecordStore) CopyBuilder(newContext *FDBRecordContext) *StoreBuilder
CopyBuilder creates a new StoreBuilder with this store's configuration but for a different context (transaction). Used to open the same store in a new transaction. Matches Java's FDBRecordStore.copyBuilder().
func (*FDBRecordStore) CountRecords ¶
func (store *FDBRecordStore) CountRecords( ctx context.Context, low, high tuple.Tuple, lowEndpoint, highEndpoint EndpointType, continuation []byte, scanProperties ScanProperties, ) (int, error)
CountRecords counts records in a range by scanning the records subspace. Unlike GetRecordCount() which uses atomic counters, this actually scans records. Matches Java's FDBRecordStore.countRecords().
func (*FDBRecordStore) DeleteAllRecords ¶
func (store *FDBRecordStore) DeleteAllRecords() error
DeleteAllRecords deletes all records from the store. Clears all data subspaces except StoreInfoKey (0) and IndexStateSpaceKey (5). Matches Java's FDBRecordStore.deleteAllRecords() which clears everything from records through index state begin, then from index state end through store end.
func (*FDBRecordStore) DeleteIndexEntries ¶
func (store *FDBRecordStore) DeleteIndexEntries(index *Index)
DeleteIndexEntries clears all entries for the given index. Matches Java's StandardIndexMaintainer.deleteWhere() with no predicate.
func (*FDBRecordStore) DeleteIndexEntriesInRange ¶
func (store *FDBRecordStore) DeleteIndexEntriesInRange(index *Index, prefix tuple.Tuple) error
DeleteIndexEntriesInRange clears index entries matching the given tuple prefix. For example, passing tuple.Tuple{"alice"} clears all entries where the first indexed value is "alice".
func (*FDBRecordStore) DeleteRecord ¶
func (store *FDBRecordStore) DeleteRecord(primaryKey tuple.Tuple) (bool, error)
DeleteRecord deletes a record by its primary key, following Java's deleteRecordAsync semantics. Returns true if a record was deleted, false if no record existed with that key. Handles both split and unsplit records via SplitHelper. Matches Java's FDBRecordStore.deleteRecordAsync(Tuple primaryKey)
func (*FDBRecordStore) DeleteRecordsWhere ¶
func (store *FDBRecordStore) DeleteRecordsWhere(prefix tuple.Tuple) error
DeleteRecordsWhere deletes all records whose primary key starts with the given prefix, along with all associated index entries, record versions, and record counts. This is a pure range-clear operation — no scanning.
The prefix must align with every active index's key expression so that index entries can be cleared via range operations. Type-specific indexes for matching types are cleared entirely. Universal indexes must have leading key expression columns that match the PK columns covered by the prefix.
Matches Java's FDBRecordStore.deleteRecordsWhereAsync().
func (*FDBRecordStore) DryRunDeleteRecord ¶
func (store *FDBRecordStore) DryRunDeleteRecord(primaryKey tuple.Tuple) (bool, error)
DryRunDeleteRecord checks whether a record with the given primary key exists and could be deleted, without actually deleting it. Returns true if the record exists (and would be deleted), false if not found. Note: does NOT check store lock state, matching Java's dryRunDeleteRecordAsync which only loads the record without calling validateRecordUpdateAllowed. Matches Java's FDBRecordStore.dryRunDeleteRecordAsync().
func (*FDBRecordStore) DryRunSaveRecord ¶
func (store *FDBRecordStore) DryRunSaveRecord( record proto.Message, existenceCheck RecordExistenceCheck, ) (*FDBStoredRecord[proto.Message], error)
DryRunSaveRecord validates a save and returns what the stored record would look like if saved, without actually writing data.
Scope — matches Java's FDBRecordStore.saveTypedRecord(isDryRun=true), which early-returns at FDBRecordStore.java:578 BEFORE the store-lock check (validateRecordUpdateAllowed, line 584), serializeAndSaveRecord (staging, line 586) and updateSecondaryIndexes (line 594). The PRIMARY-KEY existence/type checks run EARLIER (Java lines 561-577, before the isDryRun branch), so this keeps them. It deliberately does NOT validate store-lock state, does NOT stage the write, and does NOT run secondary-index maintenance. Consequences, all Java-faithful:
- a DRY RUN on a FORBID_RECORD_UPDATE-locked store previews SUCCESS (the lock check is skipped — Java's early-return precedes it), and
- a secondary-UNIQUE conflict is NOT detected in dry-run (only the real save's updateSecondaryIndexes catches it), and
- a duplicate PK introduced WITHIN the same statement is not seen by a later row (no write is staged between rows).
Doing any of these would make Go's preview STRICTER than Java's — a conformance divergence (Go rejecting a DRY RUN that Java previews as success). Pinned by TestFDB_DmlDryRun_MatchesJavaLightweightValidation and TestFDB_DmlDryRun_LockedStorePreviews.
Matches Java's FDBRecordStore.dryRunSaveRecordAsync().
func (*FDBRecordStore) Env ¶
func (store *FDBRecordStore) Env() *dst.Env
Env exposes the record context's DST environment to index maintainers. Nil-safe (a nil *dst.Env means production); index maintainers draw persisted nonces through it so a simulation run is byte-reproducible.
func (*FDBRecordStore) EstimateIndexSize ¶
func (store *FDBRecordStore) EstimateIndexSize(index *Index) (int64, error)
EstimateIndexSize returns the estimated size in bytes of a specific index. Uses FDB's native GetEstimatedRangeSizeBytes on the index's subspace.
func (*FDBRecordStore) EstimateRecordsSize ¶
func (store *FDBRecordStore) EstimateRecordsSize() (int64, error)
EstimateRecordsSize returns the estimated byte size of the records subspace only. Matches Java's FDBRecordStore.estimateRecordsSizeAsync().
func (*FDBRecordStore) EstimateRecordsSizeInRange ¶
func (store *FDBRecordStore) EstimateRecordsSizeInRange(tupleRange TupleRange) (int64, error)
EstimateRecordsSizeInRange returns the estimated size in bytes of records within the given tuple range. Uses FDB's native GetEstimatedRangeSizeBytes. Matches Java's FDBRecordStore.estimateRecordsSizeAsync(TupleRange).
func (*FDBRecordStore) EstimateStoreSize ¶
func (store *FDBRecordStore) EstimateStoreSize() (int64, error)
EstimateStoreSize returns the estimated byte size of the entire store subspace. Uses FDB's GetEstimatedRangeSizeBytes which provides an approximation. Matches Java's FDBRecordStore.estimateStoreSizeAsync().
func (*FDBRecordStore) EvaluateAggregateFunction ¶
func (store *FDBRecordStore) EvaluateAggregateFunction( ctx context.Context, recordTypeNames []string, fn *IndexAggregateFunction, scanRange TupleRange, isolationLevel IsolationLevel, ) (tuple.Tuple, error)
EvaluateAggregateFunction evaluates an aggregate function using the best matching index. Returns the aggregate result as a tuple, or nil if no matching entries exist.
For COUNT/SUM indexes: scans all group entries and reduces them. For MIN_EVER/MAX_EVER indexes: scans all group entries and reduces them. For VALUE indexes with MIN/MAX: scans 1 entry in the right direction.
Matches Java's FDBRecordStore.evaluateAggregateFunction().
func (*FDBRecordStore) EvaluateRecordFunction ¶
func (store *FDBRecordStore) EvaluateRecordFunction( fn *IndexRecordFunction, record *FDBStoredRecord[proto.Message], ) (*int64, error)
EvaluateRecordFunction evaluates an index record function for a specific record. For RANK indexes, this returns the rank of the record's score within its group. Returns nil if the record's value is not in the index (e.g. null field).
Matches Java's FDBRecordStore.evaluateIndexRecordFunction().
func (*FDBRecordStore) EvaluateStoreFunction ¶
func (store *FDBRecordStore) EvaluateStoreFunction( fn *StoreRecordFunction, record *FDBStoredRecord[proto.Message], ) (any, error)
EvaluateStoreFunction evaluates a store-level function on a record. Unlike EvaluateRecordFunction (which uses indexes), store functions access store state directly.
Currently supported functions:
- "version": returns the record's FDBRecordVersion (nil if none)
Matches Java's FDBRecordStore.evaluateStoreFunction().
func (*FDBRecordStore) FirstUnbuiltRange ¶
func (store *FDBRecordStore) FirstUnbuiltRange(index *Index) (*RangeSetRange, error)
FirstUnbuiltRange returns the first range of the index that hasn't been built yet. Returns nil, nil if the index is fully built. Matches Java's FDBRecordStore.firstUnbuiltRange(index).
func (*FDBRecordStore) GetAllIndexStates ¶
func (store *FDBRecordStore) GetAllIndexStates() map[string]IndexState
GetAllIndexStates returns a map of all index names to their current states. Indexes without an explicit state entry default to READABLE. Matches Java's FDBRecordStore.getAllIndexStates().
func (*FDBRecordStore) GetAllIndexStatesMap ¶
func (store *FDBRecordStore) GetAllIndexStatesMap() map[string]IndexState
GetAllIndexStatesMap returns a copy of the raw index states map (non-READABLE only). Goroutine-safe via stateMu (read lock). For a complete map including defaulted READABLE states, use GetAllIndexStates().
func (*FDBRecordStore) GetContext ¶
func (store *FDBRecordStore) GetContext() *FDBRecordContext
GetContext returns the record context (transaction wrapper) for this store. Matches Java's FDBRecordStore.getRecordContext().
func (*FDBRecordStore) GetDisabledIndexes ¶
func (store *FDBRecordStore) GetDisabledIndexes() []*Index
GetDisabledIndexes returns all indexes that are in DISABLED state. These indexes are not maintained or readable. Matches Java's FDBRecordStoreBase.getDisabledIndexes() (derived from getAllIndexStates).
func (*FDBRecordStore) GetEnabledIndexes ¶
func (store *FDBRecordStore) GetEnabledIndexes() []*Index
GetEnabledIndexes returns all indexes that are NOT in DISABLED state. Matches Java's FDBRecordStoreBase.getEnabledIndexes().
func (*FDBRecordStore) GetEnabledUniversalIndexes ¶
func (store *FDBRecordStore) GetEnabledUniversalIndexes() []*Index
GetEnabledUniversalIndexes returns universal indexes NOT in DISABLED state. Matches Java's FDBRecordStore.getEnabledUniversalIndexes().
func (*FDBRecordStore) GetFormatVersion ¶
func (store *FDBRecordStore) GetFormatVersion() int32
GetFormatVersion returns the store format version. Goroutine-safe via stateMu (read lock). Matches Java's FDBRecordStore.getFormatVersion().
func (*FDBRecordStore) GetHeaderUserField ¶
func (store *FDBRecordStore) GetHeaderUserField(key string) ([]byte, error)
GetHeaderUserField returns a user-defined field from the store header, or nil if the field is not set. Goroutine-safe via stateMu (read lock).
GATED like Java. getHeaderUserField() routes through validateCanAccessHeaderUserFields() — the SHARED validator at `:3221-3226`, reached from getHeaderUserField at `:3249` — which throws below HEADER_USER_FIELDS(8); Go returned nil, which a caller cannot tell apart from an unset field. Same ambiguity as GetIncarnation, and the same fix: "not set" and "this format cannot hold user fields at all" are different answers.
SetHeaderUserField already gated on this exact version, so the pair was ASYMMETRIC — a write that refused loudly beside a read that answered "absent", which is the shape that makes a caller conclude its write silently failed to persist.
func (*FDBRecordStore) GetIncarnation ¶
func (store *FDBRecordStore) GetIncarnation() (int32, error)
GetIncarnation returns the incarnation counter from the store header. Used for cross-cluster data migration versioning. Goroutine-safe via stateMu (read lock).
GATED like Java. FDBRecordStore.getIncarnation() (`:3502-3506`) throws when the format version is below INCARNATION(13), and Go returned 0 — which a caller cannot tell apart from a store whose incarnation genuinely is 0. That is not a leniency, it is an AMBIGUITY: "this store has no incarnation yet" and "this store's format is too old to HAVE one" are different facts that were returning the same value. A migration keyed off incarnation reads a too-old store as a never-migrated one.
The error is the write gate's twin (UnsupportedFeatureForFormatVersionError), not a new type: read and write are gated on the same version by the same predicate, so a caller that can write the field can read it back.
func (*FDBRecordStore) GetIndexMaintainer ¶
func (store *FDBRecordStore) GetIndexMaintainer(index *Index) (IndexMaintainer, error)
GetIndexMaintainer returns the index maintainer for the given index. Matches Java's FDBRecordStore.getIndexMaintainer().
func (*FDBRecordStore) GetIndexState ¶
func (store *FDBRecordStore) GetIndexState(indexName string) IndexState
GetIndexState returns the state of the given index. Returns READABLE if no explicit state is stored (matching Java's default behavior). Goroutine-safe via stateMu (read lock).
func (*FDBRecordStore) GetIndexesToBuildSince ¶
func (store *FDBRecordStore) GetIndexesToBuildSince(version int) []*Index
GetIndexesToBuildSince returns all indexes that need to be built because they were added or modified since the given metadata version. Matches Java's FDBRecordStore.getIndexesToBuildSince(version).
func (*FDBRecordStore) GetKeySizeLimit ¶
func (store *FDBRecordStore) GetKeySizeLimit() int
GetKeySizeLimit returns the maximum key size in bytes for index entries. Matches Java's FDBRecordStore.getKeySizeLimit().
func (*FDBRecordStore) GetMetaData ¶
func (store *FDBRecordStore) GetMetaData() *RecordMetaData
GetMetaData returns the metadata for this store. Matches Java's FDBRecordStore.getRecordMetaData().
func (*FDBRecordStore) GetMetaDataVersion ¶
func (store *FDBRecordStore) GetMetaDataVersion() int32
GetMetaDataVersion returns the metadata version stored in the header. Goroutine-safe via stateMu (read lock).
func (*FDBRecordStore) GetRangeSplitPoints ¶
func (store *FDBRecordStore) GetRangeSplitPoints(chunkSize int64) ([]fdb.Key, error)
GetRangeSplitPoints returns split points that divide the store's records subspace into approximately equal-sized chunks of the given byte size. Useful for parallelizing scans across multiple transactions. Uses FDB's native GetRangeSplitPoints which is efficient for large datasets.
func (*FDBRecordStore) GetReadableIndexes ¶
func (store *FDBRecordStore) GetReadableIndexes() []*Index
GetReadableIndexes returns all indexes that are in READABLE or READABLE_UNIQUE_PENDING state. Matches Java's FDBRecordStoreBase.getReadableIndexes().
func (*FDBRecordStore) GetReadableUniversalIndexes ¶
func (store *FDBRecordStore) GetReadableUniversalIndexes() []*Index
GetReadableUniversalIndexes returns universal indexes in READABLE state. Matches Java's FDBRecordStore.getReadableUniversalIndexes().
func (*FDBRecordStore) GetRecordCount ¶
func (store *FDBRecordStore) GetRecordCount() (int64, error)
GetRecordCount returns the total number of records in the store.
This is Java's getSnapshotRecordCount() (FDBRecordStore.java:2283, called with EmptyKeyExpression.EMPTY / Key.Evaluated.EMPTY), and it is a TOTAL under every record-count key: a GROUPED count key is rolled up by summing every group, not read out of the ungrouped slot that no grouped store ever writes to.
func (*FDBRecordStore) GetRecordMetaData ¶
func (store *FDBRecordStore) GetRecordMetaData() *RecordMetaData
GetRecordMetaData returns the metadata associated with this store. Matches Java's FDBRecordStore.getRecordMetaData().
func (*FDBRecordStore) GetRecordStoreState ¶
func (store *FDBRecordStore) GetRecordStoreState() *RecordStoreState
GetRecordStoreState returns the current state of the store (header + index states). Goroutine-safe via stateMu (read lock). Matches Java's FDBRecordStore.getRecordStoreState().
func (*FDBRecordStore) GetSnapshotRecordCount ¶
func (store *FDBRecordStore) GetSnapshotRecordCount(countKey tuple.Tuple) (int64, error)
GetSnapshotRecordCount returns the count of records matching the given evaluated value of the store's record-count key. Uses snapshot (non-conflicting) reads.
For ungrouped counting (EmptyKeyExpression), pass an empty tuple. For per-type counting, pass a tuple with the record type key.
Port of Java's getSnapshotRecordCount(key, value, filter) (FDBRecordStore.java:2283-2323). The maintained counters answer when they can (see snapshotRecordCountFromCountKey); otherwise Java does NOT fail — it falls through to evaluateAggregateFunction(emptyList(), count(key), allOf(value), SNAPSHOT, filter) (FDBRecordStore.java:2320-2322), so a store with no record-count key at all, or whose counters are WRITE_ONLY/DISABLED, is still counted from a universal COUNT index. The empty record-type list is what restricts that to universal indexes (IndexFunctionHelper.java:180-181).
Returns 0 if no count exists (null in FDB means 0, matching Java).
func (*FDBRecordStore) GetSnapshotRecordCountForRecordType ¶
func (store *FDBRecordStore) GetSnapshotRecordCountForRecordType(recordTypeName string) (int64, error)
GetSnapshotRecordCountForRecordType returns the count of records for a specific record type. Requires that the metadata uses RecordTypeKeyExpression as the count key. Matches Java's getSnapshotRecordCountForRecordType().
func (*FDBRecordStore) GetStoreHeader ¶
func (store *FDBRecordStore) GetStoreHeader() *gen.DataStoreInfo
GetStoreHeader returns a copy of the current store header proto. Goroutine-safe via stateMu (read lock). Matches Java's FDBRecordStore.getRecordStoreState().getStoreHeader().
func (*FDBRecordStore) GetSubspace ¶
func (store *FDBRecordStore) GetSubspace() subspace.Subspace
GetSubspace returns the FDB subspace for this store. Matches Java's FDBRecordStore.getSubspace().
func (*FDBRecordStore) GetUserVersion ¶
func (store *FDBRecordStore) GetUserVersion() int32
GetUserVersion returns the user-defined store version. Goroutine-safe via stateMu (read lock). Matches Java's FDBRecordStore.getUserVersion().
func (*FDBRecordStore) GetValueSizeLimit ¶
func (store *FDBRecordStore) GetValueSizeLimit() int
GetValueSizeLimit returns the maximum value size in bytes for index entries. Matches Java's FDBRecordStore.getValueSizeLimit().
func (*FDBRecordStore) GetWriteOnlyIndexes ¶
func (store *FDBRecordStore) GetWriteOnlyIndexes() []*Index
GetWriteOnlyIndexes returns all indexes that are in WRITE_ONLY state. These are indexes currently being built by an OnlineIndexer. Matches Java's FDBRecordStoreBase.getWriteOnlyIndexes() (derived from getAllIndexStates).
func (*FDBRecordStore) IndexSecondarySubspace ¶
func (store *FDBRecordStore) IndexSecondarySubspace(index *Index) subspace.Subspace
IndexSecondarySubspace returns the secondary subspace for a specific index. Matches Java's FDBRecordStore.indexSecondarySubspace(index).
func (*FDBRecordStore) IndexStateSubspace ¶
func (store *FDBRecordStore) IndexStateSubspace() subspace.Subspace
IndexStateSubspace returns the subspace where index states are stored. Matches Java's FDBRecordStore.indexStateSubspace().
func (*FDBRecordStore) IndexSubspace ¶
func (store *FDBRecordStore) IndexSubspace(index *Index) subspace.Subspace
IndexSubspace returns the subspace for a specific index's entries. Matches Java's FDBRecordStore.indexSubspace(index).
func (*FDBRecordStore) InsertRecord ¶
func (store *FDBRecordStore) InsertRecord(record proto.Message) (*FDBStoredRecord[proto.Message], error)
InsertRecord saves a record and throws an error if it already exists. This is equivalent to SaveRecordWithOptions(record, RecordExistenceCheckErrorIfExists).
Java equivalent: FDBRecordStore.insertRecordAsync(Message rec) Java location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/FDBRecordStoreBase.java:629
Returns:
- *FDBStoredRecord: The saved record with metadata
- error: RecordAlreadyExistsError if a record with the same primary key already exists
func (*FDBRecordStore) IsCacheable ¶
func (store *FDBRecordStore) IsCacheable() bool
IsCacheable returns whether the store state is marked as cacheable in the header. Goroutine-safe via stateMu (read lock). Matches Java's FDBRecordStore.getRecordStoreState().getStoreHeader().getCacheable().
func (*FDBRecordStore) IsIndexDisabled ¶
func (store *FDBRecordStore) IsIndexDisabled(indexName string) bool
IsIndexDisabled returns true if the index is in DISABLED state.
func (*FDBRecordStore) IsIndexReadable ¶
func (store *FDBRecordStore) IsIndexReadable(indexName string) bool
IsIndexReadable returns true if the index is in READABLE state.
func (*FDBRecordStore) IsIndexReadableUniquePending ¶
func (store *FDBRecordStore) IsIndexReadableUniquePending(indexName string) bool
IsIndexReadableUniquePending returns true if the index is in READABLE_UNIQUE_PENDING state. This state means the unique index is fully indexed but may have duplicate entries. Matches Java's FDBRecordStoreBase.isIndexReadableUniquePending().
func (*FDBRecordStore) IsIndexScannable ¶
func (store *FDBRecordStore) IsIndexScannable(indexName string) bool
IsIndexScannable returns true if the index can be scanned (READABLE or READABLE_UNIQUE_PENDING).
func (*FDBRecordStore) IsIndexWriteOnly ¶
func (store *FDBRecordStore) IsIndexWriteOnly(indexName string) bool
IsIndexWriteOnly returns true if the index is in WRITE_ONLY state.
func (*FDBRecordStore) IsStateCacheable ¶
func (store *FDBRecordStore) IsStateCacheable() bool
IsStateCacheable returns whether this store's state is currently cacheable. Goroutine-safe via stateMu (read lock).
func (*FDBRecordStore) IsVersionChanged ¶
func (store *FDBRecordStore) IsVersionChanged() bool
IsVersionChanged returns true if the metadata version changed during the most recent Open/CreateOrOpen (i.e., checkPossiblyRebuild detected that the stored version < current metadata version). Matches Java's FDBRecordStore.isVersionChanged().
func (*FDBRecordStore) LoadBuildProgress ¶
func (store *FDBRecordStore) LoadBuildProgress(index *Index) (int64, error)
LoadBuildProgress reads the records-scanned counter for an index build. Returns 0 if no progress has been tracked. Matches Java's IndexBuildState.loadRecordsScannedAsync().
func (*FDBRecordStore) LoadIndexingTypeStamp ¶
func (store *FDBRecordStore) LoadIndexingTypeStamp(index *Index) (*gen.IndexBuildIndexingStamp, error)
LoadIndexingTypeStamp loads the indexing method stamp for an index. Returns nil if no stamp exists. Matches Java's FDBRecordStore.loadIndexingTypeStampAsync().
func (*FDBRecordStore) LoadRecord ¶
func (store *FDBRecordStore) LoadRecord(primaryKey tuple.Tuple) (*FDBStoredRecord[proto.Message], error)
LoadRecord loads a record by its primary key. Handles both unsplit (suffix 0) and split (suffixes 1, 2, ...) records via SplitHelper, matching Java's FDBRecordStore.loadRecordAsync().
func (*FDBRecordStore) LoadRecordVersion ¶
func (store *FDBRecordStore) LoadRecordVersion(primaryKey tuple.Tuple, snapshot bool) (*FDBRecordVersion, error)
LoadRecordVersion loads the version associated with a record. Returns nil if no version is stored or versioning is not enabled. Matches Java's FDBRecordStore.loadRecordVersionAsync().
func (*FDBRecordStore) MarkIndexDisabled ¶
func (store *FDBRecordStore) MarkIndexDisabled(indexName string) (bool, error)
MarkIndexDisabled transitions an index to DISABLED state and clears all index data. Returns true if the state was changed. Matches Java's FDBRecordStore.markIndexDisabled().
func (*FDBRecordStore) MarkIndexReadable ¶
func (store *FDBRecordStore) MarkIndexReadable(indexName string) (bool, error)
MarkIndexReadable transitions an index to READABLE state. Returns true if the state was changed, false if already READABLE. Returns an error if the index is not fully built or if a unique index has violations. Matches Java's FDBRecordStore.markIndexReadable(index, allowUniquePending=false).
func (*FDBRecordStore) MarkIndexReadableOrUniquePending ¶
func (store *FDBRecordStore) MarkIndexReadableOrUniquePending(indexName string) (bool, error)
MarkIndexReadableOrUniquePending transitions a unique index to READABLE if it has no uniqueness violations, or to READABLE_UNIQUE_PENDING if violations exist. For non-unique indexes, always transitions to READABLE. Returns true if the state was changed. Returns an error if the index is not fully built. Matches Java's FDBRecordStore.markIndexReadableOrUniquePending().
func (*FDBRecordStore) MarkIndexWriteOnly ¶
func (store *FDBRecordStore) MarkIndexWriteOnly(indexName string) (bool, error)
MarkIndexWriteOnly transitions an index to WRITE_ONLY state. Returns true if the state was changed. Matches Java's FDBRecordStore.markIndexWriteOnly().
func (*FDBRecordStore) OverrideLockSaveRecord ¶
func (store *FDBRecordStore) OverrideLockSaveRecord( record proto.Message, existenceCheck RecordExistenceCheck, ) (*FDBStoredRecord[proto.Message], error)
OverrideLockSaveRecord saves a record even when the store is locked for record updates (FORBID_RECORD_UPDATE). This is used by the OnlineIndexer to write index maintenance records while the store is locked. Goroutine-safe: uses parameter-based override instead of mutable field. Matches Java's FDBRecordStore.overrideLockSaveRecordAsync().
func (*FDBRecordStore) RebuildAllIndexes ¶
func (store *FDBRecordStore) RebuildAllIndexes() error
RebuildAllIndexes rebuilds all indexes that are not in READABLE state. Matches Java's FDBRecordStore.rebuildAllIndexes().
func (*FDBRecordStore) RebuildIndex ¶
func (store *FDBRecordStore) RebuildIndex(index *Index) error
RebuildIndex rebuilds an index within the current transaction. Clears existing index data, scans all records, and re-indexes them. Upon completion, the index is marked READABLE.
Because this runs in a single transaction, it is limited by FDB's 5-second time limit and 10MB transaction size. For large stores, use OnlineIndexer.BuildIndex() which splits work across transactions.
Matches Java's FDBRecordStore.rebuildIndex() which delegates to IndexingBase.rebuildIndexAsync() for the in-transaction path.
func (*FDBRecordStore) RecordExists ¶
func (store *FDBRecordStore) RecordExists(primaryKey tuple.Tuple, isolationLevel IsolationLevel) (bool, error)
RecordExists checks if a record exists with the given primary key. Handles both split and unsplit records via SplitHelper.
Java equivalent: FDBRecordStore.recordExistsAsync(Tuple primaryKey, IsolationLevel isolationLevel)
func (*FDBRecordStore) RecordsSubspace ¶
func (store *FDBRecordStore) RecordsSubspace() subspace.Subspace
RecordsSubspace returns the subspace where records are stored. Matches Java's FDBRecordStore.recordsSubspace().
func (*FDBRecordStore) ReleaseReadLock ¶
func (store *FDBRecordStore) ReleaseReadLock(key string)
func (*FDBRecordStore) ReleaseWriteLock ¶
func (store *FDBRecordStore) ReleaseWriteLock(key string)
func (*FDBRecordStore) ReloadRecordStoreState ¶
func (store *FDBRecordStore) ReloadRecordStoreState() error
ReloadRecordStoreState forces a reload of the store state from FDB. Useful when another transaction may have changed the state. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.loadRecordStoreStateAsync() force reload path.
func (*FDBRecordStore) ResolveUniquenessViolation ¶
func (store *FDBRecordStore) ResolveUniquenessViolation(index *Index, indexKey tuple.Tuple, primaryKey tuple.Tuple) error
ResolveUniquenessViolation removes a single uniqueness violation entry. Call this after manually resolving the conflict (e.g., deleting the duplicate record). Matches Java's StandardIndexMaintainer.resolveUniquenessViolation().
func (*FDBRecordStore) ResolveUniquenessViolationByDeletion ¶
func (store *FDBRecordStore) ResolveUniquenessViolationByDeletion( index *Index, valueKey tuple.Tuple, remainPrimaryKey tuple.Tuple, ) error
ResolveUniquenessViolationByDeletion resolves uniqueness violations for a specific index value key by deleting all records that violate uniqueness, except for the record with remainPrimaryKey (if non-nil). If remainPrimaryKey is nil, all violating records are deleted. Matches Java's FDBRecordStore.resolveUniquenessViolation(index, valueKey, remainPrimaryKey).
func (*FDBRecordStore) SaveIndexingTypeStamp ¶
func (store *FDBRecordStore) SaveIndexingTypeStamp(index *Index, stamp *gen.IndexBuildIndexingStamp) error
SaveIndexingTypeStamp persists the indexing method stamp for an index. Matches Java's FDBRecordStore.saveIndexingTypeStamp().
func (*FDBRecordStore) SaveRecord ¶
func (store *FDBRecordStore) SaveRecord(record proto.Message) (*FDBStoredRecord[proto.Message], error)
SaveRecord saves a protobuf record to the store. Equivalent to SaveRecordWithOptions(record, RecordExistenceCheckNone). Java equivalent: FDBRecordStore.saveRecord(Message rec)
func (*FDBRecordStore) SaveRecordBatch ¶
func (store *FDBRecordStore) SaveRecordBatch( records []proto.Message, ) ([]*FDBStoredRecord[proto.Message], error)
SaveRecordBatch saves multiple records with pipelined existence checks.
Instead of N sequential blocking FDB reads (one per record in SaveRecord), this method issues all existence-check Gets up front as futures, then collects them in one batch. This turns N round trips into ~1 round trip for the existence checks, significantly improving throughput for batch inserts.
Semantically equivalent to calling SaveRecord N times. All records are saved in the current transaction.
func (*FDBRecordStore) SaveRecordWithOptions ¶
func (store *FDBRecordStore) SaveRecordWithOptions( record proto.Message, existenceCheck RecordExistenceCheck, ) (*FDBStoredRecord[proto.Message], error)
SaveRecordWithOptions saves a protobuf record with existence checking. This is the full-featured save method that supports all RecordExistenceCheck modes.
Java equivalent: FDBRecordStore.saveRecordAsync(Message rec, RecordExistenceCheck existenceCheck, FDBRecordVersion version, VersionstampSaveBehavior behavior) Java location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/FDBRecordStore.java:496
Parameters:
- record: The protobuf message to save
- existenceCheck: Validation to perform (NONE, ERROR_IF_EXISTS, etc.)
Returns:
- *FDBStoredRecord: The saved record with metadata
- error: RecordAlreadyExistsError, RecordDoesNotExistError, or RecordTypeChangedError based on existenceCheck
Note: Version and versionstamp support will be added in Phase 2
func (*FDBRecordStore) ScanIndex ¶
func (store *FDBRecordStore) ScanIndex( index *Index, scanRange TupleRange, continuation []byte, scanProperties ScanProperties, ) RecordCursor[*IndexEntry]
ScanIndex scans a secondary index and returns a cursor over IndexEntry results. Returns an error cursor if the index is not in a scannable state (DISABLED or WRITE_ONLY). Dispatches to the appropriate maintainer's Scan() method (VALUE vs COUNT). Matches Java's FDBRecordStore.scanIndex().
func (*FDBRecordStore) ScanIndexByType ¶
func (store *FDBRecordStore) ScanIndexByType( index *Index, scanType IndexScanType, scanRange TupleRange, continuation []byte, scanProperties ScanProperties, ) RecordCursor[*IndexEntry]
ScanIndexByType scans a secondary index with an explicit scan type. For BY_VALUE, delegates to the maintainer's Scan. For BY_RANK, converts rank range to score range and scans the B-tree. Matches Java's FDBRecordStore.scanIndex(index, scanType, range, ...).
func (*FDBRecordStore) ScanIndexRecords ¶
func (store *FDBRecordStore) ScanIndexRecords( indexName string, scanRange TupleRange, continuation []byte, scanProperties ScanProperties, ) RecordCursor[*FDBIndexedRecord]
ScanIndexRecords scans a secondary index and fetches the actual records. For each index entry, it loads the record by primary key. An orphan index entry (pointing to a record that no longer exists) raises a RecordCoreStorageError — this mirrors Java's scanIndexRecords, whose default IndexOrphanBehavior is ERROR (not SKIP), so store corruption surfaces loudly instead of returning fewer records. Matches Java's FDBRecordStore.scanIndexRecords().
func (*FDBRecordStore) ScanRecordKeys ¶
func (store *FDBRecordStore) ScanRecordKeys( continuation []byte, scanProperties ScanProperties, ) RecordCursor[tuple.Tuple]
ScanRecordKeys scans only the primary keys of records without deserializing record data. This is significantly faster than ScanRecords when you only need the keys (avoids protobuf deserialization overhead). Split records (multiple KV entries per PK) are automatically deduplicated. Matches Java's FDBRecordStore.scanRecordKeys().
func (*FDBRecordStore) ScanRecords ¶
func (store *FDBRecordStore) ScanRecords(continuation []byte, scanProperties ScanProperties) RecordCursor[*FDBStoredRecord[proto.Message]]
ScanRecords scans all records in the store. For forward scans, continuation sets the low endpoint (start after last returned key). For reverse scans, continuation sets the high endpoint (end before last returned key). Matches Java's KeyValueCursorBase behavior.
func (*FDBRecordStore) ScanRecordsByType ¶
func (store *FDBRecordStore) ScanRecordsByType(recordTypeName string, continuation []byte, scanProperties ScanProperties) RecordCursor[*FDBStoredRecord[proto.Message]]
ScanRecordsByType scans records filtered to a specific record type. When the primary key uses RecordTypeKey() as its first component (common pattern), this does a prefix scan on just that type's range — O(records of this type) instead of O(all records). Falls back to full scan + filter if RecordTypeKey is not used. Matches Java's RecordQuery with RecordTypeFilter.
func (*FDBRecordStore) ScanRecordsInRange ¶
func (store *FDBRecordStore) ScanRecordsInRange( low, high tuple.Tuple, lowEndpoint, highEndpoint EndpointType, continuation []byte, scanProperties ScanProperties, ) RecordCursor[*FDBStoredRecord[proto.Message]]
ScanRecordsInRange scans records in a key range.
This is the ONE place EventScanRecords is recorded, because it is the one method every record scan funnels through — ScanRecords, ScanRecordsByType and the query executor's range scans all end here. Java makes the same choice for the same reason: its single recording site is the innermost private scanTypedRecords (FDBRecordStore.java:1441), never the outer convenience wrappers, so no entry point can scan records without the event and none can record it twice. Instrumenting the outer wrapper instead left the executor's own scans — which enter here directly — entirely uncounted.
func (*FDBRecordStore) ScanTimeWindowLeaderboard ¶
func (store *FDBRecordStore) ScanTimeWindowLeaderboard( index *Index, scanType IndexScanType, leaderboardType int, leaderboardTimestamp int64, scanRange TupleRange, continuation []byte, scanProperties ScanProperties, ) RecordCursor[*IndexEntry]
ScanTimeWindowLeaderboard scans a TIME_WINDOW_LEADERBOARD index within a specific time window. The scanType determines how the range is interpreted:
- BY_TIME_WINDOW / BY_VALUE: scanRange contains score bounds
- BY_RANK: scanRange contains rank bounds (converted to score bounds via RankedSet)
Matches Java's FDBRecordStore.scanIndex() with TimeWindowScanRange.
func (*FDBRecordStore) ScanUniquenessViolations ¶
func (store *FDBRecordStore) ScanUniquenessViolations(index *Index) ([]UniquenessViolation, error)
ScanUniquenessViolations returns all uniqueness violations recorded for the given index. Violations are stored in the IndexUniquenessViolationsKey (7) subspace. Matches Java's StandardIndexMaintainer.scanUniquenessViolations().
func (*FDBRecordStore) ScanUniquenessViolationsForValue ¶
func (store *FDBRecordStore) ScanUniquenessViolationsForValue( index *Index, valueKey tuple.Tuple, ) ([]UniquenessViolation, error)
ScanUniquenessViolationsForValue returns uniqueness violations for a specific index value key. This filters violations to only those matching the given value key. Matches Java's StandardIndexMaintainer.scanUniquenessViolations(index, valueKey).
func (*FDBRecordStore) ScanVectorIndex ¶
func (store *FDBRecordStore) ScanVectorIndex( index *Index, queryVector []float64, k int, efSearch int, continuation []byte, scanProperties ScanProperties, ) RecordCursor[*IndexEntry]
ScanVectorIndex scans a VECTOR index with BY_DISTANCE semantics, returning results as a cursor. This is the cursor-based API matching Java's VectorIndexMaintainer.scan(VectorIndexScanBounds, ...).
Each result is an IndexEntry with Key = primaryKey and Value = tuple{distance}. Results are sorted by distance (closest first).
For prefix-partitioned indexes, use ScanVectorIndexWithPrefix instead.
func (*FDBRecordStore) ScanVectorIndexWithPrefix ¶
func (store *FDBRecordStore) ScanVectorIndexWithPrefix( index *Index, prefix tuple.Tuple, queryVector []float64, k int, efSearch int, continuation []byte, scanProperties ScanProperties, ) RecordCursor[*IndexEntry]
ScanVectorIndexWithPrefix scans a VECTOR index with BY_DISTANCE semantics, scoped to a specific prefix partition. Pass nil prefix for non-grouped indexes.
Each result is an IndexEntry with Key = primaryKey and Value = tuple{distance}. Results are sorted by distance (closest first).
func (*FDBRecordStore) SearchVectorIndex ¶
func (store *FDBRecordStore) SearchVectorIndex( index *Index, queryVector []float64, k int, efSearch int, ) ([]VectorSearchResult, error)
SearchVectorIndex performs a k-nearest-neighbor search on a VECTOR index. Matches Java's VectorIndexMaintainer scan with VectorIndexScanBounds.
For prefix-partitioned indexes, use SearchVectorIndexWithPrefix instead.
func (*FDBRecordStore) SearchVectorIndexRecords ¶
func (store *FDBRecordStore) SearchVectorIndexRecords( ctx context.Context, index *Index, queryVector []float64, k int, efSearch int, ) ([]*FDBIndexedRecord, error)
SearchVectorIndexRecords performs a kNN search and fetches the corresponding records.
For prefix-partitioned indexes, use SearchVectorIndexRecordsWithPrefix instead.
func (*FDBRecordStore) SearchVectorIndexRecordsWithPrefix ¶
func (store *FDBRecordStore) SearchVectorIndexRecordsWithPrefix( ctx context.Context, index *Index, prefix tuple.Tuple, queryVector []float64, k int, efSearch int, ) ([]*FDBIndexedRecord, error)
SearchVectorIndexRecordsWithPrefix performs a kNN search scoped to a prefix partition and fetches the corresponding records.
func (*FDBRecordStore) SearchVectorIndexWithPrefix ¶
func (store *FDBRecordStore) SearchVectorIndexWithPrefix( index *Index, prefix tuple.Tuple, queryVector []float64, k int, efSearch int, ) ([]VectorSearchResult, error)
SearchVectorIndexWithPrefix performs a k-nearest-neighbor search on a VECTOR index, scoped to a specific prefix partition. Pass nil prefix for non-grouped indexes.
func (*FDBRecordStore) SetFormatVersion ¶
func (store *FDBRecordStore) SetFormatVersion(version int32) error
SetFormatVersion updates the store's format version in the header. This is used during store migration to enable new features. Matches Java's FDBRecordStore.setFormatVersion().
func (*FDBRecordStore) SetHeaderUserField ¶
func (store *FDBRecordStore) SetHeaderUserField(key string, value []byte) error
SetHeaderUserField sets a user-defined field in the store header. The value is persisted immediately. Keep values small since the entire header is loaded on every store open. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.setHeaderUserField().
func (*FDBRecordStore) SetStateCacheability ¶
func (store *FDBRecordStore) SetStateCacheability(cacheable bool) (bool, error)
SetStateCacheability sets whether this store's state can be cached across transactions. When enabled, the metadata version stamp is initialized so cache invalidation can work. Requires FormatVersion >= CACHEABLE_STATE (7). Returns true if the cacheability was changed, false if already at the desired state. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.setStateCacheabilityAsync().
func (*FDBRecordStore) SetStoreLockState ¶
func (store *FDBRecordStore) SetStoreLockState(state gen.DataStoreInfo_StoreLockState_State, reason string) error
SetStoreLockState sets the store lock state in the header and persists it. Use FORBID_RECORD_UPDATE to prevent record mutations, or FULL_STORE to prevent the store from being opened entirely. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.setStoreLockStateAsync().
func (*FDBRecordStore) SetUserVersion ¶
func (store *FDBRecordStore) SetUserVersion(version int32) error
SetUserVersion updates the user-defined store version and writes it to FDB. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.setUserVersion().
func (*FDBRecordStore) Subspace ¶
func (store *FDBRecordStore) Subspace() subspace.Subspace
Subspace returns the subspace this store is using
func (*FDBRecordStore) UpdateIncarnation ¶
func (store *FDBRecordStore) UpdateIncarnation(updater func(current int32) int32) error
UpdateIncarnation atomically updates the incarnation counter using the provided function. The new value must be strictly greater than the current value. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.updateIncarnation().
func (*FDBRecordStore) UpdateRecord ¶
func (store *FDBRecordStore) UpdateRecord(record proto.Message) (*FDBStoredRecord[proto.Message], error)
UpdateRecord saves a record and throws an error if it does not already exist or if its type has changed. This is equivalent to SaveRecordWithOptions(record, RecordExistenceCheckErrorIfNotExistsOrTypeChanged).
Java equivalent: FDBRecordStore.updateRecordAsync(Message rec) Java location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/FDBRecordStoreBase.java:649
Returns:
- *FDBStoredRecord: The saved record with metadata
- error: RecordDoesNotExistError if no record exists with this primary key
- error: RecordTypeChangedError if an existing record has a different type
func (*FDBRecordStore) UpdateRecordCountState ¶
func (store *FDBRecordStore) UpdateRecordCountState(newState gen.DataStoreInfo_RecordCountState) error
UpdateRecordCountState transitions the record count state. Valid transitions: READABLE↔WRITE_ONLY, any→DISABLED. DISABLED is terminal. When transitioning to DISABLED, clears all count data. Goroutine-safe via stateMu (write lock). Matches Java's FDBRecordStore.updateRecordCountStateAsync().
func (*FDBRecordStore) VacuumReadableIndexesBuildData ¶
func (store *FDBRecordStore) VacuumReadableIndexesBuildData()
VacuumReadableIndexesBuildData clears build artifacts (range sets, stamps, progress counters) for indexes that are already READABLE. Matches Java's FDBRecordStore.vacuumReadableIndexesBuildData().
func (*FDBRecordStore) ValidateIndex ¶
func (store *FDBRecordStore) ValidateIndex(ctx context.Context, index *Index) (*IndexValidationResult, error)
ValidateIndex checks the consistency of an index against the actual records. Detects missing entries (record exists but index entry missing) and orphaned entries (index entry exists but no corresponding record). Matches Java's StandardIndexMaintainer.validateEntries().
type FDBRecordStoreStateCache ¶
type FDBRecordStoreStateCache interface {
// Get retrieves store state, using the cache if possible.
// On cache hit, adds a read conflict on the STORE_INFO key to ensure
// the transaction fails if concurrent modifications occur.
// On cache miss, loads fresh state from FDB.
Get(store *FDBRecordStore, existenceCheck StoreExistenceCheck) (*FDBRecordStoreStateCacheEntry, error)
// Clear removes all cached entries.
Clear()
}
FDBRecordStoreStateCache caches store state (header + index states) across transactions to avoid repeated reads of the store info key on every store open. Matches Java's FDBRecordStoreStateCache interface.
func PassThroughStoreStateCache ¶
func PassThroughStoreStateCache() FDBRecordStoreStateCache
PassThroughStoreStateCache returns the singleton pass-through cache.
type FDBRecordStoreStateCacheEntry ¶
type FDBRecordStoreStateCacheEntry struct {
// contains filtered or unexported fields
}
FDBRecordStoreStateCacheEntry holds a cached snapshot of store state along with the metadata version stamp that was current when the state was loaded. Matches Java's FDBRecordStoreStateCacheEntry.
func (*FDBRecordStoreStateCacheEntry) GetMetaDataVersionStamp ¶
func (e *FDBRecordStoreStateCacheEntry) GetMetaDataVersionStamp() []byte
GetMetaDataVersionStamp returns the metadata version stamp captured at load time.
func (*FDBRecordStoreStateCacheEntry) GetRecordStoreState ¶
func (e *FDBRecordStoreStateCacheEntry) GetRecordStoreState() *RecordStoreState
GetRecordStoreState returns the cached store state.
type FDBRecordVersion ¶
type FDBRecordVersion struct {
// contains filtered or unexported fields
}
FDBRecordVersion represents a version associated with a record in the store. Matches Java's FDBRecordVersion exactly: - 12 bytes total: 10-byte global version (FDB versionstamp) + 2-byte local version - Global version: 8-byte DB commit version (big-endian) + 2-byte batch ordering - Local version: per-transaction counter (big-endian uint16)
Versions can be "complete" (global version known) or "incomplete" (pending commit). Incomplete versions have all-0xFF in the global version bytes.
func CompleteVersionFromBytes ¶
func CompleteVersionFromBytes(b []byte) (*FDBRecordVersion, error)
CompleteVersionFromBytes parses a complete 12-byte version. Rejects versions with all-0xFF global bytes (incomplete marker). Matches Java's FDBRecordVersion.complete(byte[], boolean) constructor validation.
func FirstInDBVersion ¶
func FirstInDBVersion(dbVersion int64) *FDBRecordVersion
FirstInDBVersion returns the first version with the given DB commit version. The batch and local portions are set to 0. Matches Java's FDBRecordVersion.firstInDBVersion().
func FirstInGlobalVersion ¶
func FirstInGlobalVersion(globalVersion []byte) (*FDBRecordVersion, error)
FirstInGlobalVersion returns the first version with the given 10-byte global version. The local version is set to 0. Matches Java's FDBRecordVersion.firstInGlobalVersion().
func FromVersionstamp ¶
func FromVersionstamp(vs tuple.Versionstamp) *FDBRecordVersion
FromVersionstamp creates a complete FDBRecordVersion from an FDB tuple.Versionstamp. Matches Java's FDBRecordVersion.fromVersionstamp(Versionstamp).
func IncompleteVersion ¶
func IncompleteVersion(localVersion int) (*FDBRecordVersion, error)
IncompleteVersion creates an incomplete version with the given local version. The global version is set to all-0xFF (will be filled in at commit time).
func LastInDBVersion ¶
func LastInDBVersion(dbVersion int64) *FDBRecordVersion
LastInDBVersion returns the last version with the given DB commit version. The batch portion is set to 0xFFFF and local to 0xFFFF. Matches Java's FDBRecordVersion.lastInDBVersion().
func LastInGlobalVersion ¶
func LastInGlobalVersion(globalVersion []byte) (*FDBRecordVersion, error)
LastInGlobalVersion returns the last version with the given 10-byte global version. The local version is set to 0xFFFF. Matches Java's FDBRecordVersion.lastInGlobalVersion().
func MaxVersion ¶
func MaxVersion() *FDBRecordVersion
MaxVersion returns the maximum possible complete version. Matches Java's FDBRecordVersion.MAX_VERSION:
global bytes 0-8: 0xFF, byte 9: 0xFE (0xFF...FF would mean incomplete) local bytes 10-11: 0xFF
func MinVersion ¶
func MinVersion() *FDBRecordVersion
MinVersion returns the minimum possible complete version (all zeros). Matches Java's FDBRecordVersion.MIN_VERSION.
func NewCompleteVersion ¶
func NewCompleteVersion(globalVersion []byte, localVersion int) (*FDBRecordVersion, error)
NewCompleteVersion creates a complete version from 10-byte global version and local version.
func (*FDBRecordVersion) Equal ¶
func (v *FDBRecordVersion) Equal(other *FDBRecordVersion) bool
Equal returns true if two versions are equal. Complete versions compare all 12 bytes; incomplete versions compare local version only. Matches Java's FDBRecordVersion.equals().
func (*FDBRecordVersion) GetDBVersion ¶
func (v *FDBRecordVersion) GetDBVersion() (int64, error)
GetDBVersion returns the 8-byte FDB commit version (big-endian). Returns an error if the version is incomplete.
func (*FDBRecordVersion) GetGlobalVersion ¶
func (v *FDBRecordVersion) GetGlobalVersion() ([]byte, error)
GetGlobalVersion returns the 10-byte global versionstamp. Returns an error if the version is incomplete.
func (*FDBRecordVersion) GetLocalVersion ¶
func (v *FDBRecordVersion) GetLocalVersion() int
GetLocalVersion returns the 2-byte local version counter.
func (*FDBRecordVersion) IsComplete ¶
func (v *FDBRecordVersion) IsComplete() bool
IsComplete returns true if the global version is known.
func (*FDBRecordVersion) Less ¶
func (v *FDBRecordVersion) Less(other *FDBRecordVersion) bool
Less returns true if v sorts before other. Complete versions sort before incomplete. Among versions of the same completeness, lexicographic byte comparison of the full 12-byte raw representation. Matches Java's FDBRecordVersion.compareTo().
func (*FDBRecordVersion) Next ¶
func (v *FDBRecordVersion) Next() (*FDBRecordVersion, error)
Next returns the version immediately after this one. For complete versions: treats all 12 bytes as big-endian unsigned integer, +1 with carry. For incomplete versions: only increments local version (last 2 bytes). Matches Java's FDBRecordVersion.next().
func (*FDBRecordVersion) Prev ¶
func (v *FDBRecordVersion) Prev() (*FDBRecordVersion, error)
Prev returns the version immediately before this one. For complete versions: treats all 12 bytes as big-endian unsigned integer, -1 with borrow. For incomplete versions: only decrements local version (last 2 bytes). Matches Java's FDBRecordVersion.prev().
func (*FDBRecordVersion) String ¶
func (v *FDBRecordVersion) String() string
String returns a human-readable representation matching Java's toString(). Format: "FDBRecordVersion(complete=<bool>, raw=<hex>)"
func (*FDBRecordVersion) ToBytes ¶
func (v *FDBRecordVersion) ToBytes() []byte
ToBytes serializes the version to 12 bytes.
func (*FDBRecordVersion) ToVersionstamp ¶
func (v *FDBRecordVersion) ToVersionstamp() (tuple.Versionstamp, error)
ToVersionstamp converts this complete version to an FDB tuple.Versionstamp. Returns an error if the version is incomplete. Matches Java's FDBRecordVersion.toVersionstamp().
func (*FDBRecordVersion) WithCommittedVersion ¶
func (v *FDBRecordVersion) WithCommittedVersion(committedVersion []byte) (*FDBRecordVersion, error)
WithCommittedVersion completes an incomplete version using the committed versionstamp. This is called after transaction commit when the real versionstamp is known. Returns an error if the version is already complete. Matches Java's FDBRecordVersion.withCommittedVersion().
type FDBStoredRecord ¶
type FDBStoredRecord[M proto.Message] struct { // PrimaryKey is the record's primary key PrimaryKey tuple.Tuple // RecordType is the type of this record RecordType *RecordType // Record is the actual record data Record M // Version is the record's version, if loaded. // Matches Java's FDBStoredRecord.getVersion(). Version *FDBRecordVersion // Store is the record store this record belongs to. // Used by FunctionKeyExpression (e.g. get_versionstamp_incarnation) to access store state. // Matches Java's FDBRecord.getStore(). Store *FDBRecordStore // Storage size information KeyCount int KeySize int ValueSize int // Whether the record is split across multiple keys Split bool }
FDBStoredRecord represents a record that has been stored in or loaded from FDB This is generic to match Java's FDBStoredRecord<M extends Message>
func (*FDBStoredRecord[M]) HasVersion ¶
func (r *FDBStoredRecord[M]) HasVersion() bool
HasVersion returns whether this stored record has a version. Matches Java's FDBStoredRecord.hasVersion().
type FanType ¶
type FanType int
FanType controls how repeated (list) proto fields are handled in key expressions. Matches Java's com.apple.foundationdb.record.metadata.expressions.KeyExpression.FanType.
const ( // FanTypeNone means the field must not be repeated. This is the default. FanTypeNone FanType = iota // FanTypeFanOut produces one tuple per repeated value — used for multi-entry indexes. FanTypeFanOut // FanTypeConcatenate puts all repeated values into a single tuple element. FanTypeConcatenate )
type FieldKeyExpression ¶
type FieldKeyExpression struct {
// contains filtered or unexported fields
}
FieldKeyExpression extracts a single field value from a record for use as a key component. For repeated fields, use FanOut() or Concatenate() to control multi-value handling.
func (*FieldKeyExpression) ColumnSize ¶
func (f *FieldKeyExpression) ColumnSize() int
ColumnSize returns 1 — a field expression produces a single tuple element.
func (*FieldKeyExpression) Evaluate ¶
func (f *FieldKeyExpression) Evaluate(_ *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate extracts the field value(s) from the message. For non-repeated fields, returns one tuple with the single value. For repeated fields with FanOut, returns one tuple per value. For repeated fields with Concatenate, returns one tuple containing a nested tuple of all values.
func (*FieldKeyExpression) EvaluateFlat ¶
func (f *FieldKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
EvaluateFlat returns the scalar value directly as a single-element []any.
func (*FieldKeyExpression) EvaluateInt64 ¶
func (f *FieldKeyExpression) EvaluateInt64(record *FDBStoredRecord[proto.Message], msg proto.Message) (int64, bool, error)
EvaluateInt64 returns the field value as int64 without boxing. Returns (0, false, nil) for nil/unset fields, (val, true, nil) for integer fields.
func (*FieldKeyExpression) EvaluateScalar ¶
func (f *FieldKeyExpression) EvaluateScalar(record *FDBStoredRecord[proto.Message], msg proto.Message) (any, error)
EvaluateScalar returns the single scalar value directly — zero allocs for the return.
func (*FieldKeyExpression) FieldNames ¶
func (f *FieldKeyExpression) FieldNames() []string
FieldNames returns the field name accessed by this expression
func (*FieldKeyExpression) PackDirect ¶
func (f *FieldKeyExpression) PackDirect(pk *tuple.Packer, _ *FDBStoredRecord[proto.Message], msg proto.Message) bool
PackDirect encodes the field value directly into a Packer without boxing into any. Returns false if the field is nil/unset or not a directly-packable type.
func (*FieldKeyExpression) ToKeyExpression ¶
func (f *FieldKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes a FieldKeyExpression to proto. Matches Java's FieldKeyExpression.toKeyExpression(): the nullInterpretation field is written EXPLICITLY even at its NOT_UNIQUE default — the stored bytes carry it (byte-golden-pinned).
type FlatEvaluator ¶
type FlatEvaluator interface {
EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
}
FlatEvaluator is an optional interface for KeyExpressions that can return a single tuple directly without the [][]any wrapper. Avoids 1 alloc per call.
type FormerIndex ¶
FormerIndex tracks a deleted index for schema evolution safety. Prevents accidental reuse of an index's subspace key after deletion. Matches Java's com.apple.foundationdb.record.metadata.FormerIndex.
type FoundSplitOutOfOrderError ¶
type FoundSplitOutOfOrderError struct {
Expected int64 // LogMessageKeys.SPLIT_EXPECTED
Found int64 // LogMessageKeys.SPLIT_FOUND
KeyTuple tuple.Tuple // LogMessageKeys.KEY_TUPLE — the key whose suffix broke the sequence
}
FoundSplitOutOfOrderError is raised when a split record's segments are present but not in sequence — segment N+1 was expected and something else was found.
Ports Java's SplitHelper.FoundSplitOutOfOrderException (SplitHelper.java:1225-1231), which extends RecordCoreStorageException and carries LogMessageKeys.SPLIT_EXPECTED / SPLIT_FOUND. Java additionally attaches KEY_TUPLE and SUBSPACE at the throw site (SplitHelper.java:826-828); KeyTuple carries the first of those, and the subspace is implicit in it here.
It is a distinct type from FoundSplitWithoutStartError on purpose, because the two describe different damage: this one says the record's pieces are all there but mis-sequenced, which points at a writer that interleaved or a range that spans two records. A caller that wants to tell "corrupt but complete" from "truncated" cannot do it from a formatted string.
func (*FoundSplitOutOfOrderError) Error ¶
func (e *FoundSplitOutOfOrderError) Error() string
func (*FoundSplitOutOfOrderError) Unwrap ¶
func (e *FoundSplitOutOfOrderError) Unwrap() error
Unwrap reports this as storage corruption. Java's exception IS a RecordCoreStorageException; Go spells that relationship out so a caller matching the general storage-corruption type keeps working, the way `catch (RecordCoreStorageException)` does.
type FoundSplitWithoutStartError ¶
type FoundSplitWithoutStartError struct {
NextIndex int64 // LogMessageKeys.SPLIT_NEXT_INDEX — the segment found instead of the start
Reverse bool // LogMessageKeys.SPLIT_REVERSE — direction of the scan that found it
KeyTuple tuple.Tuple // LogMessageKeys.KEY_TUPLE
}
FoundSplitWithoutStartError is raised when a split record's continuation segments are found with no start segment — the record is truncated at the front, not merely mis-ordered.
Ports Java's SplitHelper.FoundSplitWithoutStartException (SplitHelper.java:1213-1219), carrying LogMessageKeys.SPLIT_NEXT_INDEX and SPLIT_REVERSE, plus KEY_TUPLE from the throw sites.
Java chooses between this and FoundSplitOutOfOrderException by whether any start-or-later segment has already been seen — `lastIndex >= START_SPLIT_RECORD` picks out-of-order, otherwise without-start (SplitHelper.java:824-835). Go raised one untyped error for both, so a truncated record and a scrambled one were indistinguishable to every caller and to every log.
Reverse matters for reading the report: under a reverse scan the segments arrive highest-first, so "no start yet" is the expected intermediate state rather than evidence of damage, and Java records which direction produced the judgement.
func (*FoundSplitWithoutStartError) Error ¶
func (e *FoundSplitWithoutStartError) Error() string
type FunctionEvaluator ¶
type FunctionEvaluator func(record *FDBStoredRecord[proto.Message], msg proto.Message, arguments [][]any) ([][]any, error)
FunctionEvaluator evaluates a named function on a record. Arguments are the pre-evaluated argument tuples from the arguments expression.
type FunctionKeyExpression ¶
type FunctionKeyExpression struct {
// contains filtered or unexported fields
}
FunctionKeyExpression evaluates a named function on records to produce index key values. The function is resolved from the global registry by name. Matches Java's FunctionKeyExpression abstract class.
func FunctionExpr ¶
func FunctionExpr(name string, arguments KeyExpression) *FunctionKeyExpression
FunctionExpr creates a FunctionKeyExpression with the given name and arguments. The function must be registered in the global registry before evaluation. Matches Java's FunctionKeyExpression.create(name, arguments).
func OrderFuncExpr ¶
func OrderFuncExpr(direction string, arguments KeyExpression) *FunctionKeyExpression
OrderFuncExpr creates a FunctionKeyExpression for ordering with the given direction name and arguments. Convenience wrapper matching Java's OrderFunctionKeyExpression constructor.
func (*FunctionKeyExpression) Arguments ¶
func (f *FunctionKeyExpression) Arguments() KeyExpression
Arguments returns the arguments key expression.
func (*FunctionKeyExpression) ColumnSize ¶
func (f *FunctionKeyExpression) ColumnSize() int
ColumnSize returns 1 — a function expression produces a single tuple element.
func (*FunctionKeyExpression) Evaluate ¶
func (f *FunctionKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate resolves the named function from the registry, evaluates arguments, and applies the function. Matches Java's FunctionKeyExpression.evaluateMessage().
func (*FunctionKeyExpression) FieldNames ¶
func (f *FunctionKeyExpression) FieldNames() []string
FieldNames returns field names from the arguments expression.
func (*FunctionKeyExpression) Name ¶
func (f *FunctionKeyExpression) Name() string
Name returns the function name.
func (*FunctionKeyExpression) ToKeyExpression ¶
func (f *FunctionKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes a FunctionKeyExpression to proto. Matches Java's FunctionKeyExpression.toKeyExpression().
type GroupingKeyExpression ¶
type GroupingKeyExpression struct {
// contains filtered or unexported fields
}
GroupingKeyExpression wraps a key expression and divides its columns into "grouping" (leading) and "grouped" (trailing) parts. The grouping columns form the GROUP BY key, and the grouped columns are the aggregated values. Matches Java's com.apple.foundationdb.record.metadata.expressions.GroupingKeyExpression.
func GroupAll ¶
func GroupAll(expr KeyExpression) *GroupingKeyExpression
GroupAll creates a GroupingKeyExpression where all columns are "grouping" and there are no aggregated columns. Used for COUNT indexes where the entire expression forms the GROUP BY key. Example: GroupAll(Field("price")) → count grouped by price. Matches Java's new GroupingKeyExpression(expr, 0).
func GroupBy ¶
func GroupBy(grouped KeyExpression, groupBy ...KeyExpression) *GroupingKeyExpression
GroupBy creates a GroupingKeyExpression that groups by the given expressions and treats the receiver as the aggregated value. Example: Field("score").GroupBy(Field("game_id")) →
wholeKey = Concat(game_id, score), groupedCount = 1
Matches Java's KeyExpression.groupBy().
func Ungrouped ¶
func Ungrouped(expr KeyExpression) *GroupingKeyExpression
Ungrouped creates a GroupingKeyExpression where all columns are "grouped" (aggregated) and there are no grouping columns. Used for ungrouped counts. Example: Ungrouped(EmptyKey()) → count all records with no grouping. Matches Java's KeyExpression.ungrouped().
func (*GroupingKeyExpression) ColumnSize ¶
func (g *GroupingKeyExpression) ColumnSize() int
ColumnSize delegates to the whole key expression's column size.
func (*GroupingKeyExpression) Evaluate ¶
func (g *GroupingKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate delegates to the whole key expression. The grouping/grouped split is metadata, not evaluation logic.
func (*GroupingKeyExpression) EvaluateFlat ¶
func (g *GroupingKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
EvaluateFlat delegates to the whole key's EvaluateFlat if available.
func (*GroupingKeyExpression) FieldNames ¶
func (g *GroupingKeyExpression) FieldNames() []string
FieldNames returns field names from the whole key.
func (*GroupingKeyExpression) GetGroupedCount ¶
func (g *GroupingKeyExpression) GetGroupedCount() int
GetGroupedCount returns the number of trailing "grouped" (aggregated) columns.
func (*GroupingKeyExpression) GetGroupingCount ¶
func (g *GroupingKeyExpression) GetGroupingCount() int
GetGroupingCount returns the number of leading "grouping" (GROUP BY) columns.
func (*GroupingKeyExpression) ToKeyExpression ¶
func (g *GroupingKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes GroupingKeyExpression to proto. Matches Java's GroupingKeyExpression.toKeyExpression().
type HNSWConfig ¶
type HNSWConfig struct {
NumDimensions int
M int // Connectivity factor (default 16)
MMax int // Max connections for non-zero layers (default 16 — Java DEFAULT_M_MAX, a constant, NOT derived from M; setting M > 16 requires setting MMax too, like Java)
MMax0 int // Max connections for layer 0 (default 32 — Java DEFAULT_M_MAX_0, a constant, NOT derived from M)
EfConstruction int // Insertion search factor (default 200)
Metric VectorMetric // Distance metric
ExtendCandidates bool // Extend candidate set with 2nd-degree neighbors (default false)
KeepPrunedConnections bool // Retain pruned candidates to fill up to M (default false)
EfRepair int // Delete-repair beam width; Java requires [m, 400] (default 64; 0 means "use default")
UseInlining bool // Use inlining storage for layers > 0 (default false)
Quantizer VectorQuantizer // Optional quantizer (nil = raw float64 storage)
// RaBitQ centroid-bootstrap stats (Java Config). When RaBitQ is enabled and no centroid
// is yet established, inserts sample vectors into the SAMPLES subspace, periodically roll
// them up, and once StatsThreshold vectors have accumulated, establish the rotated centroid.
SampleVectorStatsProbability float64 // prob of sampling each inserted vector (default 0.5)
MaintainStatsProbability float64 // prob of rolling up samples on an insert (default 0.05)
StatsThreshold int // accumulated count needed to establish the centroid (default 1000)
// Concurrency limits — Java uses these to limit async pipeline parallelism.
// Go's synchronous FDB model doesn't use these for concurrency control, but
// we store and round-trip them so Java-written configs are preserved.
// Matches Java's Config.maxNumConcurrentNodeFetches etc.
MaxNumConcurrentNodeFetches int // (0, 64], default 16 — node fetch parallelism in Java
MaxNumConcurrentNeighborhoodFetches int // (0, 20], default 10 — neighborhood fetch parallelism in Java
MaxNumConcurrentDeleteFromLayer int // (0, 10], default 2 — layer deletion parallelism in Java
}
HNSWConfig configures an HNSW graph. Matches Java's com.apple.foundationdb.async.hnsw.Config.
func DefaultHNSWConfig ¶
func DefaultHNSWConfig(numDimensions int) HNSWConfig
DefaultHNSWConfig returns a default HNSW configuration.
type HNSWStats ¶
type HNSWStats struct {
FDBGets atomic.Int64 // individual Get() calls (point reads)
FDBBatchGets atomic.Int64 // batched Get() calls (pipelined, count as 1 RT)
FDBRangeReads atomic.Int64 // GetRange() calls
CacheHits atomic.Int64 // reads served from in-tx cache
}
HNSWStats tracks I/O counters for a single HNSW operation. Attach to a context via WithHNSWStats and retrieve via GetHNSWStats. Zero cost when not attached — all tracking is behind a nil check.
func GetHNSWStats ¶
GetHNSWStats retrieves HNSWStats from a context, or nil if not tracking.
type IncompleteVersionstampError ¶
type IncompleteVersionstampError struct {
// Context names the encoder that refused, e.g. the index whose entry was
// being written.
Context string
}
IncompleteVersionstampError is returned when a tuple carrying an INCOMPLETE versionstamp reaches an encoder that can only write a complete one.
The Java counterpart is the IllegalArgumentException thrown by TupleOrdering.packNullsLast (TupleOrdering.java:178) and by Tuple.pack, whose message this reproduces verbatim. Java THROWS; the Go port used to reach the same condition through tuple.Pack, which PANICS — a library-boundary crash where Java hands the caller a recoverable failure. Every site that can put a versionstamp in front of a vanilla pack returns this instead.
Reachable from ordinary DDL: an index whose version column lands in the VALUE portion of a KeyWithValue split, or one that wraps the version in an ordering function. Both metadata shapes are what Java's own index generator emits (see IndexTest.java createVersionIndexWithVersionInValue), so the shapes cannot be rejected at DDL without diverging on index metadata — the failure belongs at the write, exactly where Java puts it.
func (*IncompleteVersionstampError) Error ¶
func (e *IncompleteVersionstampError) Error() string
type Index ¶
type Index struct {
Name string
Type string
RootExpression KeyExpression
Options map[string]string
AddedVersion int
LastModifiedVersion int
// Predicate filters which records are included in this index.
// If nil, all records are indexed. If set, only records where
// Predicate returns true are indexed (sparse/filtered index).
Predicate IndexPredicate
// contains filtered or unexported fields
}
func NewBitmapValueIndex ¶
func NewBitmapValueIndex(name string, rootExpression KeyExpression) *Index
NewBitmapValueIndex creates a BITMAP_VALUE index with the given name and root key expression. BITMAP_VALUE indexes store one bit per record in fixed-size bitmaps, using atomic BIT_OR/BIT_AND operations for set/clear. The position field is the last grouped column. Matches Java's new Index(name, rootExpression, IndexTypes.BITMAP_VALUE).
func NewCountIndex ¶
func NewCountIndex(name string, rootExpression KeyExpression) *Index
NewCountIndex creates a COUNT index with the given name and root key expression. COUNT indexes use FDB atomic ADD to maintain counts per grouping key. Matches Java's new Index(name, rootExpression, IndexTypes.COUNT).
func NewCountNotNullIndex ¶
func NewCountNotNullIndex(name string, rootExpression KeyExpression) *Index
NewCountNotNullIndex creates a COUNT_NOT_NULL index with the given name and root key expression. Like COUNT, but skips entries where the key contains a null value (nil element). Matches Java's new Index(name, rootExpression, IndexTypes.COUNT_NOT_NULL).
func NewCountUpdatesIndex ¶
func NewCountUpdatesIndex(name string, rootExpression KeyExpression) *Index
NewCountUpdatesIndex creates a COUNT_UPDATES index with the given name and root key expression. Like COUNT, but deletes are no-ops (count never decrements) and updates always re-count (skipUpdateForUnchangedKeys = false). Tracks total insert+update events. Matches Java's new Index(name, rootExpression, IndexTypes.COUNT_UPDATES).
func NewGroupCountCompanion ¶
NewGroupCountCompanion builds the companion COUNT(*) index for a grouped SUM or COUNT(col) index: same record type, same grouping key, same predicate, GroupAll (zero grouped columns) so its stored value is the group's row count.
Carrying the owner's predicate is a divergence from the RFC text, which defines the companion by grouping key alone. Without it, a sparse owner's companion counts rows the owner never indexed, and the merge would report groups that hold no qualifying row — an invented group, which is the very defect the companion exists to remove.
Returns false when idx needs no companion or its grouping key cannot be split.
func NewIndex ¶
func NewIndex(name string, rootExpression KeyExpression) *Index
NewIndex creates a VALUE index with the given name and root key expression. Matches Java's new Index(name, rootExpression) which defaults to IndexTypes.VALUE.
func NewMaxEverLongIndex ¶
func NewMaxEverLongIndex(name string, rootExpression KeyExpression) *Index
NewMaxEverLongIndex creates a MAX_EVER_LONG index with the given name and root key expression. MAX_EVER_LONG indexes use FDB atomic MAX to track the maximum value seen per grouping key. Values must be non-negative (unsigned comparison). Deletes are no-ops (_EVER = irreversible). Matches Java's new Index(name, rootExpression, IndexTypes.MAX_EVER_LONG).
func NewMaxEverTupleIndex ¶
func NewMaxEverTupleIndex(name string, rootExpression KeyExpression) *Index
NewMaxEverTupleIndex creates a MAX_EVER_TUPLE index with the given name and root key expression. MAX_EVER_TUPLE indexes use FDB atomic BYTE_MAX to track the maximum tuple-packed value per grouping key. Unlike MAX_EVER_LONG, accepts any tuple-encodable type and compares via byte ordering. Deletes are no-ops (_EVER = irreversible). Idempotent. Matches Java's new Index(name, rootExpression, IndexTypes.MAX_EVER_TUPLE).
func NewMaxEverVersionIndex ¶
func NewMaxEverVersionIndex(name string, rootExpression KeyExpression) *Index
NewMaxEverVersionIndex creates a MAX_EVER_VERSION index that tracks the maximum version ever written per grouping key. The root expression must be a GroupingKeyExpression with exactly 1 VersionKeyExpression in the grouped (aggregated) portion. Matches Java's new Index(name, rootExpression, IndexTypes.MAX_EVER_VERSION).
func NewMinEverLongIndex ¶
func NewMinEverLongIndex(name string, rootExpression KeyExpression) *Index
NewMinEverLongIndex creates a MIN_EVER_LONG index with the given name and root key expression. MIN_EVER_LONG indexes use FDB atomic MIN to track the minimum value seen per grouping key. Values must be non-negative (unsigned comparison). Deletes are no-ops (_EVER = irreversible). Matches Java's new Index(name, rootExpression, IndexTypes.MIN_EVER_LONG).
func NewMinEverTupleIndex ¶
func NewMinEverTupleIndex(name string, rootExpression KeyExpression) *Index
NewMinEverTupleIndex creates a MIN_EVER_TUPLE index with the given name and root key expression. MIN_EVER_TUPLE indexes use FDB atomic BYTE_MIN to track the minimum tuple-packed value per grouping key. Unlike MIN_EVER_LONG, accepts any tuple-encodable type and compares via byte ordering. Deletes are no-ops (_EVER = irreversible). Idempotent. Matches Java's new Index(name, rootExpression, IndexTypes.MIN_EVER_TUPLE).
func NewMultidimensionalIndex ¶
func NewMultidimensionalIndex(name string, rootExpression KeyExpression) *Index
NewMultidimensionalIndex creates a MULTIDIMENSIONAL index backed by a Hilbert R-tree. The root expression must be a DimensionsKeyExpression that specifies prefix, dimensions, and suffix. Matches Java's new Index(name, rootExpression, IndexTypes.MULTIDIMENSIONAL).
func NewPermutedMaxIndex ¶
func NewPermutedMaxIndex(name string, rootExpression KeyExpression, permutedSize int) *Index
NewPermutedMaxIndex creates a PERMUTED_MAX index with the given name, root key expression, and permuted size. The permuted size specifies how many trailing grouping columns are permuted to after the value in the secondary subspace, enabling value-ordered scans. Matches Java's new Index(name, rootExpression, IndexTypes.PERMUTED_MAX) with PERMUTED_SIZE_OPTION.
func NewPermutedMinIndex ¶
func NewPermutedMinIndex(name string, rootExpression KeyExpression, permutedSize int) *Index
NewPermutedMinIndex creates a PERMUTED_MIN index with the given name, root key expression, and permuted size. The permuted size specifies how many trailing grouping columns are permuted to after the value in the secondary subspace, enabling value-ordered scans. Matches Java's new Index(name, rootExpression, IndexTypes.PERMUTED_MIN) with PERMUTED_SIZE_OPTION.
func NewRankIndex ¶
func NewRankIndex(name string, rootExpression KeyExpression) *Index
NewRankIndex creates a RANK index with the given name and root key expression. RANK indexes maintain a B-tree (like VALUE) plus a skip-list ranked set per group for O(log n) rank/select queries. Matches Java's new Index(name, rootExpression, IndexTypes.RANK).
func NewSumIndex ¶
func NewSumIndex(name string, rootExpression KeyExpression) *Index
NewSumIndex creates a SUM index with the given name and root key expression. SUM indexes use FDB atomic ADD to maintain running sums per grouping key. The expression must include at least one grouped (aggregated) column. Matches Java's new Index(name, rootExpression, IndexTypes.SUM).
func NewTextIndex ¶
func NewTextIndex(name string, rootExpression KeyExpression) *Index
NewTextIndex creates a TEXT index with the given name and root key expression. TEXT indexes tokenize string fields and store per-token position lists in a BunchedMap. Matches Java's new Index(name, rootExpression, IndexTypes.TEXT).
func NewTimeWindowLeaderboardIndex ¶
func NewTimeWindowLeaderboardIndex(name string, rootExpression KeyExpression) *Index
NewTimeWindowLeaderboardIndex creates a TIME_WINDOW_LEADERBOARD index. TIME_WINDOW_LEADERBOARD indexes maintain multiple ranked sets, one per time window, enabling time-windowed leaderboard queries. Matches Java's new Index(name, rootExpression, IndexTypes.TIME_WINDOW_LEADERBOARD).
func NewVectorIndex ¶
func NewVectorIndex(name string, rootExpression KeyExpression, numDimensions int) *Index
NewVectorIndex creates a VECTOR index backed by an HNSW graph. The root expression identifies the vector field to index. numDimensions specifies the vector dimensionality. Supports EUCLIDEAN, COSINE, and INNER_PRODUCT metrics. Matches Java's new Index(name, rootExpression, IndexTypes.VECTOR).
func NewVersionIndex ¶
func NewVersionIndex(name string, rootExpression KeyExpression) *Index
NewVersionIndex creates a VERSION index with the given name and root key expression. VERSION indexes store the record's commit version in the index key for version-ordered queries. The root expression should include a VersionKeyExpression (typically via Concat with other fields). Matches Java's new Index(name, rootExpression, IndexTypes.VERSION).
func (*Index) CanonicalType ¶
canonicalIndexType resolves a deprecated index-type alias to the type whose behaviour it names, and returns every other type unchanged.
One function rather than two more `case` labels on each switch, because Java only ever answers this question ONCE. There, the type string picks a maintainer out of the factory registry and every later question — is it idempotent, does it validate grouping, can it serve this aggregate — is a method call on the maintainer that was already chosen. Go flattened that into several independent switches over `idx.Type`, so an alias handled at the dispatch and nowhere else would produce an index that builds with the right maintainer and is then mis-judged by the idempotency check, the grouping validator and the aggregate matcher. Routing every one of those switches through here keeps the alias in a single place, which is the property Java gets for free from its registry. CanonicalType is canonicalIndexType for callers outside this package — the chaos model and its verifier, which re-derive an index's behaviour from its type exactly as the five in-package switches do.
They are the same hazard with a worse failure mode. A model that does not resolve the alias simply DROPS the index: it tracks no min/max for it, the verifier's own switch skips it too, and the pair agrees perfectly about an index neither one looked at. That is a safety net reporting green on the thing it was not checking, which is worse than a wrong answer.
func (*Index) CreatesDuplicates ¶
Index represents a secondary index definition. Matches Java's com.apple.foundationdb.record.metadata.Index. CreatesDuplicates reports whether the index's root key expression fans out — a single record can produce multiple index entries (e.g. an index over a repeated/collection field). Ports Java's index.getRootExpression().createsDuplicates(); such an index does NOT produce distinct records (DistinctRecordsProperty). Returns false when the root expression is unset. FAILS CLOSED (conservatively duplicating) for an UNRECOGNIZED root type so the M4 DistinctRecords signal never mis-reports an unknown-fan-out index as distinct (which would elide a required DISTINCT).
func (*Index) GetBooleanOption ¶
GetBooleanOption returns the boolean value of an index option. Returns the default value if the option is not set. Matches Java's Index.getBooleanOption(String, boolean).
func (*Index) GetPredicateProto ¶
GetPredicateProto returns the proto representation of the predicate, if any. Returns nil for programmatic Go predicates set via SetPredicate(). The returned message is a defensive clone: callers cannot mutate the evaluator's serialized authority through this accessor.
func (*Index) GetReplacedByIndexNames ¶
GetReplacedByIndexNames returns the names of indexes that replace this one. Options with keys starting with "replacedBy" (e.g. "replacedBy", "replacedBy_0") have their values as replacement index names. Matches Java's Index.getReplacedByIndexNames().
func (*Index) HasExplicitSubspaceKey ¶
HasExplicitSubspaceKey reports whether the subspace key was chosen rather than defaulted from the index name. Matches Java's Index.hasExplicitSubspaceKey().
func (*Index) HasFilteringPredicate ¶
HasFilteringPredicate reports whether this index's predicate can actually reject a record — the question anything reasoning about index COMPLETENESS has to ask, as opposed to HasPredicate's question of whether a predicate is declared at all. A predicate that is a proved tautology rejects nothing, so the index holds an entry for every record and a scan over it is not lossy; Java draws the same line at ValueIndexExpansionVisitor.java:141, where a tautological index predicate is simply not attached to the match candidate and the index stays a full value index.
Only the serialized representation can be reasoned about. A programmatic Go predicate is an opaque closure — `func(proto.Message) bool { return true }` is a tautology no one can prove — so it counts as filtering and fails closed.
func (*Index) HasPredicate ¶
HasPredicate reports whether this is a sparse/filtered index. Check both representations: programmatic Go predicates have only Predicate, while serialized metadata carries predicateProto (and normally its compiled evaluator too). Keeping one authority prevents planner adapters from accidentally admitting one representation but not the other.
func (*Index) HasPrimaryKeyComponentPositions ¶
HasPrimaryKeyComponentPositions returns true if the index has computed PK component positions.
NOT SEMANTICALLY IDENTICAL to Java's Index.hasPrimaryKeyComponentPositions(), which is `!= null && IntStream.of(...).anyMatch(i -> i >= 0)` -- this drops the second conjunct, so the two disagree for a non-nil ALL-NEGATIVE array. They agree on everything Build produces, because buildPrimaryKeyComponentPositions returns nil rather than an all-negative array (in both engines), so the divergent state is unreachable from the builder in production. It IS constructible by hand, and metadata_evolution_validator_test.go does exactly that -- so "matches Java" is true of the reachable states and false of the predicate, which is why this says which.
func (*Index) HasRowNumberWindowPredicate ¶
HasRowNumberWindowPredicate reports whether this index declares a row-number window anywhere on a conjunctive path in its stored predicate. Answers only from the SERIALIZED predicate: a programmatic Go predicate is an opaque closure and cannot declare a window. Matches the predicate half of Java's SlidingWindowIndexMaintainerFactory.isSlidingWindowIndex().
func (*Index) IsAtomicMutationIndex ¶
IsAtomicMutationIndex reports whether this index is maintained via FDB atomic mutations that store aggregated or running-extremum entries rather than per-record values. Such indexes (COUNT/SUM totals, MAX_EVER/MIN_EVER running extrema, BITMAP_VALUE bitsets) must never be offered as an ordinary VALUE-index scan source: their entries are not the underlying record values, so an ordered per-record scan (e.g. a StreamingAgg over the index) reads stale/mislaid data.
Mirrors Java, where AtomicMutationIndexMaintainerFactory (count, count_not_null, count_updates, sum, max_ever_*, min_ever_*, max_ever_version) and BitmapValueIndexMaintainerFactory never call expandValueIndexMatchCandidate — these types only ever reach the aggregate expansion path (or none), and their maintainers reject a BY_VALUE scan at runtime. VALUE, VERSION, RANK, and the PERMUTED_MIN/MAX types are deliberately excluded here: they are genuinely value-scannable (their Java maintainers support BY_VALUE).
func (*Index) IsClearWhenZero ¶
IsClearWhenZero returns whether this index should clear entries when values reach zero. When true, atomic ADD mutations are followed by CompareAndClear(zero) to remove stale zero-value entries. Applies to COUNT, COUNT_NOT_NULL, and SUM indexes. Matches Java's IndexOptions.CLEAR_WHEN_ZERO.
func (*Index) IsUnique ¶
IsUnique returns whether this index enforces a uniqueness constraint. Matches Java's Index.isUnique() which checks IndexOptions.UNIQUE_OPTION.
func (*Index) PrimaryKeyComponentPositions ¶
PrimaryKeyComponentPositions returns the overlap mapping between index key and primary key. nil means no overlap was computed. Matches Java's Index.getPrimaryKeyComponentPositions().
func (*Index) RowNumberWindowSpec ¶
func (idx *Index) RowNumberWindowSpec() (*RowNumberWindowSpec, error)
RowNumberWindowSpec returns the window declaration the MAINTAINER will use, or an error when the index carries no usable one. Uses Java's narrower maintainer-side lookup — see qualifyRowNumberWindowPredicateProto.
func (*Index) SetClearWhenZero ¶
SetClearWhenZero enables or disables the clear-when-zero behavior. Matches Java's IndexOptions.CLEAR_WHEN_ZERO.
func (*Index) SetPredicate ¶
func (idx *Index) SetPredicate(p IndexPredicate) *Index
SetPredicate sets a filter predicate for sparse/filtered indexes. Only records where the predicate returns true will have index entries. Note: programmatic Go predicates cannot be serialized to proto. Use SetPredicateProto for predicates that must survive metadata round-tripping.
func (*Index) SetPredicateProto ¶
SetPredicateProto sets a predicate from a proto message. This both stores the proto for round-tripping and builds an evaluator function.
func (*Index) SetSubspaceKey ¶
SetSubspaceKey overrides the default subspace key (index name). Matches Java's Index.setSubspaceKey(), including its side effect of MARKING the key explicit — see useExplicitSubspaceKey.
func (*Index) SubspaceTupleKey ¶
SubspaceTupleKey returns the key used to identify this index's subspace within the IndexKey (2) subspace. Defaults to the index name. Matches Java's Index.getSubspaceTupleKey().
func (*Index) TrimPrimaryKey ¶
trimPrimaryKey removes PK components that already appear in the index key. Returns the remaining PK components that need to be appended to the index entry. Returns an error if primaryKeyComponentPositions references an index beyond the primary key length. Matches Java's Index.TrimPrimaryKey().
type IndexAggregateFunction ¶
type IndexAggregateFunction struct {
Name string // Function name (e.g. "count", "sum", "min_ever")
Operand KeyExpression // The operand (typically a GroupingKeyExpression)
Index string // Optional: explicit index name. Empty = auto-select.
}
IndexAggregateFunction specifies an aggregate computation to evaluate via an index. Matches Java's com.apple.foundationdb.record.metadata.IndexAggregateFunction.
func NewCountAggregateFunction ¶
func NewCountAggregateFunction(operand KeyExpression) *IndexAggregateFunction
NewCountAggregateFunction creates a COUNT aggregate function. Matches Java's IndexAggregateFunction(FunctionNames.COUNT, operand).
func NewMaxAggregateFunction ¶
func NewMaxAggregateFunction(operand KeyExpression) *IndexAggregateFunction
NewMaxAggregateFunction creates a MAX aggregate function (via VALUE index).
func NewMaxEverAggregateFunction ¶
func NewMaxEverAggregateFunction(operand KeyExpression) *IndexAggregateFunction
NewMaxEverAggregateFunction creates a MAX_EVER aggregate function.
func NewMinAggregateFunction ¶
func NewMinAggregateFunction(operand KeyExpression) *IndexAggregateFunction
NewMinAggregateFunction creates a MIN aggregate function (via VALUE index).
func NewMinEverAggregateFunction ¶
func NewMinEverAggregateFunction(operand KeyExpression) *IndexAggregateFunction
NewMinEverAggregateFunction creates a MIN_EVER aggregate function.
func NewSumAggregateFunction ¶
func NewSumAggregateFunction(operand KeyExpression) *IndexAggregateFunction
NewSumAggregateFunction creates a SUM aggregate function.
type IndexBuildState ¶
type IndexBuildState struct {
State IndexState
RecordsScanned *int64 // nil if not WRITE_ONLY or not tracked
RecordsInTotal *int64 // nil if no COUNT index available
}
IndexBuildState reports the current state of an index build. Matches Java's com.apple.foundationdb.record.provider.foundationdb.IndexBuildState.
func LoadIndexBuildState ¶
func LoadIndexBuildState(store *FDBRecordStore, index *Index) (*IndexBuildState, error)
LoadIndexBuildState loads the build state for an index within an open store. Matches Java's IndexBuildState.loadIndexBuildStateAsync().
type IndexEntry ¶
type IndexEntry struct {
Index *Index
Key tuple.Tuple // Full key (indexed values + primary key components)
Value tuple.Tuple // Value tuple (empty for VALUE indexes)
// contains filtered or unexported fields
}
IndexEntry represents a single entry from an index scan. Matches Java's com.apple.foundationdb.record.IndexEntry.
func (*IndexEntry) IndexValues ¶
func (e *IndexEntry) IndexValues() tuple.Tuple
IndexValues extracts the indexed values portion from the entry key. Returns the prefix of Key up to the index expression's column count.
func (*IndexEntry) PrimaryKey ¶
func (e *IndexEntry) PrimaryKey() tuple.Tuple
PrimaryKey extracts the primary key portion from the index entry key. When the index has primaryKeyComponentPositions, some PK components are pulled from the index key portion (deduplicated) and the rest from the appended tail. Matches Java's IndexEntry.getPrimaryKey() → Index.getEntryPrimaryKey().
type IndexKeySizeError ¶
IndexKeySizeError indicates an index entry key exceeds the FDB key size limit. Matches Java's FDBExceptions.FDBStoreKeySizeException.
func (*IndexKeySizeError) Error ¶
func (e *IndexKeySizeError) Error() string
type IndexMaintainer ¶
type IndexMaintainer interface {
// Update updates the index for a record change.
// oldRecord is nil for inserts, newRecord is nil for deletes.
Update(oldRecord, newRecord *FDBStoredRecord[proto.Message]) error
// UpdateWhileWriteOnly updates the index during WRITE_ONLY state (index being built).
// For idempotent indexes (VALUE), this is a pass-through to Update().
// For non-idempotent indexes, checks if the record's PK is in the already-built range.
// Matches Java's standardIndexMaintainer.updateWhileWriteOnly().
UpdateWhileWriteOnly(oldRecord, newRecord *FDBStoredRecord[proto.Message]) error
// Scan scans the index within the given tuple range.
// Matches Java's IndexMaintainer.scan().
Scan(scanRange TupleRange, continuation []byte, scanProperties ScanProperties) RecordCursor[*IndexEntry]
// DeleteWhere clears all index entries whose key starts with the given prefix.
// Uses FDB range clears — no scanning. Called by DeleteRecordsWhere.
// Matches Java's IndexMaintainer.deleteWhere().
DeleteWhere(prefix tuple.Tuple) error
// CanDeleteWhere reports whether this maintainer can clear exactly the
// entries the given prefix names, returning the reason it cannot.
// Matches Java's IndexMaintainer.canDeleteWhere.
//
// It is part of the interface — not an optional capability a maintainer may
// leave out — for the same reason Java declares it ABSTRACT: a new index
// type must not be able to reach the DeleteRecordsWhere path without having
// decided what its physical keys are prefixed by. That is not hypothetical:
// while the check was an optional interface here, the bound was absent on
// one type after another — RANK's ranked sets, PERMUTED's permuted
// secondary, the aggregates' grouping keys, TEXT's bunched tokens — because
// an optional check reads "does not implement it" and "can clear any prefix"
// as the same answer, and the first is by far the more common. Closing that
// one index type at a time converges only as fast as someone thinks to look;
// a compile error converges immediately.
//
// standardIndexMaintainer supplies the default, so a type embedding it gets
// the bound its root expression implies and overrides only to NARROW it.
//
// WHERE the question is asked is the other half, and it cannot be left to
// DeleteWhere. DeleteRecordsWhere queues the record, version and count
// clears BEFORE calling any maintainer, so a refusal raised inside
// DeleteWhere arrives after the records are already gone from the
// transaction: a caller that logs the error and commits anyway loses the
// records while the index keeps describing them. Every refusal therefore
// belongs in the store's preflight, and the matching check inside
// DeleteWhere stays only as a backstop for direct callers — which is exactly
// the split Java has between canDeleteWhere and the Verify.verify inside
// deleteWhere.
CanDeleteWhere(prefix tuple.Tuple) error
}
IndexMaintainer handles index updates and scanning. Matches Java's com.apple.foundationdb.record.provider.foundationdb.IndexMaintainer.
type IndexNotBuiltError ¶
type IndexNotBuiltError struct {
IndexName string
}
IndexNotBuiltError is returned when trying to mark an index as readable but it has unbuilt ranges remaining in its range set.
func (*IndexNotBuiltError) Error ¶
func (e *IndexNotBuiltError) Error() string
type IndexNotFoundError ¶
type IndexNotFoundError struct {
IndexName string
}
IndexNotFoundError is returned when an index name is not found in the metadata. Matches Java's MetaDataException for missing indexes.
func (*IndexNotFoundError) Error ¶
func (e *IndexNotFoundError) Error() string
type IndexNotReadableError ¶
type IndexNotReadableError struct {
IndexName string
CurrentState IndexState
}
IndexNotReadableError is returned when trying to scan an index that is not in a readable state. Matches Java's com.apple.foundationdb.record.ScanNonReadableIndexException.
func (*IndexNotReadableError) Error ¶
func (e *IndexNotReadableError) Error() string
type IndexPredicate ¶
IndexPredicate is a function that determines whether a record should be indexed. Return true to include the record in the index, false to skip it. Matches Java's Index predicate concept for sparse/filtered indexes.
type IndexRebuildPolicy ¶
type IndexRebuildPolicy func(index *Index, recordCount int64, indexOnNewRecordTypes bool) IndexState
IndexRebuildPolicy determines what state a new/changed index should be put in when the store is opened with updated metadata. Matches Java's FDBRecordStoreBase.UserVersionChecker.needRebuildIndex().
type IndexRecordFunction ¶
type IndexRecordFunction struct {
Name string // Function name (e.g. "rank")
Operand KeyExpression // The operand (typically a GroupingKeyExpression)
Index string // Optional: explicit index name. Empty = auto-select.
// TimeWindow specifies the leaderboard time window for TIME_WINDOW_RANK and
// TIME_WINDOW_RANK_AND_ENTRY functions. Nil for plain RANK (uses all-time).
// Matches Java's TimeWindowRecordFunction.timeWindow (TimeWindowForFunction).
TimeWindow *TimeWindowForFunction
}
IndexRecordFunction specifies a function to evaluate on a record using an index. Matches Java's com.apple.foundationdb.record.metadata.IndexRecordFunction.
type IndexScanType ¶
type IndexScanType string
IndexScanType identifies the type of index scan. Matches Java's com.apple.foundationdb.record.IndexScanType.
const ( // IndexScanByValue scans a VALUE index by its indexed values. IndexScanByValue IndexScanType = "BY_VALUE" // IndexScanByRank scans a RANK index by rank position. // The range bounds contain [group..., rank] where rank is an int64. // Matches Java's IndexScanType.BY_RANK. IndexScanByRank IndexScanType = "BY_RANK" // IndexScanByTextToken scans a TEXT index by text token. // Matches Java's IndexScanType.BY_TEXT_TOKEN. IndexScanByTextToken IndexScanType = "BY_TEXT_TOKEN" // IndexScanByGroup scans a PERMUTED_MIN/MAX index by group in the // secondary (permuted) subspace. Returns one entry per group with the // extremum value, ordered by [groupPrefix, value, groupSuffix]. // Matches Java's IndexScanType.BY_GROUP. IndexScanByGroup IndexScanType = "BY_GROUP" // IndexScanByTimeWindow scans a TIME_WINDOW_LEADERBOARD index within a // specific time window. The scan range contains score bounds; the // leaderboard type and timestamp are provided via TimeWindowScanRange. // Matches Java's IndexScanType.BY_TIME_WINDOW. IndexScanByTimeWindow IndexScanType = "BY_TIME_WINDOW" // IndexScanByDistance scans a VECTOR index by distance to a query vector. // Returns results sorted by distance (closest first) as a kNN search. // Must be used with ScanVectorIndex which provides VectorScanBounds. // Matches Java's IndexScanType.BY_DISTANCE. IndexScanByDistance IndexScanType = "BY_DISTANCE" // IndexScanByDistanceOrderedStream is the RFC-156 Phase C VBASE distance- // ordered STREAMING scan: a demand-driven cursor that widens its scanned // horizon in batches as the consumer (Filter → Limit) pulls, bounded by a // budget cap (honest ScanLimitReached truncation, never a silent < k). Go-only // read-side extension; no wire-format change. IndexScanByDistanceOrderedStream IndexScanType = "BY_DISTANCE_ORDERED_STREAM" )
type IndexState ¶
type IndexState int
IndexState represents the state of a secondary index. Matches Java's com.apple.foundationdb.record.IndexState.
const ( // IndexStateReadable means the index is fully built and can be read and written. IndexStateReadable IndexState = 0 // IndexStateWriteOnly means the index is being built. Written to on record changes // but not yet safe for queries. IndexStateWriteOnly IndexState = 1 // IndexStateDisabled means the index is not maintained or readable. IndexStateDisabled IndexState = 2 // IndexStateReadableUniquePending means the unique index is fully indexed but may // have duplicate entries. Safe to query if uniqueness is not assumed. IndexStateReadableUniquePending IndexState = 3 )
func AlwaysRebuildPolicy ¶
func AlwaysRebuildPolicy(_ *Index, _ int64, _ bool) IndexState
AlwaysRebuildPolicy always rebuilds indexes inline. Matches Java's ALWAYS_READABLE_CHECKER behavior.
func DefaultIndexRebuildPolicy ¶
func DefaultIndexRebuildPolicy(index *Index, recordCount int64, indexOnNewRecordTypes bool) IndexState
DefaultIndexRebuildPolicy matches Java's default behavior: inline rebuild (READABLE) for stores with ≤200 records or indexes on new record types, DISABLED otherwise (requires OnlineIndexer). Java constant: FDBRecordStoreBase.MAX_RECORDS_FOR_REBUILD = 200.
func WriteOnlyIfTooLargePolicy ¶
func WriteOnlyIfTooLargePolicy(index *Index, recordCount int64, indexOnNewRecordTypes bool) IndexState
WriteOnlyIfTooLargePolicy returns READABLE for small stores (inline rebuild) and WRITE_ONLY for larger stores. WRITE_ONLY is the production-safe choice: new writes maintain the index immediately, and the operator invokes OnlineIndexer to backfill historical data. This avoids both:
- READABLE: times out on large stores (single-transaction rebuild)
- DISABLED: index is completely ignored, new writes don't maintain it
Threshold matches Java's MAX_RECORDS_FOR_REBUILD = 200.
func (IndexState) IsDisabled ¶
func (s IndexState) IsDisabled() bool
IsDisabled returns true if this index is in DISABLED state.
func (IndexState) IsScannable ¶
func (s IndexState) IsScannable() bool
IsScannable returns true if this state allows index scans. Matches Java's IndexState.isScannable() — READABLE or READABLE_UNIQUE_PENDING.
func (IndexState) IsWriteOnly ¶
func (s IndexState) IsWriteOnly() bool
IsWriteOnly returns true if this index is in WRITE_ONLY state.
func (IndexState) String ¶
func (s IndexState) String() string
type IndexValidationEntry ¶
IndexValidationEntry represents a single missing or orphaned index entry.
type IndexValidationResult ¶
type IndexValidationResult struct {
// MissingEntries are index entries that should exist (based on records) but don't.
MissingEntries []IndexValidationEntry
// OrphanedEntries are index entries that exist but have no corresponding record.
OrphanedEntries []IndexValidationEntry
// TotalRecordsScanned is the number of records checked.
TotalRecordsScanned int
// TotalEntriesScanned is the number of index entries checked.
TotalEntriesScanned int
}
IndexValidationResult contains the results of an index validation.
func (*IndexValidationResult) IsValid ¶
func (r *IndexValidationResult) IsValid() bool
IsValid returns true if no discrepancies were found.
type IndexValueSizeError ¶
IndexValueSizeError indicates an index entry value exceeds the FDB value size limit. Matches Java's FDBExceptions.FDBStoreValueSizeException.
func (*IndexValueSizeError) Error ¶
func (e *IndexValueSizeError) Error() string
type IndexVersionKind ¶
type IndexVersionKind string
IndexVersionKind names which of an index's two version stamps a IndexVersionTooNewError refers to.
const ( // IndexVersionAdded is the version at which the index was introduced. IndexVersionAdded IndexVersionKind = "added" // IndexVersionLastModified is the version at which the index definition last changed. IndexVersionLastModified IndexVersionKind = "last modified" )
type IndexVersionTooNewError ¶
type IndexVersionTooNewError struct {
IndexName string
Kind IndexVersionKind
AddedVersion int
LastModifiedVersion int
MetaDataVersion int
}
IndexVersionTooNewError is returned when an index declares a version that is newer than the metadata version carrying it.
Such metadata is not merely untidy: an index whose lastModifiedVersion exceeds the metadata version is permanently "new since" every store header version, so every subsequent version bump re-runs the rebuild decision for it and can clear an index a background build already populated.
Matches Java's MetaDataValidator.validateIndex(), which throws MetaDataException for both the added-version and last-modified-version cases (MetaDataValidator.java:124-133).
func (*IndexVersionTooNewError) Error ¶
func (e *IndexVersionTooNewError) Error() string
func (*IndexVersionTooNewError) Unwrap ¶
func (e *IndexVersionTooNewError) Unwrap() error
Unwrap reports this as a metadata validation failure so that callers matching on *MetaDataError keep working, mirroring Java where this is a MetaDataException.
type IndexingHeartbeat ¶
type IndexingHeartbeat struct {
// contains filtered or unexported fields
}
IndexingHeartbeat manages liveness heartbeats for concurrent index building. Each indexer process writes a heartbeat at [9, indexSubspaceKey, 7, uuid] so that other processes can detect stale/crashed builders.
In non-mutual (exclusive) mode, an active heartbeat from another process prevents this indexer from starting. In mutual mode, heartbeats are written but not checked (concurrent building is allowed).
Matches Java's IndexingHeartbeat.
func NewIndexingHeartbeat ¶
func NewIndexingHeartbeat(info string, leaseLengthMs int64, allowMutual bool, env *dst.Env) *IndexingHeartbeat
NewIndexingHeartbeat creates a heartbeat manager for an indexer. leaseLengthMs is how long a heartbeat remains valid before being considered stale. env is the DST environment (from the indexer's database, oi.db.Env()); a nil env means production — the UUID and timestamps then come from crypto/rand and the wall clock, byte-identical to the pre-seam behavior.
func (*IndexingHeartbeat) CheckAndUpdate ¶
func (h *IndexingHeartbeat) CheckAndUpdate(tx fdb.WritableTransaction, storeSubspace subspace.Subspace, index *Index) error
CheckAndUpdate checks for conflicting heartbeats and updates this indexer's heartbeat.
In non-mutual mode: scans all heartbeats for this index. If any active (non-stale) heartbeat from a different indexer exists, returns a SynchronizedSessionLockedError. Stale heartbeats (older than leaseLengthMs) are ignored — the process is presumed dead.
In mutual mode: skips the check entirely and just updates.
Called once per buildRange transaction to maintain liveness. Matches Java's IndexingHeartbeat.checkAndUpdateHeartbeat().
func (*IndexingHeartbeat) Cleanup ¶
func (h *IndexingHeartbeat) Cleanup(tx fdb.WritableTransaction, storeSubspace subspace.Subspace, index *Index)
Cleanup removes this indexer's heartbeat. Called when the build completes or is explicitly cancelled. Matches Java's IndexingHeartbeat.removeHeartbeat().
type IndexingPolicy ¶
type IndexingPolicy struct {
// ForceStampOverwrite forces writing the stamp without conflict checks on
// fresh (non-continued) builds, or allows overwriting on continued builds
// when no records have been scanned. Used internally during rebuild.
ForceStampOverwrite bool
// AllowUnblock permits unblocking a blocked stamp during resume.
AllowUnblock bool
// AllowUnblockID restricts unblocking to stamps with a matching blockID.
// Empty string means any blockID is accepted (when AllowUnblock is true).
AllowUnblockID string
// AllowedTakeovers is the set of allowed build method conversions.
AllowedTakeovers map[TakeoverType]bool
}
IndexingPolicy configures how the OnlineIndexer handles stamp conflicts, blocked stamps, and build method conversions. Matches Java's OnlineIndexer.IndexingPolicy.
func (*IndexingPolicy) ShouldAllowTypeConversionContinue ¶
func (p *IndexingPolicy) ShouldAllowTypeConversionContinue(newStamp, savedStamp *gen.IndexBuildIndexingStamp) bool
ShouldAllowTypeConversionContinue returns true if switching from savedStamp's method to newStamp's method is permitted by the policy. Matches Java's IndexingPolicy.shouldAllowTypeConversionContinue().
func (*IndexingPolicy) ShouldAllowUnblock ¶
func (p *IndexingPolicy) ShouldAllowUnblock(stampBlockID string) bool
ShouldAllowUnblock returns true if the policy allows unblocking a stamp with the given blockID. Matches Java's IndexingPolicy.shouldAllowUnblock().
type IndexingRangeSet ¶
type IndexingRangeSet struct {
// contains filtered or unexported fields
}
IndexingRangeSet wraps a RangeSet scoped to a specific index's build progress. Lives at store subspace [IndexRangeSpaceKey (6), indexSubspaceKey]. Wire-compatible with Java's IndexingRangeSet.
func NewIndexingRangeSet ¶
func NewIndexingRangeSet(storeSubspace subspace.Subspace, index *Index) *IndexingRangeSet
NewIndexingRangeSet creates an IndexingRangeSet for the given index within the store's subspace. Matches Java's IndexingRangeSet.forIndexBuild(store, index).
func (*IndexingRangeSet) Clear ¶
func (irs *IndexingRangeSet) Clear(tr fdb.WritableTransaction)
Clear removes all range tracking data.
func (*IndexingRangeSet) ContainsKey ¶
func (irs *IndexingRangeSet) ContainsKey(tr fdb.WritableTransaction, key []byte) (bool, error)
ContainsKey checks if a primary key (tuple-packed bytes) is in the built range.
func (*IndexingRangeSet) FirstMissingRange ¶
func (irs *IndexingRangeSet) FirstMissingRange(tr fdb.WritableTransaction) (*RangeSetRange, error)
FirstMissingRange returns the first gap in the range set, or nil if complete.
func (*IndexingRangeSet) InsertRange ¶
func (irs *IndexingRangeSet) InsertRange(tr fdb.WritableTransaction, begin, end []byte, requireEmpty bool) (bool, error)
InsertRange marks a range as built. Returns true if the database was modified.
func (*IndexingRangeSet) IsComplete ¶
func (irs *IndexingRangeSet) IsComplete(tr fdb.WritableTransaction) (bool, error)
IsComplete returns true if all ranges have been built.
func (*IndexingRangeSet) ListMissingRanges ¶
func (irs *IndexingRangeSet) ListMissingRanges(tr fdb.WritableTransaction) ([]RangeSetRange, error)
ListMissingRanges returns all gaps in the range set.
func (*IndexingRangeSet) ListMissingRangesInBytes ¶
func (irs *IndexingRangeSet) ListMissingRangesInBytes(tr fdb.WritableTransaction, begin, end []byte) ([]RangeSetRange, error)
ListMissingRangesInBytes returns missing ranges within the given byte boundaries. Used by mutual indexing to check missing ranges within a fragment.
type Int64Evaluator ¶
type Int64Evaluator interface {
EvaluateInt64(record *FDBStoredRecord[proto.Message], msg proto.Message) (int64, bool, error)
}
Int64Evaluator extracts a single int64 value without boxing to any. Go's convT64 allocates for every non-zero int64→any conversion. This interface bypasses that by returning int64 directly.
type IntersectionChildResume ¶
IntersectionChildResume is one child's decoded resume state, the output of decodeIntersectionContinuation. Started + (empty) Continuation classify the child as START (!Started → begin fresh), MID (Started + bytes → resume from bytes), or END (Started + empty → exhausted).
func DecodeIntersectionContinuation ¶
func DecodeIntersectionContinuation(data []byte, n int) ([]IntersectionChildResume, error)
DecodeIntersectionContinuation is the exact inverse of buildIntersectionContinuation: it splits a parent IntersectionContinuation proto into n per-child resume states (RFC-071). A nil/empty continuation yields n all-fresh children (START). A proto that fails to parse, or whose child count does not match n, is a hard error (mirroring Java IntersectionCursorContinuation's RecordCoreArgumentException) — never a silent truncate. Consumed executor-side by executeIntersection / executeMultiIntersection.
type InvalidNameError ¶
type InvalidNameError = protoname.InvalidNameError
InvalidNameError mirrors Java's ProtoUtils.InvalidNameException.
type IsolationLevel ¶
type IsolationLevel int
IsolationLevel represents the transaction isolation level. Matches Java's IsolationLevel enum.
Java Reference: com.apple.foundationdb.record.IsolationLevel Location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/IsolationLevel.java
func (IsolationLevel) IsSnapshot ¶
func (level IsolationLevel) IsSnapshot() bool
IsSnapshot returns true if this isolation level uses snapshot reads.
Java equivalent: IsolationLevel.isSnapshot()
func (IsolationLevel) String ¶
func (level IsolationLevel) String() string
String returns a human-readable representation of the isolation level.
type ItemSlot ¶
ItemSlot is a leaf node slot containing a data item.
type KVCallback ¶
type KVCallback func(keyLen, valueLen int)
KVCallback is called for each raw FDB key-value pair read during iteration. Used for byte scan limiting — the callback receives the raw key and value lengths before deserialization. Matches Java's Consumer<KeyValue> callback passed to BunchedMapMultiIterator.
type KeyExpression ¶
type KeyExpression interface {
// Evaluate extracts key tuples from a record.
// Returns a list of key tuples (each tuple is a []any).
// Single-valued expressions return one tuple; fan-out expressions
// (e.g. repeated fields) return multiple tuples.
//
// record is the top-level stored record context (provides version, PK, etc.).
// msg is the current message being evaluated (changes during nesting into sub-messages).
// Either or both may be nil.
//
// Matches Java's KeyExpression.evaluateMessage(FDBRecord, Message) -> List<Key.Evaluated>.
Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
// FieldNames returns the field names this expression accesses
FieldNames() []string
// ColumnSize returns the number of tuple elements this expression produces.
// Matches Java's KeyExpression.getColumnSize().
ColumnSize() int
// ToKeyExpression serializes this expression to its protobuf representation.
// Matches Java's KeyExpression.toKeyExpression().
ToKeyExpression() *gen.KeyExpression
}
KeyExpression represents an expression that extracts key components from a record. Matches Java's KeyExpression interface which returns List<Key.Evaluated>.
func Concat ¶
func Concat(exprs ...KeyExpression) KeyExpression
Concat creates a composite key from multiple expressions
func EmptyKey ¶
func EmptyKey() KeyExpression
EmptyKey creates a key expression that produces an empty tuple.
func FanOut ¶
func FanOut(name string) KeyExpression
FanOut creates a key expression for a repeated field that produces one index entry per repeated value. Matches Java's Key.Expressions.field("name", FanType.FanOut).
func Field ¶
func Field(name string) KeyExpression
Field creates a key expression that extracts a single (non-repeated) field.
func FieldConcatenate ¶
func FieldConcatenate(name string) KeyExpression
FieldConcatenate creates a key expression for a repeated field that collects all repeated values into a single tuple element. Matches Java's Key.Expressions.field("name", FanType.Concatenate). This is the argument shape a CARDINALITY() index uses: the whole array is materialised into one Key.Evaluated so its element count can be taken.
func GetNestedExpression ¶
func GetNestedExpression(expr KeyExpression) KeyExpression
GetNestedExpression returns the nested expression of a RecordTypeKeyExpression
func GroupingKeyExpressionOf ¶
func GroupingKeyExpressionOf(g *GroupingKeyExpression) (KeyExpression, bool)
GroupingKeyExpressionOf returns the GROUPING half of a grouping key expression: the leading columns the index groups by, with the trailing aggregated columns removed. For a COUNT(*) index (no aggregated columns) that is the whole key.
Returns false when the split cannot be made exactly — no grouping columns at all (an ungrouped aggregate), or a child expression that straddles the grouping/grouped boundary. Declining is the only safe answer: a companion matched on a mis-split key would drive the merge from the wrong group set.
func KeyExpressionFromProto ¶
func KeyExpressionFromProto(expr *gen.KeyExpression) (KeyExpression, error)
KeyExpressionFromProto deserializes a protobuf KeyExpression to a Go KeyExpression. Exactly one field must be set. Matches Java's KeyExpression.fromProto().
func Nest ¶
func Nest(parentField string, child KeyExpression) KeyExpression
Nest creates a nesting expression: navigate into a message field and evaluate the child expression on the sub-message. Matches Java's field("parent").nest("child").
func NestFanOut ¶
func NestFanOut(parentField string, child KeyExpression) KeyExpression
NestFanOut creates a nesting expression for a repeated message field. Each element of the repeated field is evaluated with the child expression, producing fan-out. Matches Java's field("parent", FanType.FanOut).nest(child).
type KeyExpressionError ¶
type KeyExpressionError struct {
Message string
}
KeyExpressionError is returned when a key expression evaluation fails. Matches Java's com.apple.foundationdb.record.metadata.expressions.KeyExpression.InvalidExpressionException.
func (*KeyExpressionError) Error ¶
func (e *KeyExpressionError) Error() string
type KeyWithValueExpression ¶
type KeyWithValueExpression struct {
// contains filtered or unexported fields
}
KeyWithValueExpression wraps an inner key expression and splits its evaluated columns into a "key" portion and a "value" portion. The key portion (columns 0..splitPoint-1) is stored in the FDB key, and the value portion (columns splitPoint..end) is stored in the FDB value. This enables "covering indexes" where additional query-relevant columns can be read without fetching the record. Matches Java's com.apple.foundationdb.record.metadata.expressions.KeyWithValueExpression.
func KeyWithValue ¶
func KeyWithValue(inner KeyExpression, splitPoint int) *KeyWithValueExpression
KeyWithValue creates a KeyWithValueExpression. splitPoint is the number of leading columns that go into the FDB key; remaining columns go into the value. Matches Java's Key.Expressions.keyWithValue(inner, splitPoint).
func (*KeyWithValueExpression) ColumnSize ¶
func (k *KeyWithValueExpression) ColumnSize() int
ColumnSize returns the split point — only key columns count, not value columns. Matches Java's KeyWithValueExpression.getColumnSize().
func (*KeyWithValueExpression) Evaluate ¶
func (k *KeyWithValueExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate delegates to the inner key expression. The key/value split is only applied when writing/reading index entries, not during evaluation.
func (*KeyWithValueExpression) FieldNames ¶
func (k *KeyWithValueExpression) FieldNames() []string
FieldNames delegates to the inner key expression.
func (*KeyWithValueExpression) InnerKey ¶
func (k *KeyWithValueExpression) InnerKey() KeyExpression
InnerKey returns the wrapped key expression.
func (*KeyWithValueExpression) SplitEvaluatedKey ¶
func (k *KeyWithValueExpression) SplitEvaluatedKey(fullKey []any) (keyPart []any, valuePart []any)
SplitEvaluatedKey splits a full evaluated result into key and value portions. key = columns[0:splitPoint], value = columns[splitPoint:]. Matches Java's KeyWithValueExpression.getKey() / getValue().
func (*KeyWithValueExpression) SplitPoint ¶
func (k *KeyWithValueExpression) SplitPoint() int
SplitPoint returns the number of leading columns that form the key portion.
func (*KeyWithValueExpression) ToKeyExpression ¶
func (k *KeyWithValueExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes KeyWithValueExpression to proto. Matches Java's KeyWithValueExpression.toKeyExpression().
type Kind ¶
type Kind uint8
Kind classifies an event the way Java's StoreTimer taxonomy does with interfaces (StoreTimer.java:203-402). Java splits the classification across the type system — a bare `Event` is timed, `Count extends Event` adds `isSize()` — and reads it back with `instanceof` in getKeysAndValues (StoreTimer.java:747-780). Go has no sealed interface hierarchy, so the same three-way distinction is carried as data on the one Event struct and read back with a switch. The distinction is not cosmetic: it decides which field of the Counter carries meaning, and therefore how the event may be exported.
const ( // KindUnspecified is the zero value, and no declared event may carry it. // Making the zero value invalid is deliberate: every Event literal in this // package is unkeyed, so adding Kind to the struct made the compiler // demand a classification at each declaration rather than silently // defaulting a new event into whichever kind happened to be zero. KindUnspecified Kind = iota // KindTimed is Java's bare StoreTimer.Event: recorded with Record / // RecordSince, cumulative value is nanoseconds. Both Count() (occurrences) // and CumulativeValue() (total nanos) are meaningful. KindTimed // KindCount is Java's StoreTimer.Count with isSize()==false: recorded with // Increment / IncrementBy, ONLY Count() is meaningful. CumulativeValue() // stays 0, exactly as in Java (Counter.increment touches count alone, // StoreTimer.java:484-487). KindCount // KindSize is Java's StoreTimer.Count with isSize()==true — e.g. // Counts.SAVE_RECORD_KEY_BYTES (FDBStoreTimer.java:524). Recorded and read // exactly like KindCount: the BYTE TOTAL lands in Count(), not in // CumulativeValue(). Kept a distinct kind because it changes what the // number means to a consumer (bytes, not occurrences) even though the // storage is identical. KindSize // KindSizeDistribution is Java's StoreTimer.SizeEvent // (StoreTimer.java:401-402), which is a DIFFERENT thing from the Count above // despite the shared word "size", and the difference is not cosmetic: // // - a size Count answers "how many bytes in total", so one number says // everything and Java increments it; // - a SizeEvent answers "how big was it each time" — Java records it with // recordSize (StoreTimer.java:569-571), which adds the MAGNITUDE to // cumulativeValue and the OBSERVATION to count, and getKeysAndValues // then emits both `_count` and `_size` (StoreTimer.java:756-757). // // Collapsing the second onto the first loses the observation count and // reports a sum of magnitudes under a key that reads as a count — for the // sliding window's SW_WINDOW_COUNT that would render "the window was size 2, // then 2, then 1" as the number 5. KindSizeDistribution )
type ListKeyExpression ¶
type ListKeyExpression struct {
// contains filtered or unexported fields
}
ListKeyExpression combines multiple child expressions, producing nested tuples for each child's result (unlike Then/Concat which flattens). Each child's evaluation result is wrapped as a nested tuple element. Matches Java's com.apple.foundationdb.record.metadata.expressions.ListKeyExpression.
func ListExpr ¶
func ListExpr(children ...KeyExpression) *ListKeyExpression
ListExpr creates a ListKeyExpression from the given children.
func (*ListKeyExpression) ColumnSize ¶
func (l *ListKeyExpression) ColumnSize() int
ColumnSize returns the number of children — each child contributes one column (as a nested tuple element). Matches Java's ListKeyExpression.getColumnSize().
func (*ListKeyExpression) Evaluate ¶
func (l *ListKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate computes the cross-product of all child expression results, wrapping each child's result as a nested tuple.Tuple. Each child's Key.Evaluated values become a single nested tuple element in the result.
This matches Java's ListKeyExpression.evaluateMessage() + combine(), where childValue.toTupleAppropriateList() is added as a single List<Object> element that becomes a nested Tuple when serialized.
IMPORTANT: Child values must be wrapped as tuple.Tuple (named type), NOT bare []any. The FDB tuple packer's type switch uses `case Tuple:` which only matches the named type. Bare []any causes a runtime panic during Pack().
func (*ListKeyExpression) FieldNames ¶
func (l *ListKeyExpression) FieldNames() []string
FieldNames returns all field names from child expressions.
func (*ListKeyExpression) GetChildren ¶
func (l *ListKeyExpression) GetChildren() []KeyExpression
GetChildren returns the child expressions.
func (*ListKeyExpression) ToKeyExpression ¶
func (l *ListKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes ListKeyExpression to proto. Matches Java's ListKeyExpression.toKeyExpression().
type LiteralKeyExpression ¶
type LiteralKeyExpression struct {
// contains filtered or unexported fields
}
LiteralKeyExpression represents a static constant value in a key expression. The value does not depend on the record — it evaluates to the same fixed value for every record. Primary use case: passing static arguments to function key expressions, or creating composite indexes with a fixed prefix. Matches Java's LiteralKeyExpression.
func Literal ¶
func Literal(value any) *LiteralKeyExpression
Literal creates a key expression that always evaluates to the given constant value. Supported types: nil, int, int32, int64, float32, float64, bool, string, []byte. Matches Java's Key.Expressions.value(Object).
func (*LiteralKeyExpression) ColumnSize ¶
func (l *LiteralKeyExpression) ColumnSize() int
ColumnSize returns 1 — a literal expression produces a single tuple element.
func (*LiteralKeyExpression) Evaluate ¶
func (l *LiteralKeyExpression) Evaluate(_ *FDBStoredRecord[proto.Message], _ proto.Message) ([][]any, error)
Evaluate returns the constant value regardless of the record. Matches Java's LiteralKeyExpression.evaluateMessage() which ignores the record parameter.
func (*LiteralKeyExpression) FieldNames ¶
func (l *LiteralKeyExpression) FieldNames() []string
FieldNames returns an empty slice — literal expressions don't access any fields.
func (*LiteralKeyExpression) GetValue ¶
func (l *LiteralKeyExpression) GetValue() any
GetValue returns the constant value held by this expression.
func (*LiteralKeyExpression) ToKeyExpression ¶
func (l *LiteralKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes LiteralKeyExpression to proto. Matches Java's LiteralKeyExpression.toKeyExpression().
type MBR ¶
MBR is a minimum bounding rectangle for N dimensions. Stored as [low0, low1, ..., lowN-1, high0, high1, ..., highN-1].
func MBRFromPoint ¶
MBRFromPoint creates a degenerate MBR containing only a single point.
func MBRFromTuple ¶
MBRFromTuple deserializes an MBR from a flat tuple.
func (MBR) ContainsPoint ¶
ContainsPoint returns true if the MBR contains the given point.
func (MBR) NumDimensions ¶
NumDimensions returns the number of dimensions.
type MemoryLimitExceededError ¶
type MemoryLimitExceededError struct {
// Used is the running memory total (in bytes) at the point the budget
// was breached — i.e. the would-be total INCLUDING the charge that
// tripped it.
Used int64
// Limit is the configured statement-wide memory byte budget.
Limit int64
}
MemoryLimitExceededError is returned when a statement's accounted in-memory buffering exceeds the statement-wide memory byte budget (RFC-130). It is a per-statement resource-limit error in the same family as the scan/byte/time limits — the relational layer maps it to SQLSTATE 54F01 (ErrCodeExecutionLimitReached), matching Java's reuse of that SQLSTATE for resource limits (there is no memory-specific SQLSTATE in Java either).
func (*MemoryLimitExceededError) Error ¶
func (e *MemoryLimitExceededError) Error() string
type MetaDataError ¶
type MetaDataError struct {
Message string
}
MetaDataError is returned for metadata validation failures. Matches Java's com.apple.foundationdb.record.metadata.MetaDataException.
func (*MetaDataError) Error ¶
func (e *MetaDataError) Error() string
type MetaDataEvolutionError ¶
type MetaDataEvolutionError struct {
Message string
}
MetaDataEvolutionError describes a schema evolution violation.
func (*MetaDataEvolutionError) Error ¶
func (e *MetaDataEvolutionError) Error() string
type MetaDataEvolutionValidator ¶
type MetaDataEvolutionValidator struct {
// contains filtered or unexported fields
}
MetaDataEvolutionValidator validates that schema changes between an old and new RecordMetaData are safe. Prevents accidental data corruption from incompatible schema evolution.
Matches Java's com.apple.foundationdb.record.metadata.MetaDataEvolutionValidator.
func DefaultMetaDataEvolutionValidator ¶
func DefaultMetaDataEvolutionValidator() *MetaDataEvolutionValidator
DefaultMetaDataEvolutionValidator returns the strictest validator (all options false). Matches Java's MetaDataEvolutionValidator.getDefaultInstance().
func (*MetaDataEvolutionValidator) Validate ¶
func (v *MetaDataEvolutionValidator) Validate(oldMetaData, newMetaData *RecordMetaData) error
Validate checks that evolving from oldMetaData to newMetaData is safe. Returns nil if the evolution is valid, or an error describing the violation. Matches Java's MetaDataEvolutionValidator.validate().
type MetaDataEvolutionValidatorBuilder ¶
type MetaDataEvolutionValidatorBuilder struct {
// contains filtered or unexported fields
}
MetaDataEvolutionValidatorBuilder builds a MetaDataEvolutionValidator with custom options.
func NewMetaDataEvolutionValidator ¶
func NewMetaDataEvolutionValidator() *MetaDataEvolutionValidatorBuilder
NewMetaDataEvolutionValidator returns a builder for configuring the validator.
func (*MetaDataEvolutionValidatorBuilder) Build ¶
func (b *MetaDataEvolutionValidatorBuilder) Build() *MetaDataEvolutionValidator
func (*MetaDataEvolutionValidatorBuilder) SetAllowDeprecatedFieldRenames ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowDeprecatedFieldRenames(v bool) *MetaDataEvolutionValidatorBuilder
SetAllowDeprecatedFieldRenames permits renaming a field when the old or new field is deprecated (a narrower allowance than SetAllowFieldRenames). Matches Java's setAllowDeprecatedFieldRenames.
func (*MetaDataEvolutionValidatorBuilder) SetAllowFieldRenames ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowFieldRenames(v bool) *MetaDataEvolutionValidatorBuilder
SetAllowFieldRenames permits any field to be renamed (same field number, new name) across a metadata evolution. Matches Java's setAllowFieldRenames.
func (*MetaDataEvolutionValidatorBuilder) SetAllowIndexRebuilds ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowIndexRebuilds(v bool) *MetaDataEvolutionValidatorBuilder
func (*MetaDataEvolutionValidatorBuilder) SetAllowMissingFormerIndexNames ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowMissingFormerIndexNames(v bool) *MetaDataEvolutionValidatorBuilder
func (*MetaDataEvolutionValidatorBuilder) SetAllowNoSinceVersion ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowNoSinceVersion(v bool) *MetaDataEvolutionValidatorBuilder
func (*MetaDataEvolutionValidatorBuilder) SetAllowNoVersionChange ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowNoVersionChange(v bool) *MetaDataEvolutionValidatorBuilder
func (*MetaDataEvolutionValidatorBuilder) SetAllowOlderFormerIndexAddedVersion ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowOlderFormerIndexAddedVersion(v bool) *MetaDataEvolutionValidatorBuilder
func (*MetaDataEvolutionValidatorBuilder) SetAllowUndeprecatingFields ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowUndeprecatingFields(v bool) *MetaDataEvolutionValidatorBuilder
SetAllowUndeprecatingFields permits a field that was deprecated to become non-deprecated. Matches Java's setAllowUndeprecatingFields.
func (*MetaDataEvolutionValidatorBuilder) SetAllowUnsplitToSplit ¶
func (b *MetaDataEvolutionValidatorBuilder) SetAllowUnsplitToSplit(v bool) *MetaDataEvolutionValidatorBuilder
func (*MetaDataEvolutionValidatorBuilder) SetDisallowTypeRenames ¶
func (b *MetaDataEvolutionValidatorBuilder) SetDisallowTypeRenames(v bool) *MetaDataEvolutionValidatorBuilder
type MetaDataVersionMustIncreaseError ¶
MetaDataVersionMustIncreaseError is returned by SaveRecordMetaData when the new metadata's version is not strictly greater than the stored one. This check is unconditional — it does not consult the evolution validator's allowNoVersionChange knob, exactly like Java, where saveAndSetCurrent throws before the validator ever runs. Matches Java's MetaDataException("meta-data version must increase") with log keys OLD / NEW.
func (*MetaDataVersionMustIncreaseError) Error ¶
func (e *MetaDataVersionMustIncreaseError) Error() string
type MetaDataVersionStampStoreStateCache ¶
type MetaDataVersionStampStoreStateCache struct {
// contains filtered or unexported fields
}
MetaDataVersionStampStoreStateCache caches store state and validates entries using FDB's metadata version stamp (a system key that changes on every mutation). Matches Java's MetaDataVersionStampStoreStateCache.
func NewMetaDataVersionStampStoreStateCache ¶
func NewMetaDataVersionStampStoreStateCache(opts ...MetaDataVersionStampStoreStateCacheOption) *MetaDataVersionStampStoreStateCache
NewMetaDataVersionStampStoreStateCache creates a new cache with optional configuration.
func (*MetaDataVersionStampStoreStateCache) Clear ¶
func (c *MetaDataVersionStampStoreStateCache) Clear()
Clear removes all cached entries.
func (*MetaDataVersionStampStoreStateCache) Get ¶
func (c *MetaDataVersionStampStoreStateCache) Get(store *FDBRecordStore, existenceCheck StoreExistenceCheck) (*FDBRecordStoreStateCacheEntry, error)
Get retrieves store state, using the cache when the metadata version stamp matches. Matches Java's MetaDataVersionStampStoreStateCache.get().
type MetaDataVersionStampStoreStateCacheOption ¶
type MetaDataVersionStampStoreStateCacheOption func(*MetaDataVersionStampStoreStateCache)
MetaDataVersionStampStoreStateCacheOption configures the cache.
func WithExpireAfterAccess ¶
func WithExpireAfterAccess(d time.Duration) MetaDataVersionStampStoreStateCacheOption
WithExpireAfterAccess sets the TTL for cache entries since last access. Default: 1 minute (matches Java's default).
func WithMaxSize ¶
func WithMaxSize(n int) MetaDataVersionStampStoreStateCacheOption
WithMaxSize sets the maximum number of entries in the cache. Default: 500 (matches Java's default).
type NestingKeyExpression ¶
type NestingKeyExpression struct {
// contains filtered or unexported fields
}
NestingKeyExpression navigates into a nested protobuf message and evaluates a child expression against it. Matches Java's NestingKeyExpression.
Example: Nest("flower", Field("type")) indexes the "type" field inside a nested "flower" message.
For repeated message fields, use NestFanOut to fan out over each sub-message.
func (*NestingKeyExpression) ColumnSize ¶
func (n *NestingKeyExpression) ColumnSize() int
ColumnSize returns the child's column size — the parent message field doesn't contribute a tuple element.
func (*NestingKeyExpression) Evaluate ¶
func (n *NestingKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate navigates into the parent message field and evaluates the child expression on the sub-message(s).
func (*NestingKeyExpression) FieldNames ¶
func (n *NestingKeyExpression) FieldNames() []string
FieldNames returns the parent field name plus child field names.
func (*NestingKeyExpression) ToKeyExpression ¶
func (n *NestingKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes a NestingKeyExpression to proto. Matches Java's NestingKeyExpression.toKeyExpression().
type NoNextReason ¶
type NoNextReason int
NoNextReason indicates why a cursor stopped producing records
const ( // SourceExhausted means the cursor reached the end of its data SourceExhausted NoNextReason = iota // ReturnLimitReached means the cursor hit its row limit ReturnLimitReached // ByteLimitReached means the cursor hit its byte scan limit ByteLimitReached // TimeLimitReached means the cursor hit its time limit TimeLimitReached // ScanLimitReached means the cursor hit its key-value scan limit ScanLimitReached )
func (NoNextReason) IsLimitReached ¶
func (r NoNextReason) IsLimitReached() bool
IsLimitReached returns true if the cursor stopped due to any kind of limit
func (NoNextReason) IsOutOfBand ¶
func (r NoNextReason) IsOutOfBand() bool
IsOutOfBand returns true if this reason represents an out-of-band completion (not solely dependent on the records returned)
func (NoNextReason) IsSourceExhausted ¶
func (r NoNextReason) IsSourceExhausted() bool
IsSourceExhausted returns true if there is no more data available
type OnlineIndexer ¶
type OnlineIndexer struct {
// contains filtered or unexported fields
}
OnlineIndexer builds indexes on existing data across multiple transactions. Each transaction processes a chunk of records, tracks progress via IndexingRangeSet, and the build resumes from where it left off if interrupted.
Supports four modes:
- BY_RECORDS (default, single target): scans all records in primary key order
- BY_INDEX (single target): scans an existing readable VALUE index to find records
- MULTI_TARGET_BY_RECORDS: scans records once, builds multiple indexes simultaneously
- MUTUAL_BY_RECORDS: concurrent multi-process building with fragment-based work division
Matches Java's OnlineIndexer with IndexingByRecords, IndexingByIndex, IndexingMultiTargetByRecords, and IndexingMutuallyByRecords.
func (*OnlineIndexer) BlockIndex ¶
BlockIndex sets the block flag on the indexing stamp for all target indexes. A blocked stamp prevents other indexers from continuing the build. blockID is an optional identifier for the block reason. ttl is the time-to-live for the block; zero means permanent. Matches Java's IndexingBase.performIndexingStampOperation(BLOCK, ...).
func (*OnlineIndexer) BuildIndex ¶
func (oi *OnlineIndexer) BuildIndex(ctx context.Context) (int64, error)
BuildIndex runs the full index build: marks WRITE_ONLY, builds all records, then marks READABLE. Returns the number of records indexed. Matches Java's OnlineIndexer.buildIndex().
func (*OnlineIndexer) MarkReadableIfBuilt ¶
func (oi *OnlineIndexer) MarkReadableIfBuilt(ctx context.Context) (bool, error)
MarkReadableIfBuilt checks each target index and marks it READABLE if fully built. Returns true if all target indexes are now READABLE. This is an idempotent operation — safe to call repeatedly. Matches Java's IndexingBase.markReadableIfBuilt().
func (*OnlineIndexer) QueryIndexingStamps ¶
func (oi *OnlineIndexer) QueryIndexingStamps(ctx context.Context) (map[string]*gen.IndexBuildIndexingStamp, error)
QueryIndexingStamps returns the indexing stamps for all target indexes. Returns a map of index name → stamp. Nil stamps are returned as a NONE method stamp. Matches Java's IndexingBase.performIndexingStampOperation(QUERY, ...).
func (*OnlineIndexer) UnblockIndex ¶
func (oi *OnlineIndexer) UnblockIndex(ctx context.Context, blockID string) error
UnblockIndex clears the block flag on the indexing stamp for all target indexes. If blockID is non-empty, only unblocks stamps with a matching blockID. Matches Java's IndexingBase.performIndexingStampOperation(UNBLOCK, ...).
type OnlineIndexerBuilder ¶
type OnlineIndexerBuilder struct {
// contains filtered or unexported fields
}
OnlineIndexerBuilder constructs an OnlineIndexer.
func NewOnlineIndexerBuilder ¶
func NewOnlineIndexerBuilder() *OnlineIndexerBuilder
NewOnlineIndexerBuilder creates a new builder.
func (*OnlineIndexerBuilder) AddTargetIndex ¶
func (b *OnlineIndexerBuilder) AddTargetIndex(index *Index) *OnlineIndexerBuilder
AddTargetIndex adds a target index for multi-target building. Mutually exclusive with SetIndex. Matches Java's OnlineIndexer.Builder.addTargetIndex().
func (*OnlineIndexerBuilder) Build ¶
func (b *OnlineIndexerBuilder) Build() (*OnlineIndexer, error)
Build creates the OnlineIndexer. Matches Java's OnlineIndexer.Builder.build(): validates, deduplicates, and sorts target indexes by name (the alphabetically-first index becomes the "primary" that drives range tracking).
func (*OnlineIndexerBuilder) SetAllowUniquePendingState ¶
func (b *OnlineIndexerBuilder) SetAllowUniquePendingState(allow bool) *OnlineIndexerBuilder
SetAllowUniquePendingState opts in to leaving a unique index in READABLE_UNIQUE_PENDING when the build finds duplicates, instead of failing the build with a RecordIndexUniquenessViolationError.
Java OnlineIndexer.IndexingPolicy.Builder.allowUniquePendingState(boolean) (OnlineIndexer.java:1354). Defaults FALSE here as it does there, and even when set it is honoured only on a store at format version >= READABLE_UNIQUE_PENDING — see OnlineIndexer.shouldAllowUniquePendingState.
Java's javadoc carries the warning this option deserves: "This state might not be compatible with older code. Please verify that all instances are up-to-date before allowing it."
func (*OnlineIndexerBuilder) SetDatabase ¶
func (b *OnlineIndexerBuilder) SetDatabase(db *FDBDatabase) *OnlineIndexerBuilder
SetDatabase sets the FDB database.
func (*OnlineIndexerBuilder) SetEnforcedPostTransactionDelay ¶
func (b *OnlineIndexerBuilder) SetEnforcedPostTransactionDelay(ms int) *OnlineIndexerBuilder
SetEnforcedPostTransactionDelay sets a fixed delay in milliseconds applied after each build transaction. When positive, it is used INSTEAD of the records-per-second throttle. Default 0 disables it (records-per-second behaviour). Matches Java's OnlineIndexer.Builder.setEnforcedPostTransactionDelay().
func (*OnlineIndexerBuilder) SetFormatVersion ¶
func (b *OnlineIndexerBuilder) SetFormatVersion(version int32) *OnlineIndexerBuilder
SetFormatVersion pins the format version the indexer opens its stores at, mirroring StoreBuilder.SetFormatVersion. Java gets this for free by reusing the caller's record-store builder (IndexingCommon.getRecordStoreBuilder).
func (*OnlineIndexerBuilder) SetIndex ¶
func (b *OnlineIndexerBuilder) SetIndex(index *Index) *OnlineIndexerBuilder
SetIndex sets a single target index to build. Mutually exclusive with AddTargetIndex/SetTargetIndexes.
func (*OnlineIndexerBuilder) SetLeaseLengthMs ¶
func (b *OnlineIndexerBuilder) SetLeaseLengthMs(ms int64) *OnlineIndexerBuilder
SetLeaseLengthMs sets the heartbeat lease duration in milliseconds. If a heartbeat is not updated within this duration, the process is presumed dead. Default is 30000 (30 seconds). Only relevant for non-mutual mode; in mutual mode heartbeats are written but not checked. Matches Java's OnlineIndexer.IndexingPolicy.setLeaseLengthMillis().
func (*OnlineIndexerBuilder) SetLimit ¶
func (b *OnlineIndexerBuilder) SetLimit(limit int) *OnlineIndexerBuilder
SetLimit sets the maximum number of records to process per transaction.
func (*OnlineIndexerBuilder) SetLogger ¶
func (b *OnlineIndexerBuilder) SetLogger(logger *slog.Logger) *OnlineIndexerBuilder
SetLogger sets the slog.Logger that receives the indexer's operational progress events. A nil logger (the default) falls back to slog.Default() at log time, mirroring the client's WithLogger convention (RFC-097).
func (*OnlineIndexerBuilder) SetMarkReadable ¶
func (b *OnlineIndexerBuilder) SetMarkReadable(v bool) *OnlineIndexerBuilder
SetMarkReadable controls whether BuildIndex marks the index readable when the build completes (default true). With false, the build populates the index but leaves it WRITE_ONLY with its build stamp and progress counter intact — matching Java's OnlineIndexer.buildIndex(boolean markReadable).
func (*OnlineIndexerBuilder) SetMaxRetries ¶
func (b *OnlineIndexerBuilder) SetMaxRetries(maxRetries int) *OnlineIndexerBuilder
SetMaxRetries sets the maximum number of retries per range on transient FDB errors. When a range build fails with a transient error, the indexer retries with a halved limit. Default is 0 (no retries — errors propagate immediately). Matches Java's OnlineIndexer.Builder.setMaxRetries() (default 100 in Java).
func (*OnlineIndexerBuilder) SetMetaData ¶
func (b *OnlineIndexerBuilder) SetMetaData(md *RecordMetaData) *OnlineIndexerBuilder
SetMetaData sets the record metadata.
func (*OnlineIndexerBuilder) SetMutualIndexing ¶
func (b *OnlineIndexerBuilder) SetMutualIndexing() *OnlineIndexerBuilder
SetMutualIndexing enables concurrent/mutual index building mode. Multiple indexer processes can run simultaneously, each building different fragments of the key space. Fragments are determined by FDB shard boundaries. Matches Java's OnlineIndexer.Builder.setMutualIndexing().
func (*OnlineIndexerBuilder) SetMutualIndexingBoundaries ¶
func (b *OnlineIndexerBuilder) SetMutualIndexingBoundaries(boundaries [][]byte) *OnlineIndexerBuilder
SetMutualIndexingBoundaries enables mutual mode with pre-set fragment boundaries. Each boundary is a packed tuple representing a primary key at which to split the key space. If nil/empty, the entire key space is treated as a single fragment. Matches Java's OnlineIndexer.Builder.setMutualIndexingBoundaries().
func (*OnlineIndexerBuilder) SetPolicy ¶
func (b *OnlineIndexerBuilder) SetPolicy(policy *IndexingPolicy) *OnlineIndexerBuilder
SetPolicy sets the indexing policy for stamp conflict resolution. Matches Java's OnlineIndexer.Builder.setIndexingPolicy().
func (*OnlineIndexerBuilder) SetProgressLogIntervalMillis ¶
func (b *OnlineIndexerBuilder) SetProgressLogIntervalMillis(ms int64) *OnlineIndexerBuilder
SetProgressLogIntervalMillis sets the throttle for the per-range "Indexer: Built Range" progress log. Matches Java OnlineIndexer.Builder.setProgressLogIntervalMillis():
- a negative value (the default, -1) disables progress logging;
- 0 logs after every range;
- a positive value logs at most once per that many milliseconds.
Events go to the logger set via SetLogger (or slog.Default()) at INFO.
func (*OnlineIndexerBuilder) SetRecordTypes ¶
func (b *OnlineIndexerBuilder) SetRecordTypes(types ...string) *OnlineIndexerBuilder
SetRecordTypes sets which record types to index. If empty, indexes all types that have this index defined. Not allowed with multi-target building.
func (*OnlineIndexerBuilder) SetRecordsPerSecond ¶
func (b *OnlineIndexerBuilder) SetRecordsPerSecond(rps int) *OnlineIndexerBuilder
SetRecordsPerSecond sets the inter-transaction rate limit. The indexer will sleep between transactions to maintain approximately this rate. Default is 10,000 records/second (matching Java). Set to 0 for unlimited. Matches Java's OnlineIndexer.Builder.setRecordsPerSecond().
func (*OnlineIndexerBuilder) SetSourceIndex ¶
func (b *OnlineIndexerBuilder) SetSourceIndex(index *Index) *OnlineIndexerBuilder
SetSourceIndex sets the source index for the BY_INDEX strategy. The source index must be a READABLE VALUE index whose root expression does not create duplicates. Both source and target must apply to exactly one record type, and the target's type must be a superset of the source's. Not allowed with multi-target building. Matches Java's OnlineIndexer.Builder.setSourceIndex().
func (*OnlineIndexerBuilder) SetSubspace ¶
func (b *OnlineIndexerBuilder) SetSubspace(ss subspace.Subspace) *OnlineIndexerBuilder
SetSubspace sets the store subspace.
func (*OnlineIndexerBuilder) SetTargetIndexes ¶
func (b *OnlineIndexerBuilder) SetTargetIndexes(indexes []*Index) *OnlineIndexerBuilder
SetTargetIndexes sets multiple target indexes for multi-target building. Mutually exclusive with SetIndex. Matches Java's OnlineIndexer.Builder.setTargetIndexes().
func (*OnlineIndexerBuilder) SetTimeLimit ¶
func (b *OnlineIndexerBuilder) SetTimeLimit(d time.Duration) *OnlineIndexerBuilder
SetTimeLimit sets the overall time limit for the entire build. If the build exceeds this duration, BuildIndex returns a TimeLimitExceededError after the current range completes. Zero means unlimited (default). Matches Java's OnlineIndexer.Builder.setTimeLimitMilliseconds().
type OrderDirection ¶
type OrderDirection struct {
// contains filtered or unexported fields
}
OrderDirection specifies how tuple values are encoded for ordered storage. Matches Java's TupleOrdering.Direction enum.
type OrdinaryIndexScanFunc ¶
type OrdinaryIndexScanFunc func(scanRange TupleRange, props ScanProperties) RecordCursor[*IndexEntry]
OrdinaryIndexScanFunc scans the ORDINARY (value) subspace of an index. The repair is expressed against this function rather than against a store because its two callers reach that subspace differently: the query executor goes through FDBRecordStore.ScanIndexByType, while the index maintainer already holds a standard-maintainer handle on the same subspace and has no store.
func OrdinaryIndexScanner ¶
func OrdinaryIndexScanner(store *FDBRecordStore, index *Index) OrdinaryIndexScanFunc
OrdinaryIndexScanner returns the scan function the repair needs for an index reached through a record store — the query executor's route.
type PartlyBuiltError ¶
type PartlyBuiltError struct {
IndexName string
SavedStamp string // string representation of the saved stamp
ExpectedStamp string // string representation of the expected stamp
Message string
}
PartlyBuiltError is returned when an OnlineIndexer encounters an index that was partly built by another method or is blocked from continuing. Matches Java's com.apple.foundationdb.record.provider.foundationdb.IndexingBase.PartlyBuiltException.
func (*PartlyBuiltError) Error ¶
func (e *PartlyBuiltError) Error() string
type PassThroughRecordStoreStateCache ¶
type PassThroughRecordStoreStateCache struct{}
PassThroughRecordStoreStateCache is a no-op cache that always loads from FDB. This is the default behavior. Matches Java's PassThroughRecordStoreStateCache.
func (*PassThroughRecordStoreStateCache) Clear ¶
func (c *PassThroughRecordStoreStateCache) Clear()
Clear is a no-op.
func (*PassThroughRecordStoreStateCache) Get ¶
func (c *PassThroughRecordStoreStateCache) Get(store *FDBRecordStore, existenceCheck StoreExistenceCheck) (*FDBRecordStoreStateCacheEntry, error)
Get always loads fresh state from FDB. Skips the metadata version stamp read since PassThrough has no cache to validate against.
type Point ¶
Point represents an N-dimensional point with int64 coordinates. Null coordinates are represented as nil in the tuple.
func (Point) Coordinate ¶
Coordinate returns the coordinate at the given dimension index, or MinInt64 if nil.
func (Point) NumDimensions ¶
NumDimensions returns the number of dimensions.
type PostCommitFunc ¶
type PostCommitFunc func()
PostCommitFunc is a callback that runs after a successful commit. Matches Java's PostCommit interface.
type RTree ¶
type RTree struct {
// contains filtered or unexported fields
}
RTree is a Hilbert R-tree backed by FDB. Matches Java's com.apple.foundationdb.async.rtree.RTree.
func NewRTree ¶
func NewRTree(storage *rtreeStorage, config RTreeConfig) (*RTree, error)
NewRTree creates a new R-tree. Returns an error if config is invalid.
func (*RTree) Clear ¶
func (rt *RTree) Clear(tx fdb.WritableTransaction) error
Clear removes all data from the R-tree.
func (*RTree) InsertOrUpdate ¶
func (rt *RTree) InsertOrUpdate(tx fdb.WritableTransaction, point Point, keySuffix tuple.Tuple, value tuple.Tuple) error
InsertOrUpdate inserts a new item or updates an existing one. Matches Java's RTree.insertOrUpdate().
func (*RTree) Scan ¶
func (rt *RTree) Scan(tx fdb.ReadTransaction, lastHV *big.Int, lastKey tuple.Tuple, mbrPredicate func(MBR) bool) ([]ItemSlot, error)
Scan returns all items matching the MBR predicate, starting after (lastHV, lastKey). Items are returned in Hilbert value order. Convenience wrapper around ScanIterator.
func (*RTree) ScanIterator ¶
func (rt *RTree) ScanIterator(tx fdb.ReadTransaction, lastHV *big.Int, lastKey tuple.Tuple, mbrPredicate func(MBR) bool) *RTreeIterator
ScanIterator returns a lazy iterator over items matching the MBR predicate, starting after (lastHV, lastKey). Items are yielded one at a time in Hilbert value order. Only fetches leaf nodes from FDB on demand.
type RTreeConfig ¶
type RTreeConfig struct {
MinM int // Min slots per non-root node (default 16)
MaxM int // Max slots per node (default 32)
SplitS int // Siblings involved in split/fuse (default 2)
StoreHilbertValues bool // Store HV in leaf slots (default true)
NumDimensions int // Number of spatial dimensions
}
RTreeConfig configures the R-tree behavior. Matches Java's RTree.Config.
func DefaultRTreeConfig ¶
func DefaultRTreeConfig(numDimensions int) RTreeConfig
DefaultRTreeConfig returns the default R-tree configuration.
type RTreeIterator ¶
type RTreeIterator struct {
// contains filtered or unexported fields
}
RTreeIterator lazily walks the R-tree depth-first in Hilbert order, fetching one leaf node at a time from FDB.
type RangeSet ¶
type RangeSet struct {
// contains filtered or unexported fields
}
RangeSet tracks ranges of completed work in an FDB subspace. Wire-compatible with Java's com.apple.foundationdb.async.RangeSet.
func NewRangeSet ¶
NewRangeSet creates a RangeSet that stores data in the given subspace.
func (*RangeSet) Clear ¶
func (rs *RangeSet) Clear(tr fdb.WritableTransaction)
Clear removes all ranges from the set.
func (*RangeSet) Contains ¶
Contains checks if key is in any range in the set. Adds a read conflict on the key for proper isolation.
func (*RangeSet) InsertRange ¶
func (rs *RangeSet) InsertRange(tr fdb.WritableTransaction, begin, end []byte, requireEmpty bool) (bool, error)
InsertRange adds range [begin, end) to the set. If begin is nil, uses FIRST_KEY. If end is nil, uses FINAL_KEY. If requireEmpty is true, only inserts if the range is currently empty (atomic test-and-set). Returns true if the database was modified.
func (*RangeSet) IsEmpty ¶
func (rs *RangeSet) IsEmpty(tr fdb.WritableTransaction) (bool, error)
IsEmpty returns true if no ranges have been inserted into this set.
func (*RangeSet) MissingRanges ¶
func (rs *RangeSet) MissingRanges(tr fdb.WritableTransaction, begin, end []byte, limit int) ([]RangeSetRange, error)
MissingRanges returns the gaps (ranges not in the set) within [begin, end). If begin is nil, uses FIRST_KEY. If end is nil, uses FINAL_KEY. If limit <= 0, returns all gaps.
type RangeSetEmptyKeyError ¶
type RangeSetEmptyKeyError struct{}
RangeSetEmptyKeyError is returned when a RangeSet operation receives an empty key.
func (*RangeSetEmptyKeyError) Error ¶
func (e *RangeSetEmptyKeyError) Error() string
type RangeSetInvertedRangeError ¶
RangeSetInvertedRangeError is returned when begin > end in a range operation.
func (*RangeSetInvertedRangeError) Error ¶
func (e *RangeSetInvertedRangeError) Error() string
type RangeSetKeyTooLargeError ¶
type RangeSetKeyTooLargeError struct {
Key []byte
}
RangeSetKeyTooLargeError is returned when a key is >= \xff.
func (*RangeSetKeyTooLargeError) Error ¶
func (e *RangeSetKeyTooLargeError) Error() string
type RangeSetRange ¶
RangeSetRange represents a gap (missing range) as [Begin, End).
type RankQuerier ¶
type RankQuerier interface {
RankForScore(score tuple.Tuple, nullsAreLow bool) (*int64, error)
ScoreForRank(rank tuple.Tuple) (tuple.Tuple, error)
}
RankQuerier is the public interface for rank-based queries on a RANK index maintainer.
type RecordAlreadyExistsError ¶
type RecordAlreadyExistsError struct {
Message string
PrimaryKey any // tuple.Tuple, but using any to avoid import cycle
}
RecordAlreadyExistsError is returned when attempting to insert a record that already exists. Includes structured context matching Java's RecordAlreadyExistsException.
Java equivalent: com.apple.foundationdb.record.provider.foundationdb.RecordAlreadyExistsException Location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/RecordAlreadyExistsException.java Java includes: LogMessageKeys.PRIMARY_KEY
func (*RecordAlreadyExistsError) Error ¶
func (e *RecordAlreadyExistsError) Error() string
type RecordContextConfig ¶
type RecordContextConfig struct {
// TransactionTimeout is the timeout for the FDB transaction.
// Zero means use FDB's default.
TransactionTimeout time.Duration
// Priority sets the transaction priority.
Priority TransactionPriority
// TransactionID is an optional identifier for tracing/debugging.
TransactionID string
// TransactionSizeWarnBytes triggers a warning when the approximate
// transaction size exceeds this threshold. Zero disables the check.
// FDB's hard limit is 10MB; a typical warning threshold is 8MB.
TransactionSizeWarnBytes int64
// TransactionSizeErrorBytes causes operations to return
// TransactionSizeExceededError when the approximate transaction
// size exceeds this threshold. Zero disables the check.
// Setting this below FDB's 10MB limit lets callers commit early.
TransactionSizeErrorBytes int64
// Tags are transaction tags used for tag-based throttling, applied to every
// transaction this config creates. Matches Java's FDBRecordContextConfig
// tags (FDBRecordContextConfig.java:60), which are applied one at a time via
// transaction.options().setTag (FDBRecordContext.java:205-207) — the plain
// TAG option, never AUTO_THROTTLE_TAG.
//
// Java models this as a Set<String>, so duplicates collapse and iteration
// order is arbitrary. ValidateTags dedups; SetTags sorts, because the commit
// request's TagSet is a length-prefixed concatenation in insertion order and
// an arbitrary order would make the commit bytes vary run to run for the
// same config. Order is not a wire contract on either side.
Tags []string
// Timer is the StoreTimer every context this config creates records into.
// Matches Java's FDBRecordContextConfig.timer (FDBRecordContextConfig.java:42,
// Builder.setTimer :357-368), which likewise defaults to null/nil.
//
// Nil does NOT mean uninstrumented: it means "inherit the database's timer",
// which is the same relationship Java has between FDBDatabaseRunner.setTimer and
// the context config it delegates to (FDBDatabaseRunner.java:105-119). Set it only
// to give one runner's transactions a timer separate from the rest of the process
// — an index build measured on its own, say.
Timer *StoreTimer
}
RecordContextConfig holds configuration for creating FDBRecordContext instances. Matches Java's FDBRecordContextConfig.
func (*RecordContextConfig) SetTags ¶
func (c *RecordContextConfig) SetTags(tags []string) error
SetTags validates and stores the tag set, returning an error rather than panicking where Java throws. Tags are sorted so the resulting commit bytes are deterministic for a given config.
type RecordCoreStorageError ¶
type RecordCoreStorageError struct {
Message string // Java's RecordCoreStorageException message
IndexName string // LogMessageKeys.INDEX_NAME
PrimaryKey tuple.Tuple // LogMessageKeys.PRIMARY_KEY (nil if the entry yielded no PK)
IndexKey tuple.Tuple // LogMessageKeys.INDEX_KEY
}
RecordCoreStorageError signals storage-level corruption detected while resolving an index entry to its base record. Matches Java's com.apple.foundationdb.record.RecordCoreStorageException.
When a record is fetched from an index entry with IndexOrphanBehavior.ERROR (FDBRecordStoreBase.loadIndexEntryRecord) and the referenced record is missing, Java throws this exception rather than dropping the row, attaching LogMessageKeys.INDEX_NAME / PRIMARY_KEY / INDEX_KEY. An index entry with no base record means the index and the records disagree — index corruption, an out-of-band delete, or a maintainer bug — and both query execution (RecordQueryIndexPlan → FetchIndexRecords.PRIMARY_KEY) and the index-from-index rebuild (scanIndexRecords defaults to ERROR) use this loud path. Silently skipping would convert detectable corruption into quietly-fewer rows.
func (*RecordCoreStorageError) Error ¶
func (e *RecordCoreStorageError) Error() string
type RecordCountKeySizeMismatchError ¶
RecordCountKeySizeMismatchError is Java's recordCoreException("key and value are not the same size") thrown by getSnapshotRecordCount (FDBRecordStore.java:2295-2297) when the evaluated value has a different number of columns than the key expression it is supposed to be a value of.
It is a typed error rather than a plain message because the two sizes are the whole diagnosis: the caller either passed a value for a different count key or truncated one, and the alternative to failing is answering from a slot nothing ever writes — a confident, wrong 0.
func (*RecordCountKeySizeMismatchError) Error ¶
func (e *RecordCountKeySizeMismatchError) Error() string
type RecordCursor ¶
type RecordCursor[T any] interface { // OnNext asynchronously returns the next result from this cursor OnNext(ctx context.Context) (RecordCursorResult[T], error) // Close releases any resources held by this cursor Close() error // IsClosed returns true if the cursor has been closed IsClosed() bool }
RecordCursor is a generic async iterator over records
func Chained ¶
func Chained[T any]( generator func(prev *T) (*T, error), encode func(T) []byte, decode func([]byte) (T, bool), continuation []byte, ) RecordCursor[T]
Chained creates a cursor that produces values from a generator function. generator receives the previous value (nil for the first call) and returns the next value or nil to signal exhaustion. encode/decode serialize/deserialize values for continuations. Matches Java's ChainedCursor.
func ConcatCursors ¶
func ConcatCursors[T any](first, second CursorFactory[T], continuation []byte) RecordCursor[T]
ConcatCursors concatenates two cursor factories: results from first, then second. Continuation tokens are wire-compatible with Java's ConcatCursor.
func Dedup ¶
func Dedup[T any]( innerFactory CursorFactory[T], equal func(a, b T) bool, pack func(T) []byte, unpack func([]byte) (T, bool), continuation []byte, ) RecordCursor[T]
Dedup creates a cursor that removes adjacent duplicate elements. equal compares two elements; pack/unpack serialize the last value for continuations. If pack is nil, continuation will not include lastValue. Matches Java's DedupCursor.
func Empty ¶
func Empty[T any]() RecordCursor[T]
Empty returns a cursor that produces no results (source exhausted immediately).
func Fallback ¶
func Fallback[T any]( inner RecordCursor[T], fallbackFactory func(lastResult *RecordCursorResult[T]) RecordCursor[T], ) RecordCursor[T]
Fallback creates a cursor that falls back to an alternative on error. fallbackFactory receives the last successful result (nil if the inner cursor failed on its first call) and should return a cursor that resumes from there. Matches Java's FallbackCursor — one-shot fallback (fails permanently if the fallback cursor also errors).
func FlatMapPipelined ¶
func FlatMapPipelined[T, V any]( outerFactory CursorFactory[T], innerFactory func(T, []byte) RecordCursor[V], continuation []byte, pipelineSize int, ) RecordCursor[V]
FlatMapPipelined creates a cursor that flat-maps an outer cursor through an inner cursor factory. Matches Java's RecordCursor.flatMapPipelined().
Parameters:
- outerFactory: creates the outer cursor from a continuation
- innerFactory: given an outer value and optional inner continuation, creates an inner cursor
- continuation: serialized FlatMapContinuation for resumption (nil to start fresh)
- pipelineSize: accepted for API compat (Go processes sequentially)
func FlatMapPipelinedWithCheck ¶
func FlatMapPipelinedWithCheck[T, V any]( outerFactory CursorFactory[T], innerFactory func(T, []byte) RecordCursor[V], checkValueFunc func(T) []byte, continuation []byte, pipelineSize int, ) RecordCursor[V]
FlatMapPipelinedWithCheck is like FlatMapPipelined but with an optional check value function. The check value validates that the outer record hasn't changed between transactions when resuming from a continuation mid-inner-cursor.
func FromList ¶
func FromList[T any](items []T) RecordCursor[T]
FromList creates a cursor from a slice. Matches Java's RecordCursor.fromList().
func FromListWithContinuation ¶
func FromListWithContinuation[T any](items []T, continuation []byte) RecordCursor[T]
FromListWithContinuation creates a cursor from a slice, starting from a continuation. Matches Java's RecordCursor.fromList(list, continuation). Continuation format: 4-byte big-endian position (nil/empty = start from beginning). Java uses ByteBuffer.wrap(continuation).getInt() which reads first 4 bytes and throws BufferUnderflowException for continuations shorter than 4 bytes. Go returns an error from OnNext for invalid continuation lengths to match Java's fail-fast behavior.
func InstrumentIndexScanCursor ¶
func InstrumentIndexScanCursor(timer *StoreTimer, inner RecordCursor[*IndexEntry]) RecordCursor[*IndexEntry]
InstrumentIndexScanCursor times each entry an index-scan cursor produces into EventScanIndex. It is the exported form of the wrapper the store's own scan methods apply, for the one caller that cannot use them: the query executor builds its index cursor from the maintainer directly (it needs the per-range factory that FDBRecordStore.ScanIndex does not expose), so without this the engine's primary index-scan path produces no scan event at all.
Decorating the maintainer instead would be the tidier-looking fix and is wrong: IndexMaintainer implementations are type-asserted for capability interfaces (RankQuerier among them), and a struct decorator silently fails those assertions.
A nil timer returns the cursor unchanged, so an uninstrumented store pays nothing per entry.
func Intersection ¶
func Intersection[T any]( cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, ) RecordCursor[T]
Intersection creates a merge-intersection cursor that returns only elements present in ALL child cursors (by comparison key). All cursors must be ordered by the same key. Returns the element from the first cursor when all match. Matches Java's IntersectionCursor.create().
func IntersectionMulti ¶
func IntersectionMulti[T any]( cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, ) RecordCursor[[]T]
IntersectionMulti creates a merge-intersection cursor that returns, for each set of elements present in ALL child cursors (by comparison key), the list of those elements (index i is the element from child i). All cursors must be ordered by the same key. Matches Java's IntersectionMultiCursor.create().
func IntersectionMultiResume ¶
func IntersectionMultiResume[T any]( cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, resume []IntersectionChildResume, ) RecordCursor[[]T]
IntersectionMultiResume is IntersectionMulti with per-child resume state (see IntersectionResume). resume may be nil (all children fresh).
func IntersectionResume ¶
func IntersectionResume[T any]( cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, resume []IntersectionChildResume, ) RecordCursor[T]
IntersectionResume is Intersection with per-child resume state from DecodeIntersectionContinuation. Each child's cached continuation is seeded from resume[i] (START → fresh, MID → its bytes, END → end), so a resumed child re-encodes correctly on the next checkpoint (RFC-071). resume may be nil (all children fresh, == Intersection).
func LimitRowsCursor ¶
func LimitRowsCursor[T any](cursor RecordCursor[T], n int) RecordCursor[T]
LimitRowsCursor wraps a cursor and limits to at most n elements. Matches Java's RecordCursor.limitRowsTo() exactly: 0 (and MaxInt) mean UNLIMITED — the cursor is returned unchanged — and a negative limit is an error (Java throws RecordCoreException("Invalid row limit"); Go's no-panic rule surfaces it as an error cursor). The previous n<=0→Empty reading silently inverted Java's 0-is-unlimited convention.
func MapCursor ¶
func MapCursor[T, R any](cursor RecordCursor[T], fn func(T) R) RecordCursor[R]
MapCursor creates a cursor that transforms each value using the given function. Continuations from the inner cursor are passed through transparently.
func MapErrCursor ¶
func MapErrCursor[T, R any](cursor RecordCursor[T], fn func(T) (R, error)) RecordCursor[R]
MapErrCursor creates a cursor that transforms each value using a function that can return an error. If the transform function returns an error, iteration stops with that error. Continuations from the inner cursor are passed through. Matches Java's MapResultCursor with checked exceptions.
func NewAutoContinuingCursor ¶
func NewAutoContinuingCursor[T any]( runner *FDBDatabaseRunner, generator func(*FDBRecordContext, []byte) RecordCursor[T], maxRetries int, ) RecordCursor[T]
NewAutoContinuingCursor creates a cursor that automatically creates new transactions when the inner cursor stops before exhaustion (e.g., time limit, scan limit). Matches Java's AutoContinuingCursor.
Parameters:
- runner: provides transaction creation and context configuration
- generator: creates a cursor within a transaction context from a continuation
- maxRetries: maximum retries on transient FDB errors (0 = no retries)
func OrElse ¶
func OrElse[T any](primary RecordCursor[T], alternative func() RecordCursor[T]) RecordCursor[T]
OrElse returns the primary cursor if it has results, otherwise falls back to the alternative cursor. Matches Java's RecordCursor.orElse().
func OrElseWithContinuation ¶
func OrElseWithContinuation[T any]( primaryFactory CursorFactory[T], alternativeFactory CursorFactory[T], continuation []byte, ) RecordCursor[T]
OrElseWithContinuation creates an OrElse cursor with continuation support. Matches Java's OrElseCursor with OrElseContinuation proto serialization. Both primary and alternative are cursor factories that accept continuation bytes for cross-transaction resume.
func OuterMergeMultiResume ¶
func OuterMergeMultiResume[T any]( cursors []RecordCursor[T], compKeyFunc ComparisonKeyFunc[T], reverse bool, resume []IntersectionChildResume, driving int, absent func(childIndex int) T, ) RecordCursor[[]T]
OuterMergeMultiResume creates the driven outer merge. driving indexes the stream that decides the group set; absent supplies a filler value for a non-driving stream that has no row for the current key.
Every cursor must be ordered by the same comparison key, ascending unless reverse. resume carries per-child positions exactly as IntersectionMultiResume does.
func SkipCursor ¶
func SkipCursor[T any](cursor RecordCursor[T], n int) RecordCursor[T]
SkipCursor wraps a cursor and skips the first n elements. Matches Java's RecordCursor.skip().
func SkipThenLimit ¶
func SkipThenLimit[T any](cursor RecordCursor[T], skip, limit int) RecordCursor[T]
SkipThenLimit is a convenience that skips n elements then limits to m. Matches Java's RecordCursor.skipThenLimit().
func Stopped ¶
func Stopped[T any](reason NoNextReason, continuation RecordCursorContinuation) RecordCursor[T]
Stopped returns a cursor that produces no value and reports the given NoNextReason and continuation. reason must be a genuine stop reason and, per RecordCursor's contract (RecordCursor.java:212-215), anything other than SourceExhausted must carry a NON-end continuation so the caller can resume.
The precondition is checked HERE and not left to NewResultNoNext at pull time. Java validates in RecordCursorResult.withoutNextValue (RecordCursorResult.java:252-258), where deciding the stop and reporting it are the same instant. A cursor splits those apart: a violation built here would otherwise surface as a panic from whichever parent happened to pull it, naming a stack that does not contain the mistake. A misbuilt stop is a programming error either way — this only decides whether the failure names its author.
type RecordCursorContinuation ¶
type RecordCursorContinuation interface {
// ToBytes serializes this continuation to a byte array.
// Returns (nil, nil) if this is an end continuation.
ToBytes() ([]byte, error)
// IsEnd returns true if this represents the end of iteration
IsEnd() bool
}
RecordCursorContinuation represents the position of a cursor for resumption
type RecordCursorResult ¶
type RecordCursorResult[T any] struct { // contains filtered or unexported fields }
RecordCursorResult represents the result of a cursor's OnNext() call.
Invariants (matching Java's RecordCursorResult):
- A result WITH a value (HasNext=true) must NOT have an EndContinuation
- A result with SourceExhausted MUST have an EndContinuation
- A result with any other NoNextReason must NOT have an EndContinuation
The value is held BY VALUE, not behind a pointer, and hasNext is what distinguishes "has a value" — the pointer carried no information the flag does not. Boxing it cost one heap allocation per emitted row PER CURSOR LEVEL, and a plan is a stack of cursors: on a 20k-row wide scan whose plan is a projection over a scan, the boxes were the largest single allocator in the row path. GetValue still refuses to answer without a value, so the zero T a no-next result now carries is unreachable.
func MapResult ¶
func MapResult[T, R any](result RecordCursorResult[T], fn func(T) R) RecordCursorResult[R]
MapResult transforms a result's value using the given function. If the result has no value (HasNext() is false), returns a no-next result with the same reason and continuation. Go generics require this as a standalone function rather than a method. Matches Java's RecordCursorResult.map().
func NewResultNoNext ¶
func NewResultNoNext[T any](reason NoNextReason, continuation RecordCursorContinuation) RecordCursorResult[T]
NewResultNoNext creates a result indicating no more records. Enforces invariants matching Java's RecordCursorResult.withoutNextValue():
- EndContinuation is only valid with SourceExhausted
- SourceExhausted requires an EndContinuation
func NewResultWithValue ¶
func NewResultWithValue[T any](value T, continuation RecordCursorContinuation) RecordCursorResult[T]
NewResultWithValue creates a result with a value. Panics if continuation is an EndContinuation OR nil — a value result must always carry a RESUMABLE continuation (Java's RecordCursorResult.withNextValue has no null arm). A nil here would make every parent snapshot the child as START and silently replay the emitted rows on resume.
func (RecordCursorResult[T]) GetContinuation ¶
func (r RecordCursorResult[T]) GetContinuation() RecordCursorContinuation
GetContinuation returns the continuation for resuming the cursor
func (RecordCursorResult[T]) GetNoNextReason ¶
func (r RecordCursorResult[T]) GetNoNextReason() NoNextReason
GetNoNextReason returns the reason why there's no next record (valid when HasNext is false)
func (RecordCursorResult[T]) GetValue ¶
func (r RecordCursorResult[T]) GetValue() T
GetValue returns the value. Panics if HasNext() is false — callers must check HasNext() first. This matches Java's behavior of throwing IllegalResultValueAccessException.
func (RecordCursorResult[T]) HasNext ¶
func (r RecordCursorResult[T]) HasNext() bool
HasNext returns true if this result contains a value
func (RecordCursorResult[T]) HasStoppedBeforeEnd ¶
func (r RecordCursorResult[T]) HasStoppedBeforeEnd() bool
HasStoppedBeforeEnd returns true if the cursor stopped before exhausting all records. This means the cursor can be resumed with the continuation to get more results. Matches Java's RecordCursorResult.hasStoppedBeforeEnd() which checks the continuation, not the reason — with the EndContinuation↔SourceExhausted invariant, these are equivalent.
func (RecordCursorResult[T]) WithContinuation ¶
func (r RecordCursorResult[T]) WithContinuation(continuation RecordCursorContinuation) RecordCursorResult[T]
WithContinuation returns a copy of this result with a different continuation. Matches Java's RecordCursorResult.withContinuation().
type RecordDeserializationError ¶
type RecordDeserializationError struct {
PrimaryKey any // tuple.Tuple, but using any to avoid import cycle
Cause error
}
RecordDeserializationError is returned when a record fails to deserialize (unmarshal) from protobuf. Matches Java's com.apple.foundationdb.record.provider.foundationdb.RecordDeserializationException.
func (*RecordDeserializationError) Error ¶
func (e *RecordDeserializationError) Error() string
func (*RecordDeserializationError) Unwrap ¶
func (e *RecordDeserializationError) Unwrap() error
type RecordDoesNotExistError ¶
type RecordDoesNotExistError struct {
Message string
PrimaryKey any // tuple.Tuple, but using any to avoid import cycle
}
RecordDoesNotExistError is returned when attempting to update a record that does not exist. Includes structured context matching Java's RecordDoesNotExistException.
Java equivalent: com.apple.foundationdb.record.provider.foundationdb.RecordDoesNotExistException Location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/RecordDoesNotExistException.java Java includes: LogMessageKeys.PRIMARY_KEY
func (*RecordDoesNotExistError) Error ¶
func (e *RecordDoesNotExistError) Error() string
type RecordExistenceCheck ¶
type RecordExistenceCheck int
RecordExistenceCheck controls record existence validation during save operations. Matches Java's FDBRecordStoreBase.RecordExistenceCheck enum.
Java Reference: com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase.RecordExistenceCheck Location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/FDBRecordStoreBase.java:394
const ( // RecordExistenceCheckNone performs no existence validation. // This is the default behavior for SaveRecord. // // Java equivalent: NONE RecordExistenceCheckNone RecordExistenceCheck = iota // RecordExistenceCheckErrorIfExists throws an error if the record already exists. // This corresponds to InsertRecord behavior. // // Returns: RecordAlreadyExistsError if record exists // Java equivalent: ERROR_IF_EXISTS RecordExistenceCheckErrorIfExists // RecordExistenceCheckErrorIfNotExists throws an error if the record does not exist. // Use this for update-only operations where the record must pre-exist. // // Returns: RecordDoesNotExistError if record doesn't exist // Java equivalent: ERROR_IF_NOT_EXISTS RecordExistenceCheckErrorIfNotExists // RecordExistenceCheckErrorIfTypeChanged throws an error if an existing record has a different type. // Use this to prevent accidentally overwriting a record of a different type with the same primary key. // // Returns: RecordTypeChangedError if existing record has different type // Java equivalent: ERROR_IF_RECORD_TYPE_CHANGED RecordExistenceCheckErrorIfTypeChanged // RecordExistenceCheckErrorIfNotExistsOrTypeChanged combines ERROR_IF_NOT_EXISTS and ERROR_IF_RECORD_TYPE_CHANGED. // This corresponds to UpdateRecord behavior - the record must exist and must have the same type. // // Returns: RecordDoesNotExistError if record doesn't exist // Returns: RecordTypeChangedError if existing record has different type // Java equivalent: ERROR_IF_NOT_EXISTS_OR_RECORD_TYPE_CHANGED RecordExistenceCheckErrorIfNotExistsOrTypeChanged )
func (RecordExistenceCheck) ErrorIfExists ¶
func (c RecordExistenceCheck) ErrorIfExists() bool
ErrorIfExists returns true if this check should error when a record already exists.
Java equivalent: RecordExistenceCheck.errorIfExists()
func (RecordExistenceCheck) ErrorIfNotExists ¶
func (c RecordExistenceCheck) ErrorIfNotExists() bool
ErrorIfNotExists returns true if this check should error when a record does not exist.
Java equivalent: RecordExistenceCheck.errorIfNotExists()
func (RecordExistenceCheck) ErrorIfTypeChanged ¶
func (c RecordExistenceCheck) ErrorIfTypeChanged() bool
ErrorIfTypeChanged returns true if this check should error when a record's type changes.
Java equivalent: RecordExistenceCheck.errorIfTypeChanged()
func (RecordExistenceCheck) String ¶
func (c RecordExistenceCheck) String() string
String returns a human-readable representation of the existence check.
type RecordIndexUniquenessViolationError ¶
type RecordIndexUniquenessViolationError struct {
IndexName string
IndexKey tuple.Tuple
PrimaryKey tuple.Tuple
ExistingKey tuple.Tuple
}
RecordIndexUniquenessViolationError indicates a unique index constraint violation. Matches Java's RecordIndexUniquenessViolation.
func (*RecordIndexUniquenessViolationError) Error ¶
func (e *RecordIndexUniquenessViolationError) Error() string
type RecordMetaData ¶
type RecordMetaData struct {
// contains filtered or unexported fields
}
RecordMetaData describes the schema for records stored in a record store. This is a simplified version for our MVP - just enough to define record types and their primary keys.
func RecordMetaDataFromProto ¶
func RecordMetaDataFromProto(md *gen.MetaData) (*RecordMetaData, error)
RecordMetaDataFromProto deserializes a MetaData proto back into a RecordMetaData. Matches Java's RecordMetaDataBuilder.loadFromProto().
func (*RecordMetaData) AmbiguousDeclaredNames ¶
func (m *RecordMetaData) AmbiguousDeclaredNames() ([]string, bool)
AmbiguousDeclaredNames reports a pair of declared record types whose names collide across the SQL and storage namespaces, in USER identifiers, or ok=false when none collide.
Descriptor names are ESCAPED (protoname.ToProtoBufCompliantName) and the escaping is NOT injective across the two namespaces: MY$TABLE is stored as MY__1TABLE, while a table whose SQL name IS MY__1TABLE is stored as MY__01TABLE. Any lookup that tries a name as given and then its escaped form resolves the first of those to the wrong entry, and no ordering fixes it — either order prices one of the two wrong.
It lives here, beside DeclaresSyntheticRecordTypes, because it is the same KIND of fact: a property of the declarations that decides whether a caller computing over "all record types" can trust the answer. Both the statistics reader and both collection entry points need it, and a shared property with three consumers does not belong in any one of them.
CASE-SENSITIVE, and every gate that cites this function inherits that. The collision test is a map lookup on the escaped name, so a schema declaring quoted "MY$TABLE" (stored MY__1TABLE) alongside quoted "my__1table" (stored my__01table) is NOT reported: the spellings differ only in case. That gap does not reach a destructive path, because GetRecordType is case-sensitive too and never resolves one to the other -- but a renderer that lowercases before comparing would re-open it. Tracked in TODO.md.
Returns USER identifiers because the operator has to act on the SQL names; the collision itself is detected in storage space, where it lives.
func (*RecordMetaData) CommonPrimaryKey ¶
func (m *RecordMetaData) CommonPrimaryKey() KeyExpression
CommonPrimaryKey returns the primary key expression if all record types share the same one, or nil if they differ. Uses structural comparison via keyExpressionEquals. Matches Java's RecordMetaData.commonPrimaryKey().
func (*RecordMetaData) CommonPrimaryKeyLength ¶
func (m *RecordMetaData) CommonPrimaryKeyLength() int
CommonPrimaryKeyLength returns the number of columns in the primary key if all record types have the same PK length, or -1 if they differ. Matches Java's RecordMetaData.commonPrimaryKeyLength().
func (*RecordMetaData) DeclaresSyntheticRecordTypes ¶
func (m *RecordMetaData) DeclaresSyntheticRecordTypes() bool
DeclaresSyntheticRecordTypes reports whether the metadata DECLARES joined or unnested record types — types this port carries verbatim (see preservedMetaDataFields) but does not model.
It exists so that "Go does not model synthetic types" cannot be silently mistaken for "this metadata has none". Those are different claims, and only the second one licenses treating the record-type set as complete. A caller that computes over "all record types" — a scan range, a coverage decision, a count — is computing over a set that omits the synthetic ones, and must refuse rather than answer from the partial set.
func (*RecordMetaData) FileDescriptor ¶
func (m *RecordMetaData) FileDescriptor() protoreflect.FileDescriptor
FileDescriptor returns the schema's protobuf file descriptor.
func (*RecordMetaData) GetAllIndexes ¶
func (m *RecordMetaData) GetAllIndexes() map[string]*Index
GetAllIndexes returns all indexes by name.
func (*RecordMetaData) GetFormerIndexes ¶
func (m *RecordMetaData) GetFormerIndexes() []*FormerIndex
GetFormerIndexes returns all former (deleted) indexes. Matches Java's RecordMetaData.getFormerIndexes().
func (*RecordMetaData) GetFormerIndexesSince ¶
func (m *RecordMetaData) GetFormerIndexesSince(version int) []*FormerIndex
GetFormerIndexesSince returns former indexes removed since the given version. Matches Java's RecordMetaData.getFormerIndexesSince(int).
func (*RecordMetaData) GetIndex ¶
func (m *RecordMetaData) GetIndex(name string) *Index
GetIndex returns the index with the given name, or nil if not found. Matches Java's RecordMetaData.getIndex(String).
func (*RecordMetaData) GetIndexFromSubspaceKey ¶
func (m *RecordMetaData) GetIndexFromSubspaceKey(key any) *Index
GetIndexFromSubspaceKey returns the index with the given subspace key, or nil. Matches Java's RecordMetaData.getIndexFromSubspaceKey().
func (*RecordMetaData) GetIndexesForRecordType ¶
func (m *RecordMetaData) GetIndexesForRecordType(name string) []*Index
GetIndexesForRecordType returns the indexes defined for a specific record type, including both single-type and multi-type indexes. Does NOT include universal indexes — use GetUniversalIndexes() for those. Matches Java's RecordType.getAllIndexes().
Resolves through GetRecordType rather than indexing the map, so a caller holding the SQL identifier for a type stored under its escaped protobuf name gets that type's indexes instead of nil. A raw lookup here returns "this type has no indexes", which is a silent wrong answer wherever the result feeds an index-selection decision.
func (*RecordMetaData) GetIndexesToBuildSince ¶
func (m *RecordMetaData) GetIndexesToBuildSince(version int) []*Index
GetIndexesToBuildSince returns indexes that were added or modified since the given metadata version. Used by CreateOrOpen to detect new indexes that need to be built when opening an existing store with updated metadata. Matches Java's RecordMetaData.getIndexesToBuildSince(int).
func (*RecordMetaData) GetRecordCountKey ¶
func (m *RecordMetaData) GetRecordCountKey() KeyExpression
GetRecordCountKey returns the key expression used for record counting. Returns nil if counting is disabled.
func (*RecordMetaData) GetRecordType ¶
func (m *RecordMetaData) GetRecordType(name string) *RecordType
GetRecordType returns the record type for the given name.
Record types are keyed by their STORAGE name — the ProtoUtils-escaped descriptor name, which is what the wire carries. A caller holding a USER identifier (SQL text: a table declared `"foo$table"` is stored as FOO__1TABLE) resolves through the escape on a miss.
Java does not need this because its relational layer keeps its OWN table map keyed by the user name (RecordLayerSchemaTemplate.getTable) and never addresses RecordMetaData with a user identifier; Go's relational layer uses RecordMetaData directly as its table catalog, so the translation lives here — ONE boundary that every SQL path already funnels through — rather than being sprinkled over the 25 call sites.
The fallback fires only when the direct key misses, so it never SHADOWS a stored type and ToProtoBufCompliantName is deterministic. It is not, however, unambiguous: the escaping is not injective across the two namespaces, so a schema declaring both MY__1TABLE (the storage form of SQL MY$TABLE) and MY__01TABLE (the storage form of SQL MY__1TABLE) resolves a lookup for the SQL name MY__1TABLE to the FIRST of those — the wrong entry. No ordering fixes it; either order prices one of the pair wrong. See AmbiguousDeclaredNames, which is how a caller computing over all record types detects that case, and TestGetRecordTypeMisResolvesAnAmbiguousPair, which pins the behaviour so a reordering "fix" fails loudly.
func (*RecordMetaData) GetRecordTypeFromRecordTypeKey ¶
func (m *RecordMetaData) GetRecordTypeFromRecordTypeKey(key any) *RecordType
GetRecordTypeFromRecordTypeKey returns the record type with the given type key. Returns nil if no record type matches. Matches Java's RecordMetaData.getRecordTypeFromRecordTypeKey(), which scans the record types comparing getRecordTypeKey().equals(recordTypeKey).
Comparison goes through recordTypeKeyIdentity — the same identity the duplicate check uses — so a lookup can never answer a question Build did not already settle. Comparing through the general subspace-key normalizer folded a []byte key into the string of the same bytes, and Build admits that pair as two distinct types, so the lookup returned whichever of them the map happened to yield first.
func (*RecordMetaData) GetSubspaceKeyCounter ¶
func (m *RecordMetaData) GetSubspaceKeyCounter() int64
GetSubspaceKeyCounter returns the counter-based subspace-key counter value. Matches Java's RecordMetaData.getSubspaceKeyCounter().
func (*RecordMetaData) GetUnionDescriptor ¶
func (m *RecordMetaData) GetUnionDescriptor() protoreflect.MessageDescriptor
GetUnionDescriptor returns the protobuf message descriptor for UnionDescriptor. Returns nil if the schema has no union (single-type schema). Matches Java's RecordMetaData.getUnionDescriptor().
func (*RecordMetaData) GetUnionFieldForRecordType ¶
func (m *RecordMetaData) GetUnionFieldForRecordType(rt *RecordType) protoreflect.FieldDescriptor
GetUnionFieldForRecordType returns the union field descriptor for a record type. Returns nil if the record type has no union field (single-type schema). Matches Java's RecordMetaData.getUnionFieldForRecordType().
func (*RecordMetaData) GetUniversalIndexes ¶
func (m *RecordMetaData) GetUniversalIndexes() []*Index
GetUniversalIndexes returns indexes that apply to all record types.
func (*RecordMetaData) HasIndexes ¶
func (m *RecordMetaData) HasIndexes() bool
HasIndexes returns true if any indexes are defined.
func (*RecordMetaData) IsSplitLongRecords ¶
func (m *RecordMetaData) IsSplitLongRecords() bool
IsSplitLongRecords returns whether records >100KB are split across multiple KV pairs.
func (*RecordMetaData) IsStoreRecordVersions ¶
func (m *RecordMetaData) IsStoreRecordVersions() bool
IsStoreRecordVersions returns whether record versioning is enabled.
func (*RecordMetaData) PrimaryKeyHasRecordTypePrefix ¶
func (m *RecordMetaData) PrimaryKeyHasRecordTypePrefix() bool
PrimaryKeyHasRecordTypePrefix returns true if all record types have a primary key that starts with a RecordTypeKeyExpression. Matches Java's RecordMetaData.primaryKeyHasRecordTypePrefix().
func (*RecordMetaData) RecordTypes ¶
func (m *RecordMetaData) RecordTypes() map[string]*RecordType
RecordTypes returns all record types
NOTE: this returns the LIVE map, not a copy, and the map IS mutated after Build.
The census below is over changes to its KEY SET, because that is all the derived field depends on: computeAmbiguousDeclaredNames ranges the keys and probes declared[escaped], and never reads a *RecordType value. Mutating a value already in the map is irrelevant here.
ENUMERATED per site rather than counted by regex, and by SHAPE rather than by one shape mistaken for all of them. Both mistakes were made here in succession: first a count that included the sentence stating it, then an assignment census presented as a mutation census -- which survived a round of review, because the two read alike and the missing shape was delete().
Insertions, subscript form -- 8:
2 on the BUILDER, before any RecordMetaData exists, both in this file:
one in setRecordsWithUnionName, one in setRecordsWithoutUnion
6 post-Build, every one in a test:
1 in record_type_key_identity_test.go
5 in metadata_evolution_validator_test.go
Removals, delete() form -- 4, ALL post-Build, every one in a test:
1 in record_type_key_identity_test.go
3 in metadata_evolution_validator_test.go
Two of those three are bare removals with no paired insertion (the
"rejects removed type" cases); the third is half of a rename. A removal
invalidates the derived field exactly as an insertion does.
clear(), the maps.* helpers, and whole-map assignment: none AFTER
construction. online_indexer.go does assign a whole recordTypes, but that
is a []string on a different struct -- it was once miscounted into this
census.
CONSTRUCTION is a separate route with the same fail-open, and is not a
mutation of this map at all, which is why it sits outside the counts above:
metadata_evolution_validator_test.go and online_indexer_preset_test.go each
build &RecordMetaData{recordTypes: ...} directly, so Build never runs and
ambiguousFound stays false -- reported as "no collision" over a set nobody
derived.
Twelve sites, ten of them after Build.
This matters because Build DERIVES ambiguousNames from this map, so any post-Build key-set change leaves the derived field describing a declared set that no longer exists. Latent today, and measured so: none of the THREE files named above calls AmbiguousDeclaredNames, so nothing reads the stale value. A test that starts doing both re-arms it.
Copying the map here would NOT close that. All ten post-Build sites touch the private field directly rather than through this accessor, so a copy prevents none of them while adding an O(types) allocation to every caller -- including computeAmbiguousDeclaredNames itself.
The staleness is silent either way, but it is at least deterministic: the field always means "what Build saw", never "whatever the set was the first time somebody happened to ask", which is what the sync.Once it replaced meant.
func (*RecordMetaData) RecordTypesForIndex ¶
func (m *RecordMetaData) RecordTypesForIndex(idx *Index) []*RecordType
RecordTypesForIndex returns the record types that the given index covers. Universal indexes cover all record types. Type-specific indexes cover only the record types they are associated with. Matches Java's RecordMetaData.recordTypesForIndex(Index).
func (*RecordMetaData) SyntheticRecordTypeNames ¶
func (m *RecordMetaData) SyntheticRecordTypeNames() []string
SyntheticRecordTypeNames returns the declared joined/unnested type names, for diagnostics. The port does not model these types; this reads their names off the carried protos so an error can say which ones it refused for.
func (*RecordMetaData) ToProto ¶
func (m *RecordMetaData) ToProto() (*gen.MetaData, error)
ToProto serializes RecordMetaData to its protobuf representation. Matches Java's RecordMetaData.toProto().
EVERY field of the MetaData message is accounted for here, in one of two ways, and the distinction is the point of this comment — the previous version said only "Matches Java's RecordMetaData.toProto()", which read as a completeness claim it did not have. Six fields were being dropped silently.
MODELLED — parsed into Go structures and re-serialized from them:
1 records 9 dependencies 2 indexes 10 subspace_key_counter 3 record_types 11 uses_subspace_key_counter 4 split_long_records 5 version 6 former_indexes 7 record_count_key 8 store_record_versions
CARRIED VERBATIM — held as opaque protos and re-emitted unchanged, never interpreted (see preservedMetaDataFields):
12 joined_record_types 14 user_defined_functions 13 unnested_record_types 15 views
Carried is not supported. The port does not model synthetic record types, user-defined functions or views; it declines to DELETE them from metadata it did not author. Anything whose behaviour would depend on interpreting them must refuse rather than proceed on the partial view — see RecordMetaData.DeclaresSyntheticRecordTypes.
Extension ranges (1000-2000) are genuine unknown fields, and they are carried here too — as preservedMetaDataFields.unknown. Protobuf's own unknown-field preservation does NOT cover them across this round trip: it keeps unknown bytes attached to the message they were parsed into, and ToProto builds a FRESH MetaData, so nothing carries them over unless this does.
Unknown-field preservation is also the mechanism fields 12-15 were mistakenly assumed to be covered by, where it never applied for the opposite reason — they are declared fields of a message this code parses, so they were never unknown in the first place. Both halves of the message therefore need explicit carrying, and neither gets it for free.
func (*RecordMetaData) UsesSubspaceKeyCounter ¶
func (m *RecordMetaData) UsesSubspaceKeyCounter() bool
UsesSubspaceKeyCounter reports whether index subspace keys are assigned from a counter rather than from index names. Matches Java's RecordMetaData.usesSubspaceKeyCounter().
func (*RecordMetaData) Version ¶
func (m *RecordMetaData) Version() int
Version returns the metadata version
type RecordMetaDataBuilder ¶
type RecordMetaDataBuilder struct {
// contains filtered or unexported fields
}
RecordMetaDataBuilder provides a builder pattern for creating RecordMetaData This matches the Java RecordMetaDataBuilder pattern
func NewRecordMetaDataBuilder ¶
func NewRecordMetaDataBuilder() *RecordMetaDataBuilder
NewRecordMetaDataBuilder creates a new builder
func (*RecordMetaDataBuilder) AddIndex ¶
func (b *RecordMetaDataBuilder) AddIndex(recordTypeName string, index *Index) *RecordMetaDataBuilder
AddIndex adds a secondary index for a specific record type. Matches Java's RecordMetaDataBuilder.addIndex(String recordType, Index index).
func (*RecordMetaDataBuilder) AddMultiTypeIndex ¶
func (b *RecordMetaDataBuilder) AddMultiTypeIndex(recordTypeNames []string, index *Index) *RecordMetaDataBuilder
AddMultiTypeIndex adds an index spanning multiple record types. If recordTypeNames is nil or empty, treats as universal index. If only one name, adds as single-type index. Matches Java's RecordMetaDataBuilder.addMultiTypeIndex().
func (*RecordMetaDataBuilder) AddUniversalIndex ¶
func (b *RecordMetaDataBuilder) AddUniversalIndex(index *Index) *RecordMetaDataBuilder
AddUniversalIndex adds an index that applies to all record types. Matches Java's RecordMetaDataBuilder.addUniversalIndex(Index index).
func (*RecordMetaDataBuilder) Build ¶
func (b *RecordMetaDataBuilder) Build() (*RecordMetaData, error)
Build creates the final RecordMetaData.
Returns an error if any record type has no primary key set, and refuses any metadata whose index registry and record-type associations do not agree in both directions -- see the bijection check below.
WHAT BUILD WRITES INTO THE BUILDER'S OWN OBJECTS -- first, because two successive revisions of this comment claimed it wrote nothing, and the revision that fixed THAT over-claimed in the other direction by listing three writes where there is one. Exactly one:
- `idx.primaryKeyComponentPositions`, on every SINGLE-TYPE index, because `indexes[k] = v` shares the pointer. That is the point: Java sets positions on the objects the caller registered and the scan call sites read them off those same objects. (Multi-type and universal indexes are deliberately excluded -- see the loop.)
`rt.explicitRecordTypeKey` and `fi.SubspaceKey` are NOT writes, which is easy to misread because the assignments look like ones: both sites open with a struct copy (`rt := *v`, `f := *fi`) and then assign the COPY. The builder's RecordType and FormerIndex objects come out of Build unchanged. They belong to the copied set below.
WHAT STAYS SHARED with the builder after Build returns: the `*Index` objects themselves, and therefore everything reachable through them -- `Options` (a map, with the exported in-place mutators SetUnique and SetClearWhenZero), `primaryKeyComponentPositions`, `Predicate`, `predicateProto`, `subspaceKey`, and the KeyExpression graphs behind `RootExpression`. Also shared, both descriptors: `fileDescriptor` and `unionDescriptor`; and the KeyExpression graphs behind each record type's `PrimaryKey` and behind `recordCountKey`.
WHAT IS COPIED: every container Build owns directly -- the index registry map, the universal and former index slices, each record type's index slices, the RecordType and FormerIndex structs themselves (with their `[]byte` and subspace-key fields deep-copied), the `preserved` struct and all FIVE of its slices (`unknown` included), and `recordsSourceProto` (a proto.Clone; note this is the RETAINED verbatim descriptor, not the shared `fileDescriptor` named above).
WHAT IS DERIVED HERE and shared with nothing: `fieldNumberToRecordType` and `ambiguousNames`, both computed from the metadata this Build assembled.
Copying the containers keeps a later builder mutation from rewriting what Build returned; sharing the objects is what callers depend on when they hand a pre-Build *Index to ScanIndex, RebuildIndex or SetIndex, and what keeps OnlineIndexer's containment check an identity check rather than a name check. The objects therefore stay mutable through their exported fields and through those two setters, which is a divergence from Java's `private final` plus `ImmutableMap.copyOf`: DIVERGENCES.md has the analysis and the fix.
func (*RecordMetaDataBuilder) EnableCounterBasedSubspaceKeys ¶
func (b *RecordMetaDataBuilder) EnableCounterBasedSubspaceKeys() *RecordMetaDataBuilder
EnableCounterBasedSubspaceKeys switches index subspace keys from name-based (string) to counter-based (int64). Each index added after this call gets an auto-incrementing integer subspace key instead of the index name. Matches Java's RecordMetaDataBuilder.enableCounterBasedSubspaceKeys().
func (*RecordMetaDataBuilder) GetFormerIndexes ¶
func (b *RecordMetaDataBuilder) GetFormerIndexes() []*FormerIndex
GetFormerIndexes returns the builder's former indexes (for testing/inspection).
func (*RecordMetaDataBuilder) GetRecordCountKey ¶
func (b *RecordMetaDataBuilder) GetRecordCountKey() KeyExpression
GetRecordCountKey returns the record count key expression on the builder.
func (*RecordMetaDataBuilder) GetRecordType ¶
func (b *RecordMetaDataBuilder) GetRecordType(name string) *RecordTypeBuilder
GetRecordType returns the record type builder for setting primary keys, etc. Panics with MetaDataError if the record type does not exist, matching Java's RecordMetaDataBuilder.getRecordType() which throws MetaDataException.
func (*RecordMetaDataBuilder) GetRecordTypes ¶
func (b *RecordMetaDataBuilder) GetRecordTypes() map[string]*RecordType
GetRecordTypes returns the record types map on the builder.
func (*RecordMetaDataBuilder) GetSubspaceKeyCounter ¶
func (b *RecordMetaDataBuilder) GetSubspaceKeyCounter() int64
GetSubspaceKeyCounter returns the current counter value; 0 when the scheme is not enabled. Matches Java's RecordMetaDataBuilder.getSubspaceKeyCounter().
func (*RecordMetaDataBuilder) GetVersion ¶
func (b *RecordMetaDataBuilder) GetVersion() int
GetVersion returns the current metadata version on the builder. Matches Java's RecordMetaDataBuilder.getVersion().
func (*RecordMetaDataBuilder) IsSplitLongRecords ¶
func (b *RecordMetaDataBuilder) IsSplitLongRecords() bool
IsSplitLongRecords returns whether split long records is enabled on the builder. Matches Java's RecordMetaDataBuilder.isSplitLongRecords().
func (*RecordMetaDataBuilder) IsStoreRecordVersions ¶
func (b *RecordMetaDataBuilder) IsStoreRecordVersions() bool
IsStoreRecordVersions returns whether record versioning is enabled on the builder. Matches Java's RecordMetaDataBuilder.isStoreRecordVersions().
func (*RecordMetaDataBuilder) RemoveIndex ¶
func (b *RecordMetaDataBuilder) RemoveIndex(indexName string) *RecordMetaDataBuilder
RemoveIndex removes an index by name and records it as a FormerIndex to prevent subspace key reuse. Matches Java's RecordMetaDataBuilder.removeIndex(String).
func (*RecordMetaDataBuilder) SetRecordCountKey ¶
func (b *RecordMetaDataBuilder) SetRecordCountKey(key KeyExpression) *RecordMetaDataBuilder
SetRecordCountKey sets the key expression for partitioning record counts. If set, the store will maintain record counts using FDB atomic ADD mutations. If nil (default), record counting is disabled. Java equivalent: RecordMetaDataBuilder.setRecordCountKey(KeyExpression)
func (*RecordMetaDataBuilder) SetRecords ¶
func (b *RecordMetaDataBuilder) SetRecords(fd protoreflect.FileDescriptor) *RecordMetaDataBuilder
SetRecords sets the protobuf file descriptor containing record definitions. Uses the default union message name "UnionDescriptor".
func (*RecordMetaDataBuilder) SetRecordsSourceProto ¶
func (b *RecordMetaDataBuilder) SetRecordsSourceProto(fdp *descriptorpb.FileDescriptorProto) *RecordMetaDataBuilder
SetRecordsSourceProto retains the ORIGINAL FileDescriptorProto the file descriptor was built from, so ToProto() can emit it verbatim. Java keeps the source proto inside Descriptors.FileDescriptor and toProto() returns it unchanged; Go's protodesc.ToFileDescriptorProto instead RECONSTRUCTS the proto — absolutizing type names (".T" where Java stored "T") and materializing json_name — which changes the stored bytes. Descriptor bytes are wire (the catalog persists RecordMetaData.toProto()), so the source proto must survive to serialization untouched.
func (*RecordMetaDataBuilder) SetRecordsWithUnionName ¶
func (b *RecordMetaDataBuilder) SetRecordsWithUnionName(fd protoreflect.FileDescriptor, unionName string) *RecordMetaDataBuilder
SetRecordsWithUnionName is SetRecords with an explicit union message name. Use this when the proto file's union message is not called "UnionDescriptor" — e.g. schemas that must coexist with another RecordMetaData in the same Go package (gen.*), where duplicate UnionDescriptor symbols would clash. Behaviour is identical to SetRecords in every other respect.
func (*RecordMetaDataBuilder) SetSplitLongRecords ¶
func (b *RecordMetaDataBuilder) SetSplitLongRecords(split bool) *RecordMetaDataBuilder
SetSplitLongRecords enables or disables splitting records >100KB across multiple FDB key-value pairs. Matches Java's RecordMetaDataBuilder.setSplitLongRecords(boolean).
func (*RecordMetaDataBuilder) SetStoreRecordVersions ¶
func (b *RecordMetaDataBuilder) SetStoreRecordVersions(store bool) *RecordMetaDataBuilder
SetStoreRecordVersions enables or disables automatic record versioning. When enabled, each save assigns an FDBRecordVersion to the record. Java equivalent: RecordMetaDataBuilder.setStoreRecordVersions(boolean)
func (*RecordMetaDataBuilder) SetSubspaceKeyCounter ¶
func (b *RecordMetaDataBuilder) SetSubspaceKeyCounter(counter int64) *RecordMetaDataBuilder
SetSubspaceKeyCounter sets the counter's starting value, for callers whose indexes already carry keys that would collide with counter-based assignment. Matches Java's RecordMetaDataBuilder.setSubspaceKeyCounter(long), including both of its refusals: the scheme must already be enabled, and the counter may only move FORWARD. Moving it backwards would hand a fresh index a key some existing index already owns, which is a silent data collision rather than an error, so the guard is not a convenience.
func (*RecordMetaDataBuilder) SetVersion ¶
func (b *RecordMetaDataBuilder) SetVersion(version int) *RecordMetaDataBuilder
SetVersion sets the metadata schema version. This should be bumped when the schema changes for evolution tracking. Matches Java's RecordMetaDataBuilder.setVersion(int).
func (*RecordMetaDataBuilder) UsesSubspaceKeyCounter ¶
func (b *RecordMetaDataBuilder) UsesSubspaceKeyCounter() bool
UsesSubspaceKeyCounter reports whether counter-based subspace-key assignment is in effect. Matches Java's RecordMetaDataBuilder.usesSubspaceKeyCounter().
type RecordSerializationError ¶
type RecordSerializationError struct {
Cause error
}
RecordSerializationError is returned when a record fails to serialize (marshal) to protobuf. Matches Java's com.apple.foundationdb.record.provider.foundationdb.RecordSerializationException.
func (*RecordSerializationError) Error ¶
func (e *RecordSerializationError) Error() string
func (*RecordSerializationError) Unwrap ¶
func (e *RecordSerializationError) Unwrap() error
type RecordStoreAlreadyExistsError ¶
type RecordStoreAlreadyExistsError struct{}
RecordStoreAlreadyExistsError is returned when attempting to create a store that already exists. Matches Java's com.apple.foundationdb.record.provider.foundationdb.RecordStoreAlreadyExistsException.
func (*RecordStoreAlreadyExistsError) Error ¶
func (e *RecordStoreAlreadyExistsError) Error() string
type RecordStoreDoesNotExistError ¶
type RecordStoreDoesNotExistError struct{}
RecordStoreDoesNotExistError is returned when attempting to open a store that does not exist. Matches Java's com.apple.foundationdb.record.provider.foundationdb.RecordStoreDoesNotExistException.
func (*RecordStoreDoesNotExistError) Error ¶
func (e *RecordStoreDoesNotExistError) Error() string
type RecordStoreNoInfoButNotEmptyError ¶
type RecordStoreNoInfoButNotEmptyError struct {
FirstKey []byte // First key found in the subspace (Java's LogMessageKeys.KEY)
}
RecordStoreNoInfoButNotEmptyError is returned when a store subspace has data but no valid store header (StoreInfoKey). Matches Java's com.apple.foundationdb.record.provider.foundationdb.RecordStoreNoInfoAndNotEmptyException.
func (*RecordStoreNoInfoButNotEmptyError) Error ¶
func (e *RecordStoreNoInfoButNotEmptyError) Error() string
type RecordStoreState ¶
type RecordStoreState struct {
StoreHeader *gen.DataStoreInfo
IndexStates map[string]IndexState
}
RecordStoreState captures the mutable state of a record store at a point in time. Matches Java's RecordStoreState.
type RecordStoreStateNotLoadedError ¶
type RecordStoreStateNotLoadedError struct{}
RecordStoreStateNotLoadedError is returned when store operations are called before the store state has been loaded via Create/Open/CreateOrOpen. Matches Java's com.apple.foundationdb.record.provider.foundationdb.UninitializedRecordStoreException.
func (*RecordStoreStateNotLoadedError) Error ¶
func (e *RecordStoreStateNotLoadedError) Error() string
type RecordType ¶
type RecordType struct {
// Name of the record type (usually the protobuf message name)
Name string
// Protobuf message descriptor
Descriptor protoreflect.MessageDescriptor
// Primary key definition
PrimaryKey KeyExpression
// Since version (for schema evolution)
SinceVersion int
// Record type index in union descriptor (for key construction)
RecordTypeIndex int
// Union field descriptor for reflection-based access
UnionFieldDescriptor protoreflect.FieldDescriptor
// contains filtered or unexported fields
}
RecordType represents a type of record that can be stored
func (*RecordType) GetAllIndexes ¶
func (rt *RecordType) GetAllIndexes() []*Index
GetAllIndexes returns all indexes for this record type (single-type + multi-type). Does not include universal indexes. Matches Java's RecordType.getAllIndexes().
func (*RecordType) GetIndexes ¶
func (rt *RecordType) GetIndexes() []*Index
GetIndexes returns the indexes defined for this record type (single-type only). Does not include multi-type or universal indexes. Matches Java's RecordType.getIndexes().
func (*RecordType) GetMultiTypeIndexes ¶
func (rt *RecordType) GetMultiTypeIndexes() []*Index
GetMultiTypeIndexes returns the multi-type indexes for this record type. Matches Java's RecordType.getMultiTypeIndexes().
func (*RecordType) GetRecordTypeKey ¶
func (rt *RecordType) GetRecordTypeKey() any
GetRecordTypeKey returns the explicit record type key if set, or falls back to the record type index. Matches Java's RecordType.getRecordTypeKey().
The stored value is ALREADY canonical — SetRecordTypeKey and the proto reader canonicalize on the way in, as Java's setter does — so this returns it verbatim. Normalizing on the way out instead would leave every other consumer of the field (duplicate validation, proto export, prefix comparison) looking at the raw value while only the evaluation path saw the canonical one, which is the split that let equal-encoding keys pass validation as distinct.
The derived arm converts the record type index because RecordTypeIndex is a declared int field, not a caller-supplied value: the conversion is exact and total, and it gives int and int64 spellings of a key one representation.
func (*RecordType) HasExplicitRecordTypeKey ¶
func (rt *RecordType) HasExplicitRecordTypeKey() bool
HasExplicitRecordTypeKey returns true if the record type key was explicitly set. Matches Java's RecordType.hasExplicitRecordTypeKey().
func (*RecordType) IsSynthetic ¶
func (rt *RecordType) IsSynthetic() bool
IsSynthetic reports whether this is a synthetic record type (one assembled from other records, e.g. a joined type). The Go port does not model synthetic record types — they are out of scope (see CLAUDE.md) — so this is always false. Kept as a method for 1:1 fidelity with Java's RecordType.isSynthetic() so callers (e.g. the typed-records range preset) read identically to the Java algorithm.
The constant false is SOUND ONLY BECAUSE no synthetic type can reach a *RecordType. Record types are built from the union descriptor's fields, and a joined or unnested type is declared in the metadata proto rather than in the union — so it never becomes one of these. The dangerous reading is that synthetic types are absent from the METADATA, which is not what this says and is not true once fields 12/13 are carried. Callers that need the metadata-level question must ask RecordMetaData.DeclaresSyntheticRecordTypes.
func (*RecordType) PrimaryKeyHasRecordTypePrefix ¶
func (rt *RecordType) PrimaryKeyHasRecordTypePrefix() bool
PrimaryKeyHasRecordTypePrefix returns true if this record type's primary key starts with a RecordTypeKeyExpression — i.e. its records live in a contiguous record-type-keyed sub-range of the records space. Matches Java's RecordType.primaryKeyHasRecordTypePrefix().
type RecordTypeBuilder ¶
type RecordTypeBuilder struct {
// contains filtered or unexported fields
}
RecordTypeBuilder provides methods to configure a specific record type
func (*RecordTypeBuilder) SetPrimaryKey ¶
func (rtb *RecordTypeBuilder) SetPrimaryKey(keyExpr KeyExpression) *RecordTypeBuilder
SetPrimaryKey sets the primary key expression for this record type
func (*RecordTypeBuilder) SetRecordTypeKey ¶
func (rtb *RecordTypeBuilder) SetRecordTypeKey(key any) *RecordTypeBuilder
SetRecordTypeKey overrides the auto-derived record type key for this record type. By default, the record type index (proto field number order) is used. Matches Java's RecordTypeBuilder.setRecordTypeKey(Key.Evaluated), which delegates to RecordTypeIndexesBuilder.setRecordTypeKey: reject anything that is not a primitive, then store TupleTypeUtil.toTupleEquivalentValue(key).
Canonicalizing HERE, not at every read, is the whole point. The key is read by duplicate-key validation, by proto serialization, by DeleteRecordsWhere's prefix comparison and by the tuple packer, and each of those asks a different question of it — equality, encodability, wire bytes. A value normalized only on the evaluation path leaves the others looking at a different representation of the same key, which is how int64(7) and uint(7) came to be two "distinct" keys that encode to identical bytes.
A rejected key is reported from Build() rather than panicking: Java throws MetaDataException from the setter, but a Go builder setter returns the builder for chaining and library code must not panic, so the error is deferred to the one call that already returns one.
type RecordTypeChangedError ¶
type RecordTypeChangedError struct {
Message string
PrimaryKey any // tuple.Tuple, but using any to avoid import cycle
ActualType string
ExpectedType string
}
RecordTypeChangedError is returned when attempting to update a record but its type has changed. Includes structured context matching Java's RecordTypeChangedException.
Java equivalent: com.apple.foundationdb.record.provider.foundationdb.RecordTypeChangedException Location: fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/provider/foundationdb/RecordTypeChangedException.java Java includes: LogMessageKeys.PRIMARY_KEY, LogMessageKeys.ACTUAL_TYPE, LogMessageKeys.EXPECTED_TYPE
func (*RecordTypeChangedError) Error ¶
func (e *RecordTypeChangedError) Error() string
type RecordTypeKeyExpression ¶
type RecordTypeKeyExpression struct {
// contains filtered or unexported fields
}
RecordTypeKeyExpression represents the special record type key prefix. Matches Java's RecordTypeKeyExpression: evaluates to the record type key (an integer derived from the union descriptor field number). It carries NO state. Java's RecordTypeKeyExpression is a singleton with no fields whose evaluateMessage reads the key off the record being evaluated:
record != null ? Key.Evaluated.scalar(record.getRecordType().getRecordTypeKey())
: Key.Evaluated.NULL
Go previously bound a metadata-derived map onto the expression instead. That made the expression object metadata-scoped state while the object itself is shared: RecordMetaDataBuilder does not copy key expressions, so two builds from one expression graph both wrote into the same slot, and whichever bound LAST decided the record type key for BOTH — the first metadata's stores then wrote index entries and primary keys under the second metadata's key. No amount of invalidation fixes that, because the two bindings are both live at once; the state has to go. Resolving from the record makes the key a function of the record's own resolved type, which is what it always meant.
func RecordTypeKey ¶
func RecordTypeKey() *RecordTypeKeyExpression
RecordTypeKey creates a key expression that prefixes with the record type
func (*RecordTypeKeyExpression) ColumnSize ¶
func (r *RecordTypeKeyExpression) ColumnSize() int
ColumnSize returns 1 for the type key itself, plus the nested expression's column size if present.
func (*RecordTypeKeyExpression) Evaluate ¶
func (r *RecordTypeKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate returns the record type key (integer), optionally followed by nested values. Matches Java's RecordTypeKeyExpression.evaluateMessage() which returns record.getRecordType().getRecordTypeKey() — the union descriptor field number.
func (*RecordTypeKeyExpression) EvaluateFlat ¶
func (r *RecordTypeKeyExpression) EvaluateFlat(record *FDBStoredRecord[proto.Message], msg proto.Message) ([]any, error)
EvaluateFlat returns the type key as a single-element []any, or the type key followed by the nested expression's columns when Nest() was used.
evaluateKeyFlat propagates this result directly with no fallback to Evaluate, and store.go computes every record's primary key through it, so the nested columns must be produced here rather than declined — returning only the type key collapses every record of the type onto one primary key.
func (*RecordTypeKeyExpression) EvaluateScalar ¶
func (r *RecordTypeKeyExpression) EvaluateScalar(record *FDBStoredRecord[proto.Message], msg proto.Message) (any, error)
EvaluateScalar returns the type key directly — zero alloc.
Only the bare record-type key is a scalar. Nest() is a Go-only extension (Java's RecordTypeKeyExpression is KeyExpressionWithoutChildren with getColumnSize() == 1), and a nested expression makes ColumnSize() > 1, so there is no single value to return. Erroring routes every caller to Evaluate; returning just the type key would silently drop the nested columns and pack a short key.
func (*RecordTypeKeyExpression) FieldNames ¶
func (r *RecordTypeKeyExpression) FieldNames() []string
FieldNames returns the field names accessed by nested expression
func (*RecordTypeKeyExpression) Nest ¶
func (r *RecordTypeKeyExpression) Nest(expr KeyExpression) KeyExpression
Nest adds a nested key expression after the record type prefix
func (*RecordTypeKeyExpression) PackDirect ¶
func (r *RecordTypeKeyExpression) PackDirect(pk *tuple.Packer, record *FDBStoredRecord[proto.Message], msg proto.Message) bool
PackDirect encodes the record type key directly into a Packer. Reports false when the type cannot be resolved from the record, which routes the caller to the erroring Evaluate path rather than packing a guess.
A nested expression is declined for the same reason: this packer emits one element, so accepting a Nest() would write a key short of ColumnSize().
func (*RecordTypeKeyExpression) ToKeyExpression ¶
func (r *RecordTypeKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes a RecordTypeKeyExpression to proto. A bare RecordTypeKeyExpression serializes as RecordTypeKey{}. With a nested expression, serializes as Then{RecordTypeKey{}, nested} matching Java's concat(recordTypeKey(), nested).
type RecordTypeKeyTypeError ¶
type RecordTypeKeyTypeError struct {
// Key is the offending value.
Key any
// Reason distinguishes the two ways a key is refused. Empty means the Go
// TYPE is not one a record type key may have, which is Java's wording
// verbatim. A non-empty reason means the type is fine but this VALUE
// cannot be represented, where Java's message would be actively
// misleading — a uint64 above max int64 is a primitive, and saying
// otherwise sends the reader looking for the wrong mistake.
Reason string
}
RecordTypeKeyTypeError reports a record type key whose Go type cannot be a record type key. Java's equivalent is the MetaDataException "Only primitive types are allowed as record type key" thrown by RecordTypeIndexesBuilder.setRecordTypeKey.
func (*RecordTypeKeyTypeError) Error ¶
func (e *RecordTypeKeyTypeError) Error() string
type RecordTypeKeyUnresolvedError ¶
type RecordTypeKeyUnresolvedError struct {
// MessageType is the proto message name that was being evaluated, empty
// when there was no message either.
MessageType string
}
RecordTypeKeyUnresolvedError reports an evaluation of a record type key against a record whose type was never resolved. Java cannot reach this: its FDBRecord always carries a RecordType, and the save path evaluates the primary key against an FDBStoredRecordBuilder that has been given the type before any key is computed (FDBRecordStore.saveTypedRecord). Go's callers must do the same. It is an ERROR rather than a fallback to the message's type NAME because that fallback wrote a string where the integer type key belongs — bytes Java reads as a different key entirely — and did it silently.
func (*RecordTypeKeyUnresolvedError) Error ¶
func (e *RecordTypeKeyUnresolvedError) Error() string
type RecordTypeStatistic ¶
type RecordTypeStatistic struct {
// Count is the number of records of this type observed by the scan. Exact
// for a store at rest; see the type comment for what concurrent key moves do.
Count int64
// CollectedAtVersion is the read version the count was taken at.
CollectedAtVersion int64
// CollectedAtUnixNanos is the collector's wall clock at collection.
// Used for expiry; see StatisticsReader.
CollectedAtUnixNanos int64
}
RecordTypeStatistic is one collected per-record-type statistic.
Count is COUNTED, not sampled. That is the point of collecting offline: it removes the floor, the quantization and the bytes-to-rows conversion that make plan-time sampling unusable for small tables.
It is EXACT for a store that is not being mutated under the scan, and only then. Collection spans transactions -- it must, since a full scan cannot fit in one -- and each batch is a consistent snapshot of its own, not of the run. So a record whose PRIMARY KEY MOVES concurrently, from an already-scanned key to a later one, is observed by both batches and counted twice; the reverse move is observed by neither and counted zero times. Ordinary inserts and deletes are not a problem in the same way -- they are simply seen or not, which is the usual meaning of "as of collection time" -- but a key move can make the total differ from any count the store ever actually had.
This is not fixable by scanning harder. A run-wide snapshot needs one read version across the whole store, and FDB expires a read version in 5s -- the same limit that forces the batching. The honest statement is therefore the narrower one, and it is enough for the purpose: a count that is exact at rest and near-exact under churn still separates a 150-row table from a 1,000,000-row one, which is the decision this feature exists to inform, and it is a class better than the estimator it replaced.
type RowNumberWindowDirection ¶
type RowNumberWindowDirection int
RowNumberWindowDirection is the sort direction of a sliding window's ordering field. Matches Java's IndexPredicate.RowNumberWindowPredicate.Direction.
const ( // RowNumberWindowAscending keeps the SMALLEST ordering values — the rows // with the lowest row numbers in ascending order. RowNumberWindowAscending RowNumberWindowDirection = iota // RowNumberWindowDescending keeps the LARGEST ordering values. RowNumberWindowDescending )
func (RowNumberWindowDirection) String ¶
func (d RowNumberWindowDirection) String() string
type RowNumberWindowSpec ¶
type RowNumberWindowSpec struct {
// OrderingField is the field PATH of the ordering key, outermost first.
OrderingField []string
// Direction selects MIN (ASC) or MAX (DESC) extremum semantics.
Direction RowNumberWindowDirection
// Size is the window's N — how many records the index keeps per partition.
Size int
// PartitionFieldPaths are the PARTITION BY field paths, each outermost
// first. Empty means unpartitioned.
PartitionFieldPaths [][]string
}
RowNumberWindowSpec is the Go form of Java's IndexPredicate.RowNumberWindowPredicate: the declaration `QualifyRowNumber(orderingField, direction) <= size`, optionally `PARTITION BY partitionFieldPaths`.
It is a WINDOWING SPEC, not a row filter. Go's Index.Predicate is a `func(proto.Message) bool` that answers "does this record belong in the index"; a row-number window cannot be answered per-record, because the answer depends on every other record in the partition. So the compiled Index.Predicate for this arm accepts every record (matching Java's RowNumberWindowPredicate.shouldIndexThisRecord, IndexPredicate.java:739-742) and the actual windowing lives in the maintainer, which reads the spec back off the stored proto through RowNumberWindowPredicateOf.
func (*RowNumberWindowSpec) OrderingKey ¶
func (s *RowNumberWindowSpec) OrderingKey() (KeyExpression, error)
OrderingKey builds the KeyExpression for the ordering field. Matches Java's RowNumberWindowPredicate.getOrderingKey().
func (*RowNumberWindowSpec) PartitionKey ¶
func (s *RowNumberWindowSpec) PartitionKey() (KeyExpression, error)
PartitionKey builds the KeyExpression for the partition key, or nil when the window is unpartitioned. Multiple partition paths are concatenated in declaration order. Matches Java's RowNumberWindowPredicate.getPartitionKey().
func (*RowNumberWindowSpec) PartitionKeyColumnSize ¶
func (s *RowNumberWindowSpec) PartitionKeyColumnSize() (int, error)
PartitionKeyColumnSize returns the total number of columns the partition key produces, or 0 when unpartitioned. Matches Java's RowNumberWindowPredicate.getPartitionKeyColumnSize().
func (*RowNumberWindowSpec) String ¶
func (s *RowNumberWindowSpec) String() string
type SPFreshConfig ¶
type SPFreshConfig struct {
NumDimensions int
Metric VectorMetric
Lmax int // posting split threshold (entries)
LminRatio int // Lmin = Lmax / LminRatio (merge threshold)
CellTarget int // fine centroids per cell, build target
CellMax int // coarse-split threshold (fine centroids)
Replication int // closure replication cap r
Alpha float64 // RNG closure threshold (> 1.0)
Kn int // NPA reassignment neighborhood
CooldownSec int // post-split merge cooldown
NumExBits int // RaBitQ extended bits for posting residual codes
Sidecar bool // fp16 sidecar for re-rank
// BuildAssignCells is the bulk-build wave-B assignment width w_b (RFC-099):
// nearest coarse cells whose fines are candidates per imported vector.
BuildAssignCells int
}
SPFreshConfig is the structural configuration of an SPFresh index. Every field here is immutable for an existing index (RFC-094 §10).
func DefaultSPFreshConfig ¶
func DefaultSPFreshConfig(numDimensions int) SPFreshConfig
DefaultSPFreshConfig returns the RFC-094 defaults for the given dimensionality.
func (SPFreshConfig) Lmin ¶
func (c SPFreshConfig) Lmin() int
Lmin returns the merge threshold in entries.
type SPFreshIntegrityReport ¶
type SPFreshIntegrityReport struct {
Members int // total membership rows in the index
Sampled int // pks actually checked
OK int // sampled pks whose every membership target holds the posting entry
MembershipWithoutEntry int // sampled pks with >=1 membership target missing its posting entry
TargetStates map[string]int // membership-target references by centroid state: active/sealed/forward/dead/absent
BadTargets int // target references in forward/dead/absent state (unambiguously bad post-drain)
// Posting-size accounting (SPANN §3.2.1 balanced-postings / SPFresh LIRE
// split-merge bounds). The papers' defining property is length-limited
// postings; LIRE's split exists to hold the ceiling. Post-drain the normal
// envelope is mostly <=Lmax with some <=4*Lmax (just-split children,
// unsampled Lmax..2Lmax postings, closure overcount), and NEVER >4*Lmax —
// the chunked-drain hard guarantee. A split that fails to drain grows a
// posting unboundedly past the envelope, which OversizedHard catches.
ActiveFines int // ACTIVE fine centroids scanned
Oversized int // ACTIVE postings with > Lmax entries (soft: includes the legitimate <=4Lmax band)
OversizedHard int // ACTIVE postings with > 4*Lmax entries (the LIRE hard-envelope violation)
MaxPostingLen int // largest ACTIVE posting observed
Violations []SPFreshIntegrityViolation
}
SPFreshIntegrityReport is the structured result of SPFreshCheckIntegrity — the same membership⊆postings + target-state invariants SPFreshDebugIntegrity formats as a string, returned as data for programmatic assertions. The report is descriptive; the caller sets policy. After the maintenance queue is drained to quiescence the strict invariant is MembershipWithoutEntry == 0, BadTargets == 0, and OversizedHard == 0 (every membership target ACTIVE-or- SEALED with its posting entry present, no posting over the 4×Lmax envelope). SEALED targets are valid — sealed postings are still searched mid-split; only FORWARD/DEAD/absent count as BadTargets.
func SPFreshCheckIntegrity ¶
func SPFreshCheckIntegrity(rtx *FDBRecordContext, store *FDBRecordStore, indexName string, sample int) (SPFreshIntegrityReport, error)
SPFreshCheckIntegrity samples up to `sample` pks evenly from the index's own membership rows and verifies, for each, that every membership target holds the pk's posting entry (membership ⊆ postings) and classifies the target centroid's lifecycle state. It is the structured, programmatic form of SPFreshDebugIntegrity. O(index) reads (it streams the membership keyspace) — never call it on a serving path. `sample` <= 0 checks a single pk.
Violations beyond a small cap are counted but not individually recorded (BadTargets / MembershipWithoutEntry stay exact; Violations is truncated).
type SPFreshIntegrityViolation ¶
type SPFreshIntegrityViolation struct {
PrimaryKey tuple.Tuple
FineID int64
// Kind: "missing_posting" (membership target lacks this pk's posting
// entry), "absent_target" (target fineID is in no cell), "forward_target"
// (target centroid split away), "dead_target" (target centroid GC'd).
Kind string
}
SPFreshIntegrityViolation is one structural defect found by SPFreshCheckIntegrity: a membership row referencing a posting/centroid that the LIRE invariants forbid.
func (SPFreshIntegrityViolation) String ¶
func (v SPFreshIntegrityViolation) String() string
type SPFreshMaintenanceOptions ¶
type SPFreshMaintenanceOptions struct {
// Tenants is the set of (store, index) pairs to maintain. The caller owns
// discovery — store layout is application keyspace, not enumerable from
// inside the record layer. Sharding the list across workers is safe:
// SweepSPFreshIndexes is concurrent-safe by construction (unique lease
// owners, task-level exclusion).
Tenants []SPFreshTenant
// SweepInterval is the rebalance cadence. <= 0 uses the default (10s).
SweepInterval time.Duration
// RefineInterval is the refinement cadence. <= 0 uses the default (5m).
// Ignored when DisableRefine is set.
RefineInterval time.Duration
// DisableRefine turns off the RFC-104 refinement loop entirely (sweep
// only) — e.g. for a read-mostly fleet where ingest drift never builds up.
DisableRefine bool
// Sweep / Refine carry the per-pass budgets and the StoreTimer that
// accumulates instrumentation (per-kind action counts, lease skips,
// refine moves/converged — see spfresh_metrics.go). Their zero values are
// the documented defaults; set Timer to scrape metrics.
Sweep SPFreshSweepOptions
Refine SPFreshRefineOptions
// OnSweep / OnRefine, when set, are called after each pass with its result
// and joined per-tenant error — the hook for logging / exporting metrics /
// alerting on backlog. A pass error is never fatal to the loop (per-tenant
// failures are already isolated inside Sweep/Refine); the loop runs until
// ctx is canceled.
OnSweep func(SPFreshSweepResult, error)
OnRefine func(SPFreshRefineResult, error)
}
SPFreshMaintenanceOptions configures the reference maintenance loop.
type SPFreshRecallReport ¶
type SPFreshRecallReport struct {
K int // neighbors per query
CorpusSize int // indexed records scanned for ground truth
QueriesRun int // query samples evaluated
MeanRecall float64 // average recall@k across queries (the headline signal)
MinRecall float64 // worst single-query recall@k
PerfectFraction float64 // fraction of queries with recall@k == 1.0
}
SPFreshRecallReport summarizes a recall measurement.
func MeasureSPFreshRecall ¶
func MeasureSPFreshRecall(ctx context.Context, store *FDBRecordStore, indexName string, k, querySamples int, seed int64) (SPFreshRecallReport, error)
MeasureSPFreshRecall measures recall@k of a readable SPFresh index against brute-force ground truth over `querySamples` query vectors drawn from the index's own records (deterministic by seed). Returns a zero-query report when the index is empty. The store must be bound to a transaction (call inside db.Run); the whole scan+queries run in that one tx, so keep the corpus under spfreshMaxRecallCorpus (see its doc for the scale limit). Mostly read-only, but it can inherit SearchSPFreshIndex's read-path split-repair write for any over-envelope posting (none on a maintained index). Distances use the index's configured metric, so the ground-truth ranking matches what the index optimizes, and recall is scored with the SPANN §4.2.1 tie correction (a result within the k-th true distance counts, so equidistant/duplicate vectors don't under-report).
Queries are drawn from the corpus itself (not a held-out set as in the SPANN SIFT benchmark), so absolute numbers run slightly optimistic — the self-match is a guaranteed hit. That is fine for the intended use as a relative drift signal: alert on MeanRecall falling below YOUR measured baseline, not on an absolute target.
type SPFreshRefineOptions ¶
type SPFreshRefineOptions struct {
// BudgetPerTenant bounds the vectors re-evaluated per tenant per pass.
// 0 means the default (spfreshRefineFleetBudget).
BudgetPerTenant int
// Timer, when non-nil, accumulates refinement instrumentation across the pass
// (CountSPFreshRefineMoves, CountSPFreshRefineConverged) — the observability
// the rebalance sweeper gets via its own Timer. Nil disables recording.
Timer *StoreTimer
}
SPFreshRefineOptions tunes one fleet refinement pass.
type SPFreshRefineResult ¶
type SPFreshRefineResult struct {
Moves int // vectors moved (re-routed) across all tenants this pass
Refined int // tenants that completed a refine pass without error
Converged int // tenants whose cursor wrapped a full cycle moving nothing
}
SPFreshRefineResult summarizes one fleet refinement pass.
func RefineSPFreshIndexes ¶
func RefineSPFreshIndexes(ctx context.Context, db *FDBDatabase, tenants []SPFreshTenant, opts SPFreshRefineOptions) (SPFreshRefineResult, error)
RefineSPFreshIndexes runs ONE budgeted refinement pass over each tenant — the "refinement loop beside the rebalancer loop" (RFC-104). Unlike SweepSPFreshIndexes (task-driven: tenants with no pending lifecycle task rows are skipped), refinement is CURSOR-driven and unconditional — every tenant's persistent round-robin cursor advances by up to BudgetPerTenant vectors, re-routing each against the current (converged) topology and moving the stale ones, recovering the closure replication fast ingest never fired.
Run it on a SLOWER cadence than the rebalance sweep: refinement is recall-recovery, not correctness, and a fully converged tenant re-scans its cursor for zero moves each pass. The result's Converged count (cursor wrapped a full cycle with zero moves) lets a caller back off quiescent tenants. As in SweepSPFreshIndexes, per-tenant failures are isolated (joined, not fatal — one corrupt tenant must not halt fleet refinement) and ctx cancellation ends the pass between tenants.
type SPFreshSweepOptions ¶
type SPFreshSweepOptions struct {
// MaxRoundsPerTenant bounds the scan-and-act rounds per tenant per
// pass. 0 means the default (8).
MaxRoundsPerTenant int
// MaxActionsPerTenant is the per-tenant fairness budget: at most this
// many lifecycle actions per pass, ENFORCED WITHIN a round too — a
// whale tenant whose single scan finds thousands of independent task
// rows must not monopolize the pass. Undrained tenants
// are reported, not errored — the next pass continues them. 0 means
// the default (64).
MaxActionsPerTenant int
// Timer collects SPFresh maintenance instrumentation (per-kind action
// counts, zombie cleanups, lease skips — see spfresh_metrics.go) across
// the pass. Nil disables recording.
Timer *StoreTimer
}
SPFreshSweepOptions tunes one sweep pass.
type SPFreshSweepResult ¶
type SPFreshSweepResult struct {
Actions int // lifecycle actions executed across all tenants
Worked int // tenants that had pending maintenance
Undrained int // tenants whose budget ran out with work remaining
}
SPFreshSweepResult summarizes one sweep pass.
func SweepSPFreshIndexes ¶
func SweepSPFreshIndexes(ctx context.Context, db *FDBDatabase, tenants []SPFreshTenant, opts SPFreshSweepOptions) (SPFreshSweepResult, error)
SweepSPFreshIndexes makes ONE bounded pass over the tenants: a cheap pending-work probe per tenant (two snapshot reads), then a round-budgeted rebalance for the tenants that need it. Per-tenant failures are collected, not fatal — one corrupt tenant must not halt fleet maintenance; the pass continues and the joined error reports every failure. Callers loop passes on their own cadence and stop idling tenants however they like (the result says whether anything happened).
type SPFreshTenant ¶
type SPFreshTenant struct {
StoreBuilder func(*FDBRecordContext) (*FDBRecordStore, error)
IndexName string
}
SPFreshTenant names one index a sweeper drives: the store (the caller owns tenant discovery — store layout is application keyspace, not enumerable from inside the record layer) and the index within it.
type ScalarEvaluator ¶
type ScalarEvaluator interface {
EvaluateScalar(record *FDBStoredRecord[proto.Message], msg proto.Message) (any, error)
}
ScalarEvaluator is an optional interface for KeyExpressions that extract a single scalar value. Avoids both the outer [][]any and inner []any allocs.
type ScanLimitReachedError ¶
type ScanLimitReachedError struct {
// Reason is the out-of-band stop reason that triggered the failure
// (ScanLimitReached or ByteLimitReached).
Reason NoNextReason
}
ScanLimitReachedError is returned by a leaf cursor when it hits a scanned-records or scanned-bytes limit AND ExecuteProperties. FailOnScanLimitReached is set. Mirrors Java's ScanLimitReachedException (RecordCoreException, SQLSTATE 54F01): with setFailOnScanLimitReached(true) the scan errors instead of paginating. Default (false) is unchanged — the cursor returns a ScanLimitReached/ByteLimitReached NoNextReason and the caller paginates via the continuation.
func (*ScanLimitReachedError) Error ¶
func (e *ScanLimitReachedError) Error() string
type ScanLimiterState ¶
type ScanLimiterState struct {
// contains filtered or unexported fields
}
ScanLimiterState holds the mutable, execution-scoped counters that the scanned-records / scanned-bytes / time limits are checked against. It is the structural analog of Java's ExecuteState (ExecuteState.java:44-47, the RecordScanLimiter + ByteScanLimiter pair) plus the transaction-anchored TimeScanLimiter that CursorLimitManager mints from FDBRecordContext.getTransactionCreateTime() (CursorLimitManager.java:88-98) — NOT the Go type literally named ExecuteState (execute_state.go), which is a Go-only, statement-scoped extension (RFC-130's memory byte budget, no Java analog) held on ExecuteProperties.State. The two live on separate pointer fields with separate lifetimes for a reason: State/ExecuteState is minted ONCE per statement and survives every page/transaction retry (RFC-130 deliberately budgets memory across the whole result set); ScanState/ ScanLimiterState is minted fresh every time DefaultExecuteProperties is called — which paginatingRows.executeProps() does exactly once per page, INSIDE the retried transaction closure, so every retry attempt and every page gets its own honest scan/byte/time budget, matching Java's CursorLimitManager being rebuilt from a fresh FDBRecordContext each attempt.
That per-page lifetime is the AUTO-COMMIT story, and it is the whole story only there, because a page IS a transaction there. Inside an explicit SQL transaction the SQL layer overrides the freshly minted state with one held on the transaction (RFC-198 Decision 5), so every page of every statement charges ONE budget against FDB's single 5-second window instead of N fresh ones — which is the same thing Java gets from a transaction-scoped ExecuteState plus a transactionCreateTime anchor. AnchorAt below is what re-anchors that longer-lived state on the read-version instant; nothing on the auto-commit path calls it. Do not read this comment's resemblance to "ExecuteState" as a naming correspondence with Go's existing ExecuteState type; it names the Java class this ports, not the sibling Go type.
The pointer is carried on ExecuteProperties and copied BY REFERENCE through every value-copy (WithX helpers, ClearSkipAndLimit, per-leg innerProps) — the same reference-sharing pattern ExecuteProperties.State uses for the RFC-130 memory budget, just page-scoped instead of statement-scoped. That reference sharing is the fix for a real hang: an IN-join/IN-union with many legs previously gave every leg's leaf cursor its OWN local recordsScanned/bytesScanned/startTime, so a scan/byte/time limit configured to keep one FDB transaction under the 5s hard wall never tripped when each individual leg's own contribution stayed small — the limit was checked, just against the wrong (per-leg) denominator. A single ExecuteProperties value threaded through ExecutePlan's recursive leg calls (executeInJoin/executeInUnion: props.ClearSkipAndLimit(), never a fresh DefaultExecuteProperties()) now shares ONE counter set across every leg, so the aggregate scan actually stops (or errors, with FailOnScanLimitReached) once the total crosses the configured budget — matching Java's per-transaction CursorLimitManager sharing.
A nil *ScanLimiterState (any ExecuteProperties built as a raw struct literal rather than through DefaultExecuteProperties) is handled by each leaf cursor falling back to a private, cursor-local instance — identical to the pre-fix per-cursor counters, so every existing single-cursor caller is unaffected.
Concurrency: plain (non-atomic) fields, deliberately. Every leaf cursor that touches a ScanLimiterState is reached exclusively through the executor's single-threaded call chain (pkg/recordlayer/query/executor launches zero goroutines — the pinned invariant test package_invariant_test.go enforces this, and execute_state.go's ExecuteState relies on the same guarantee for its own counters) and none of the leaf cursors in this package (key_value_cursor.go, index_scan.go, record_key_cursor.go, count_index_maintainer.go, bitmap_value_index_maintainer.go, multidimensional_index_maintainer.go, text_cursor.go) spawn a goroutine either — including text_cursor.go's KVCallback, invoked synchronously from within textCursor.OnNext's own call to the underlying iterator, never from a separate goroutine. An earlier version of this file used sync/atomic for bytesScanned only, defensively, while leaving recordsScanned a plain field — inconsistent under both readings of the invariant (if it holds, the atomic ops are pure overhead — a per-record RMW where a `+=` used to suffice; if it doesn't, recordsScanned was ALREADY a silent race the moment anything pipelines). If the executor ever goes concurrent, the pinned test fires and every field here moves to atomic together, not just the one a defensive habit happened to cover.
func NewScanLimiterState ¶
func NewScanLimiterState() *ScanLimiterState
NewScanLimiterState mints a fresh counter set anchored to the current instant — Java's FDBRecordContext.transactionCreateTime, set once when the transaction/execution attempt begins (FDBRecordContext.java:187) and shared by every TimeScanLimiter minted for that transaction (CursorLimitManager.java:93).
func NewScanLimiterStateIn ¶
func NewScanLimiterStateIn(env *dst.Env) *ScanLimiterState
NewScanLimiterStateIn is NewScanLimiterState anchored on env's clock.
The time budget is not instrumentation: it decides whether a leaf cursor stops with TimeLimitReached, and therefore WHERE THE PAGE ENDS and what continuation the caller gets back. The SQL layer arms it on every single statement (paginatingRows.executeProps clamps to a per-transaction page budget so the FDB 5s wall is never crossed), so a wall-clock anchor means a simulated run pages differently depending on how fast the machine happened to be — nondeterminism in the exact layer RFC-199 exists to make reproducible.
func (*ScanLimiterState) AddBytesScanned ¶
func (s *ScanLimiterState) AddBytesScanned(n int64)
AddBytesScanned charges n more bytes against the shared counter.
func (*ScanLimiterState) AddRecordScanned ¶
func (s *ScanLimiterState) AddRecordScanned()
AddRecordScanned charges one more record against the shared counter.
func (*ScanLimiterState) AnchorAt ¶
func (s *ScanLimiterState) AnchorAt(t time.Time)
AnchorAt moves the time anchor to t, keeping the records/bytes counters. It exists for the ONE state whose lifetime outlives the instant it was minted at: the transaction-scoped state of an explicit SQL transaction (RFC-198 Decision 5). That state is minted at the first statement's executeProps — before any read has happened — but the budget it enforces is FDB's 5-second MVCC window, which opens at the GRV. Minting time is the refuted proxy (a first statement need not take a read version at all: a RYW-covered read or a store-state-cache hit reads nothing), so the page preflight re-anchors on the client's read-version instant once one exists. Re-anchoring is idempotent between GRVs, and a retry's fresh GRV re-anchors automatically at the next page.
A zero t is ignored: "no instant" must never look like an epoch-zero anchor that makes every elapsed measurement astronomical.
func (*ScanLimiterState) BytesScanned ¶
func (s *ScanLimiterState) BytesScanned() int64
BytesScanned returns the number of bytes charged against this state so far. A nil receiver reports zero.
func (*ScanLimiterState) Elapsed ¶
func (s *ScanLimiterState) Elapsed() time.Duration
Elapsed reports how long this state has been running, on the SAME clock its anchor was minted on. Every leaf cursor's TimeLimit check goes through here.
A nil receiver reports zero, which reads as "no time has passed" and so never trips a limit — the safe direction for a state that was never configured.
func (*ScanLimiterState) RecordsScanned ¶
func (s *ScanLimiterState) RecordsScanned() int
RecordsScanned returns the number of records charged against this state so far. A nil receiver (no shared state configured) reports zero.
func (*ScanLimiterState) StartTime ¶
func (s *ScanLimiterState) StartTime() time.Time
StartTime returns the instant this state was minted — the anchor every leaf cursor sharing it measures TimeLimit against. A nil receiver returns the zero Time; callers must not call this on a nil state for a live time check (leaf cursors fall back to a private, non-nil state first).
Use Elapsed for a live limit check. Reading the anchor and subtracting it from some other clock is the mistake this type now makes structurally impossible.
type ScanProperties ¶
type ScanProperties struct {
// ExecuteProperties holds the execution-level properties
ExecuteProperties ExecuteProperties
// Reverse indicates if the scan should be in reverse order
Reverse bool
// CursorStreamingMode overrides the default streaming mode
CursorStreamingMode CursorStreamingMode
}
ScanProperties groups properties that pertain to a single scan
func ForwardScan ¶
func ForwardScan() ScanProperties
ForwardScan returns properties for a forward scan with default execution properties. Returns a fresh copy each time to prevent mutation of shared state.
func NewScanProperties ¶
func NewScanProperties(executeProps ExecuteProperties) ScanProperties
NewScanProperties creates scan properties with the given execution properties
func ReverseScan ¶
func ReverseScan() ScanProperties
ReverseScan returns properties for a reverse scan with default execution properties. Returns a fresh copy each time to prevent mutation of shared state.
func (ScanProperties) GetExecuteProperties ¶
func (s ScanProperties) GetExecuteProperties() ExecuteProperties
GetExecuteProperties returns the execute properties
func (ScanProperties) IsReverse ¶
func (s ScanProperties) IsReverse() bool
IsReverse returns true if this is a reverse scan
func (ScanProperties) WithExecuteProperties ¶
func (s ScanProperties) WithExecuteProperties(props ExecuteProperties) ScanProperties
WithExecuteProperties returns a copy with the specified execute properties
func (ScanProperties) WithReverse ¶
func (s ScanProperties) WithReverse(reverse bool) ScanProperties
WithReverse returns a copy with the reverse flag set
func (ScanProperties) WithStreamingMode ¶
func (s ScanProperties) WithStreamingMode(mode CursorStreamingMode) ScanProperties
WithStreamingMode returns a copy with the specified streaming mode
type SlidingWindowCorruptionError ¶
SlidingWindowCorruptionError reports sliding-window bookkeeping that cannot be true of any consistent window — a missing boundary pointer where the count says there must be one, or a boundary entry key shorter than the window key.
Matches Java's RecordCoreException with INDEX_NAME log info; it is a distinct Go type so callers can tell corrupt bookkeeping apart from an ordinary read failure.
func (*SlidingWindowCorruptionError) Error ¶
func (e *SlidingWindowCorruptionError) Error() string
type SlidingWindowDeleteWhereError ¶
SlidingWindowDeleteWhereError reports a deleteRecordsWhere the sliding window cannot serve. Matches Java's Query.InvalidExpressionException ("deleteRecordsWhere not supported by index X") raised when canDeleteWhere returns false.
func (*SlidingWindowDeleteWhereError) Error ¶
func (e *SlidingWindowDeleteWhereError) Error() string
type SplitKeyExpression ¶
type SplitKeyExpression struct {
// contains filtered or unexported fields
}
SplitKeyExpression takes a key expression producing multiple single-element results (via FanOut) and splits them into fixed-size batches. Each batch concatenates splitSize values into one tuple. For example, 12 values with splitSize 3 produces 4 tuples of 3 elements each.
The joined expression must have column size 1 and must create duplicates (e.g. FanOut on a repeated field). The total number of values must be an even multiple of splitSize.
Matches Java's com.apple.foundationdb.record.metadata.expressions.SplitKeyExpression.
func Split ¶
func Split(joined KeyExpression, splitSize int) *SplitKeyExpression
Split creates a SplitKeyExpression that batches the joined expression's results into groups of splitSize. splitSize must be > 0.
func (*SplitKeyExpression) ColumnSize ¶
func (s *SplitKeyExpression) ColumnSize() int
ColumnSize returns the split size — each batch produces splitSize columns. Matches Java's SplitKeyExpression.getColumnSize().
func (*SplitKeyExpression) Evaluate ¶
func (s *SplitKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)
Evaluate evaluates the joined expression and splits the results into batches of splitSize. Each result from the joined expression must be a single-element tuple (from FanOut). The values are flattened, then chunked.
Returns an error if the total number of values is not evenly divisible by splitSize, matching Java's RecordCoreException behavior.
func (*SplitKeyExpression) FieldNames ¶
func (s *SplitKeyExpression) FieldNames() []string
FieldNames returns the field names accessed by the joined expression.
func (*SplitKeyExpression) GetJoined ¶
func (s *SplitKeyExpression) GetJoined() KeyExpression
GetJoined returns the underlying joined key expression.
func (*SplitKeyExpression) GetSplitSize ¶
func (s *SplitKeyExpression) GetSplitSize() int
GetSplitSize returns the number of elements per batch.
func (*SplitKeyExpression) ToKeyExpression ¶
func (s *SplitKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes SplitKeyExpression to proto. Matches Java's SplitKeyExpression.toKeyExpression().
type StaleMetaDataVersionError ¶
StaleMetaDataVersionError is returned when the stored metadata version is newer than the local metadata version, meaning another instance already evolved the schema. Matches Java's RecordStoreStaleMetaDataVersionException.
func (*StaleMetaDataVersionError) Error ¶
func (e *StaleMetaDataVersionError) Error() string
type StartContinuation ¶
type StartContinuation struct{}
StartContinuation represents the start of a cursor's iteration, or a state where no continuation is available for the current result. Unlike EndContinuation, this is NOT terminal — the cursor may have more data. Matches Java's RecordCursorStartContinuation.
func (*StartContinuation) IsEnd ¶
func (c *StartContinuation) IsEnd() bool
IsEnd returns false — StartContinuation is never an end state.
func (*StartContinuation) ToBytes ¶
func (c *StartContinuation) ToBytes() ([]byte, error)
ToBytes returns nil (no position information available).
type StatisticsReadRefusal ¶
type StatisticsReadRefusal string
StatisticsReadRefusal names WHY a statistics read produced no usable set.
It exists because a bool cannot: ReadStatisticsAt has seven distinct ways to decline, and collapsing them into ok=false made the refusals INDISTINGUISHABLE TO TESTS. Two separate checks were found dead that way -- each pinned by a spec asserting ok==false, each silently superseded by a later check that refused the same fixture first, and nothing went red at the moment either was superseded. Fixtures cannot fix that: an undecodable entry has no stamps BY CONSTRUCTION, so no fixture can make the decode arm the only thing able to refuse it.
Asserting the REASON makes the mutation matrix diagonal by construction, and means the next arm added cannot inherit an older arm's test.
const ( // StatisticsReadOK — a usable set. StatisticsReadOK StatisticsReadRefusal = "" // StatisticsReadAbsent — nothing is stored here at all: no header AND no // entries. The ordinary "never collected" case, and the ONLY refusal that // means the store is empty. StatisticsReadAbsent StatisticsReadRefusal = "no statistics stored" // StatisticsReadHeaderMissing — per-type entries survive but the header does // not. DISTINCT from Absent: something IS stored, and reporting it as // absence tells an operator the store is empty while it holds orphaned // entries that a collect would clear. The header is what makes a set // vouchable, so entries without one are torn, not missing. StatisticsReadHeaderMissing StatisticsReadRefusal = "entries present with no header" // StatisticsReadUndecodableKey — an entry key this build cannot parse. StatisticsReadUndecodableKey StatisticsReadRefusal = "entry key could not be decoded" // StatisticsReadUnknownIntegerKey — an integer key that is not THE header; // record-type names are strings, so this is corruption or a newer layout. StatisticsReadUnknownIntegerKey StatisticsReadRefusal = "unknown integer entry key" // StatisticsReadNonStringKey — a key element that is neither the header // integer nor a record-type string. StatisticsReadNonStringKey StatisticsReadRefusal = "entry key is neither header nor record type" // StatisticsReadUndecodableValue — an entry value this build cannot decode. StatisticsReadUndecodableValue StatisticsReadRefusal = "entry value could not be decoded" // StatisticsReadCountMismatch — more or fewer entries than the header says // the write put down. StatisticsReadCountMismatch StatisticsReadRefusal = "entry count disagrees with the header" // StatisticsReadVersionMismatch — an entry carrying a version that is not // the header's, so it came from a different collection run. StatisticsReadVersionMismatch StatisticsReadRefusal = "entry version disagrees with the header" // StatisticsReadTimestampMismatch — same, for the timestamp. SPLIT from the // version case deliberately: they are two arms of one condition, and a // single shared reason would leave their specs unable to tell each other // apart -- which is the exact confound this type exists to remove. The // timestamp arm shipped undriven once already because the only spec covering // the pair moved the version. StatisticsReadTimestampMismatch StatisticsReadRefusal = "entry timestamp disagrees with the header" )
type StatisticsSubspace ¶
type StatisticsSubspace struct {
// contains filtered or unexported fields
}
StatisticsSubspace addresses collected statistics for record stores under one root. The root MUST be outside every record store's subspace, and for a tenant-scoped deployment must be inside the tenant.
func NewStatisticsSubspace ¶
func NewStatisticsSubspace(root subspace.Subspace) StatisticsSubspace
NewStatisticsSubspace returns statistics addressing rooted at root.
type StoreBuilder ¶
type StoreBuilder struct {
// contains filtered or unexported fields
}
StoreBuilder builds an FDBRecordStore with configuration options. This follows the builder pattern from Java exactly.
func NewStoreBuilder ¶
func NewStoreBuilder() *StoreBuilder
NewStoreBuilder creates a new store builder
func (*StoreBuilder) Build ¶
func (b *StoreBuilder) Build() (*FDBRecordStore, error)
Build returns a store without checking database state (advanced use case)
func (*StoreBuilder) Create ¶
func (b *StoreBuilder) Create() (*FDBRecordStore, error)
Create creates a new record store, fails if store already exists
func (*StoreBuilder) CreateOrOpen ¶
func (b *StoreBuilder) CreateOrOpen() (*FDBRecordStore, error)
CreateOrOpen creates store if it doesn't exist, opens if it does (like Java). When opening an existing store whose metadata version is older than the current metadata, new indexes are automatically rebuilt inline. Matches Java's FDBRecordStore.checkPossiblyRebuild().
func (*StoreBuilder) Open ¶
func (b *StoreBuilder) Open() (*FDBRecordStore, error)
Open opens an existing record store, fails if store doesn't exist. When the current metadata version is higher than the stored version, new indexes are automatically rebuilt inline (matching Java's checkVersion flow).
func (*StoreBuilder) SetAssumeAllIndexesReadable ¶
func (b *StoreBuilder) SetAssumeAllIndexesReadable(assume bool) *StoreBuilder
SetAssumeAllIndexesReadable pre-populates an empty indexStates map during Build(), making ensureStoreStateLoaded() a complete no-op (zero FDB reads, zero lazy-load). Safe when CreateOrOpen ran at startup and all indexes are known to be READABLE. This is an explicit opt-in for maximum performance in the Build() path.
func (*StoreBuilder) SetBypassFullStoreLockReason ¶
func (b *StoreBuilder) SetBypassFullStoreLockReason(reason string) *StoreBuilder
SetBypassFullStoreLockReason sets a reason string that, if it matches the stored FULL_STORE lock reason exactly, allows the store to be opened despite the lock. This is intended for recovery operations. Calling it with "" bypasses a lock whose stored reason is empty — Java's bypass is a @Nullable String compared with equals(), so the empty string is a valid bypass value, distinct from "no bypass" (the field's nil default). Matches Java's FDBRecordStore.Builder.setBypassFullStoreLockReason().
func (*StoreBuilder) SetContext ¶
func (b *StoreBuilder) SetContext(ctx *FDBRecordContext) *StoreBuilder
SetContext sets the record context
func (*StoreBuilder) SetDatabase ¶
func (b *StoreBuilder) SetDatabase(db *FDBDatabase) *StoreBuilder
SetDatabase sets the database for inheriting the store state cache. Matches Java's FDBRecordStore.Builder.setDatabase().
func (*StoreBuilder) SetFormatVersion ¶
func (b *StoreBuilder) SetFormatVersion(version int32) *StoreBuilder
SetFormatVersion pins the format version this store opens at, instead of defaulting to the newest version this binary knows. An explicit 0 is an ERROR, not a request for the default -- see validateBuilder.
Port of Java's FDBRecordStoreBase.BaseBuilder.setFormatVersion (FDBRecordStoreBase.java:2245, :2266). Its javadoc gives the reason the value has to be a builder property rather than a constant: during a rolling upgrade you arrange "for setFormatVersion to be called with the OLD format version" on every instance, so no upgraded instance starts writing a layout the not-yet-upgraded ones cannot read. A store that always jumped to its binary's newest version would make a staged rollout impossible.
The version is a CEILING, never a downgrade: a store whose header is already past it keeps what it has, because the data on disk may already be in that layout. Values outside [formatVersionMinimum, formatVersionMaxSupported] are rejected when the store is opened.
func (*StoreBuilder) SetIndexRebuildPolicy ¶
func (b *StoreBuilder) SetIndexRebuildPolicy(policy IndexRebuildPolicy) *StoreBuilder
SetIndexRebuildPolicy sets the policy for rebuilding indexes during store open when the metadata version changes. If not set, DefaultIndexRebuildPolicy is used (inline rebuild for ≤200 records, DISABLED otherwise). Matches Java's FDBRecordStore.newBuilder().setUserVersionChecker().
func (*StoreBuilder) SetMetaDataProvider ¶
func (b *StoreBuilder) SetMetaDataProvider(metaData *RecordMetaData) *StoreBuilder
SetMetaDataProvider sets the metadata
func (*StoreBuilder) SetSkipPossiblyRebuild ¶
func (b *StoreBuilder) SetSkipPossiblyRebuild(skip bool) *StoreBuilder
SetSkipPossiblyRebuild disables automatic index rebuild checks during Open/CreateOrOpen. When set, the store will not call checkPossiblyRebuild even if the metadata version changed. This is used by OnlineIndexer which manages index states independently. Matches Java's IndexMaintenanceFilter.NONE behavior.
func (*StoreBuilder) SetStoreStateCache ¶
func (b *StoreBuilder) SetStoreStateCache(cache FDBRecordStoreStateCache) *StoreBuilder
SetStoreStateCache sets a per-store cache override. If not set, the database's cache is used. Matches Java's FDBRecordStore.Builder.setStoreStateCache().
func (*StoreBuilder) SetSubspace ¶
func (b *StoreBuilder) SetSubspace(subspace subspace.Subspace) *StoreBuilder
SetSubspace sets the subspace for this store
type StoreExistenceCheck ¶
type StoreExistenceCheck int
StoreExistenceCheck controls how store existence is validated during open. Matches Java's FDBRecordStoreBase.StoreExistenceCheck.
const ( // ExistenceCheckNone performs no existence check. ExistenceCheckNone StoreExistenceCheck = iota // ExistenceCheckErrorIfExists fails if the store already exists. ExistenceCheckErrorIfExists // ExistenceCheckErrorIfNotExists fails if the store does not exist. ExistenceCheckErrorIfNotExists )
type StoreIsFullyLockedError ¶
StoreIsFullyLockedError is returned when attempting to open a store with FULL_STORE lock state without providing the correct bypass reason. Matches Java's com.apple.foundationdb.record.StoreIsFullyLockedException.
func (*StoreIsFullyLockedError) Error ¶
func (e *StoreIsFullyLockedError) Error() string
type StoreIsLockedForRecordUpdatesError ¶
StoreIsLockedForRecordUpdatesError is returned when attempting to modify records in a store with FORBID_RECORD_UPDATE lock state. Matches Java's com.apple.foundationdb.record.StoreIsLockedForRecordUpdates.
func (*StoreIsLockedForRecordUpdatesError) Error ¶
func (e *StoreIsLockedForRecordUpdatesError) Error() string
type StoreRecordFunction ¶
type StoreRecordFunction struct {
Name string
}
StoreRecordFunction identifies a function to be evaluated on a record using store context (not index-backed). Matches Java's com.apple.foundationdb.record.metadata.StoreRecordFunction.
type StoreStatistics ¶
type StoreStatistics struct {
// PerType maps record type name to its statistic. A type ABSENT here has
// no statistic — which is a normal outcome, never an implied zero.
PerType map[string]RecordTypeStatistic
// CollectedAtVersion / CollectedAtUnixNanos are the run's own stamps, from
// the header entry.
CollectedAtVersion int64
CollectedAtUnixNanos int64
}
StoreStatistics is everything collected for one record store.
func ReadStatistics ¶
func ReadStatistics( ctx context.Context, db *FDBDatabase, stats StatisticsSubspace, storeSubspace subspace.Subspace, ) (StoreStatistics, bool, error)
ReadStatistics returns the statistics collected for one store, or ok=false if there are none. It is a SNAPSHOT read: a planner read must never add a conflict range, or planning could make a transaction retry.
Absent, malformed and unknown-format all return ok=false. There is no partial success: a caller gets a usable set or nothing.
func ReadStatisticsAt ¶
func ReadStatisticsAt( ctx context.Context, db *FDBDatabase, stats StatisticsSubspace, storeSubspace subspace.Subspace, tags ...string, ) (StoreStatistics, bool, int64, error)
ReadStatisticsAt is ReadStatisticsAtWithRefusal reduced to a boolean, for callers that only need to know whether the set is usable.
Every caller that DISTINGUISHES refusals must use the WithRefusal form. A bool cannot tell apart the eight ways this read declines, and FOUR checks were found dead precisely because their specs asserted ok==false: a later check refused the same fixture first, and the earlier one stopped being exercised with nothing going red at the moment it happened.
That applies to callers that REPORT a refusal too, not only to tests. The relational gate used this wrapper and therefore told operators "not collected" for every torn set -- an earlier draft of this very comment said "every caller that ASSERTS on a refusal", and its only non-test caller was doing exactly that while not asserting, so the wording excused it.
type StoreTimer ¶
type StoreTimer struct {
// contains filtered or unexported fields
}
StoreTimer collects instrumentation counters for Record Layer operations. All operations are goroutine-safe. A nil *StoreTimer is safe to use (all methods are no-ops on nil receiver).
func (*StoreTimer) Add ¶
func (t *StoreTimer) Add(other *StoreTimer)
Add folds every counter of other into this timer, matching Java's StoreTimer.add (StoreTimer.java:731-740).
This is Java's mechanism for aggregating instrumentation collected by a short-lived timer into a longer-lived one. It is NOT the only one, and not the one the SQL layer uses: Java's other model shares a single timer instance across many contexts (FDBDatabaseRunner.setTimer feeds every context the retry loop opens, FDBDatabaseRunner.java:105-119), which needs no fold at all because the contexts write into the same counters. Go's FDBDatabase-level timer follows that second model. Add exists for callers doing the first — measuring one unit of work in a scratch timer and rolling it up afterwards.
Counters are read one at a time, so a timer being concurrently written to does not tear an individual counter but may contribute a mix of pre- and post-write values across counters. Java has exactly the same property.
func (*StoreTimer) GetCount ¶
func (t *StoreTimer) GetCount(event Event) int64
GetCount returns the occurrence count for the given event (0 if never recorded).
func (*StoreTimer) GetCounter ¶
func (t *StoreTimer) GetCounter(event Event) *Counter
GetCounter returns the counter for the given event, or nil if never recorded.
func (*StoreTimer) GetTimeNanos ¶
func (t *StoreTimer) GetTimeNanos(event Event) int64
GetTimeNanos returns the cumulative nanoseconds for the given event (0 if never recorded).
func (*StoreTimer) Increment ¶
func (t *StoreTimer) Increment(event Event)
Increment adds one occurrence of event and leaves its cumulative value at zero. That a count event carries no duration is load-bearing, not incidental: Java uses getTimeNanos()==0 as the proof that an event is a counter rather than a timer (RecordLayerMetricCollector.java:90), and the exporter renders any non-zero cumulative value as a duration in seconds. See Counter.Increment.
func (*StoreTimer) IncrementBy ¶
func (t *StoreTimer) IncrementBy(event Event, amount int64)
IncrementBy adds amount occurrences of event, leaving its cumulative value at zero (see Increment). For a KindSize event the amount IS the byte total, which is why it accumulates in Count() — the same place Java keeps it.
func (*StoreTimer) KeysAndValues ¶
func (t *StoreTimer) KeysAndValues() map[string]int64
KeysAndValues renders the timer in Java's log-key form — the map StoreTimer.getKeysAndValues produces (StoreTimer.java:747-780) and feeds to KeyValueLogMessage.
The suffix rules are Java's, verbatim: every event emits `<name>_count`; a SizeEvent additionally emits `<name>_size` carrying the summed magnitudes; and a timed event additionally emits `<name>_micros` carrying nanoseconds divided by 1000 with integer truncation. A Count — including a size Count — emits only `_count`, because its cumulative value is 0 by construction.
The SizeEvent arm comes FIRST in Java (StoreTimer.java:755-759) and so does it here: Java tests `instanceof SizeEvent` before `instanceof Count`, so a SizeEvent gets `_size` even though its cumulative value would also satisfy the timed branch's shape.
This is the LOGGING surface and is deliberately distinct from the Prometheus exposition in pkg/recordlayer/rlmetrics, which speaks that ecosystem's conventions (base units, `_total`, summaries) instead of Java's log keys. Both read the same counters; neither is a re-encoding of the other.
func (*StoreTimer) Record ¶
func (t *StoreTimer) Record(event Event, timeNanos int64)
Record records an elapsed time in nanoseconds for the given event.
func (*StoreTimer) RecordSince ¶
func (t *StoreTimer) RecordSince(event Event, startTime time.Time)
RecordSince records the duration elapsed since startTime for the given event.
func (*StoreTimer) RecordSize ¶
func (t *StoreTimer) RecordSize(event Event, size int64)
RecordSize records one observation of a magnitude — Java's StoreTimer.recordSize (StoreTimer.java:569-571), which is Counter.record: the SIZE accumulates in CumulativeValue and the OBSERVATION in Count.
Deliberately not Increment: a KindSizeDistribution event is asked "how big was it each time", and folding the magnitude into Count would answer a question nobody asked with a number that looks like an answer to this one.
func (*StoreTimer) Snapshot ¶
func (t *StoreTimer) Snapshot() map[string]*CounterSnapshot
Snapshot returns an immutable snapshot of all counters at the current instant. The returned map is keyed by Event.Name.
type SubspaceSplitter ¶
type SubspaceSplitter interface {
SubspaceOf(keyBytes []byte) (subspace.Subspace, error)
SubspaceTag(ss subspace.Subspace) (tuple.Tuple, error)
}
SubspaceSplitter determines which sub-map a given FDB key belongs to. Used by BunchedMapMultiIterator to partition scans across multiple BunchedMaps. Matches Java's com.apple.foundationdb.map.SubspaceSplitter.
type SynchronizedSessionLockedError ¶
type SynchronizedSessionLockedError struct {
ExistingIndexerID string
ExistingInfo string
HeartbeatAgeMs int64
LeaseLengthMs int64
}
SynchronizedSessionLockedError is returned when a non-mutual indexer detects an active heartbeat from another indexer process. Matches Java's SynchronizedSessionLockedException.
func (*SynchronizedSessionLockedError) Error ¶
func (e *SynchronizedSessionLockedError) Error() string
type SyntheticRecordTypesNotModeledError ¶
type SyntheticRecordTypesNotModeledError struct {
// TypeNames are the synthetic declarations found, so a caller can say which.
//
// STORAGE names -- and unlike every other name field outside
// StatisticsStatus, they stay that way all the way out: Error() prints them
// verbatim too, for the reason given there. A programmatic consumer matching
// against metadata needs them in the namespace metadata uses, and here so
// does the human.
TypeNames []string
}
SyntheticRecordTypesNotModeledError reports metadata declaring JOINED or UNNESTED record types, which this port carries opaquely rather than modelling.
Collection refuses such a schema before scanning. RecordTypes() omits those declarations, so a run would read every record in the store to produce a set that is a PARTIAL view of the schema by construction — and would then write a header vouching for it. Completeness is undecidable against a partial set, so there is no reading of that outcome a planner could safely use.
func (*SyntheticRecordTypesNotModeledError) Error ¶
func (e *SyntheticRecordTypesNotModeledError) Error() string
Error renders the refusal for a human, naming the declarations EXACTLY as the metadata stores them.
The reason is the PRIOR on what produced the string -- not the domain, and not proof of provenance. Both kinds of name end up as protobuf message names (Java's SyntheticRecordTypeBuilder.buildDescriptor sets the synthetic one via DescriptorProto.setName, so it is validated exactly like a record type's), so the domain does not separate them; and DecodeOnceIfReversible is a pure function of the string, so its round-trip test would run identically on either. What differs is what could have written the name:
A record type declared through SQL DDL passes through protoname.ToProtoBufCompliantName. Among stored names that round-trip, escaped ones are therefore the case worth serving, and decoding is the best available reading. It is NOT proof -- SetRecords copies descriptor names verbatim -- which is exactly why that guard exists instead of an unconditional decode.
Nothing escapes into a synthetic name. Java's RecordMetaDataBuilder.addJoinedRecordType / addUnnestedRecordType store the string their caller passed, and this port never CREATES one; it only round-trips what Java wrote. So a synthetic MY__1JOINED that round-trips is not evidence of escaping, and decoding it would invent MY$JOINED -- a declaration the operator cannot find.
That matters most precisely here: this refusal exists because the port does not model these types, so the only thing an operator can do with the name is match it against their Java-side metadata, which holds the verbatim string.
The list arrives sorted by SyntheticRecordTypeNames and stays in that order; with no decoding step there are not two namespaces to disagree about.
type TagValidationError ¶
type TagValidationError struct {
Message string
// Tag is the offending tag for a length violation, empty for a count violation.
Tag string
}
TagValidationError reports a tag set rejected by the record layer's limits. Java throws IllegalArgumentException with these exact messages.
func (*TagValidationError) Error ¶
func (e *TagValidationError) Error() string
type TakeoverType ¶
type TakeoverType int
TakeoverType represents allowed build method conversions when resuming an index build that was started by a different indexing method. Matches Java's OnlineIndexer.IndexingPolicy.TakeoverTypes.
const ( // TakeoverMultiTargetToSingle allows a single-target BY_RECORDS build to continue // a MULTI_TARGET_BY_RECORDS build. TakeoverMultiTargetToSingle TakeoverType = iota // TakeoverMutualToSingle allows a single-target BY_RECORDS build to continue // a MUTUAL_BY_RECORDS build. TakeoverMutualToSingle // TakeoverByRecordsToMutual allows a MUTUAL_BY_RECORDS build to continue // a BY_RECORDS or MULTI_TARGET_BY_RECORDS build. TakeoverByRecordsToMutual )
type TextIndexBunchedSerializer ¶
type TextIndexBunchedSerializer struct{}
TextIndexBunchedSerializer serializes Tuple keys and position lists ([]int) for TEXT indexes. Position lists are delta-compressed using base-128 variable-length integer encoding. Wire-compatible with Java's com.apple.foundationdb.record.provider.foundationdb.indexes.TextIndexBunchedSerializer.
func TextIndexBunchedSerializerInstance ¶
func TextIndexBunchedSerializerInstance() *TextIndexBunchedSerializer
TextIndexBunchedSerializerInstance returns the singleton serializer.
func (*TextIndexBunchedSerializer) CanAppend ¶
func (s *TextIndexBunchedSerializer) CanAppend() bool
CanAppend returns true — this format supports appending entries without re-serialization.
func (*TextIndexBunchedSerializer) DeserializeEntries ¶
func (s *TextIndexBunchedSerializer) DeserializeEntries(key tuple.Tuple, data []byte) ([]BunchedEntry[tuple.Tuple, []int], error)
DeserializeEntries deserializes a bunch of entries from data, using key as the first entry's key. Matches Java's TextIndexBunchedSerializer.deserializeEntries().
func (*TextIndexBunchedSerializer) DeserializeKey ¶
func (s *TextIndexBunchedSerializer) DeserializeKey(data []byte, offset, length int) (tuple.Tuple, error)
DeserializeKey unpacks a Tuple key from data[offset:offset+length]. Matches Java's TextIndexBunchedSerializer.deserializeKey().
func (*TextIndexBunchedSerializer) DeserializeKeys ¶
func (s *TextIndexBunchedSerializer) DeserializeKeys(key tuple.Tuple, data []byte) ([]tuple.Tuple, error)
DeserializeKeys deserializes only the keys from a bunch (skipping values for efficiency). Matches Java's TextIndexBunchedSerializer.deserializeKeys().
func (*TextIndexBunchedSerializer) SerializeEntries ¶
func (s *TextIndexBunchedSerializer) SerializeEntries(entries []BunchedEntry[tuple.Tuple, []int]) ([]byte, error)
SerializeEntries packs an entry list into a single byte array. Format: PREFIX + entries (first entry's key omitted). Matches Java's TextIndexBunchedSerializer.serializeEntries().
func (*TextIndexBunchedSerializer) SerializeEntry ¶
SerializeEntry packs a single key-value pair (for appending to a bunch). Format: varInt(keyLen) + keyBytes + varInt(listSize) + deltaCompressedList Matches Java's TextIndexBunchedSerializer.serializeEntry().
func (*TextIndexBunchedSerializer) SerializeKey ¶
func (s *TextIndexBunchedSerializer) SerializeKey(key tuple.Tuple) []byte
SerializeKey packs a key using standard Tuple encoding. Matches Java's TextIndexBunchedSerializer.serializeKey().
type TextSubspaceSplitter ¶
type TextSubspaceSplitter struct {
// contains filtered or unexported fields
}
TextSubspaceSplitter splits TEXT index keys by grouping columns. Given an FDB key in the index subspace, extracts the first groupingColumns elements as the subspace prefix for that token's BunchedMap. Matches Java's TextSubspaceSplitter.
func NewTextSubspaceSplitter ¶
func NewTextSubspaceSplitter(indexSubspace subspace.Subspace, groupingColumns int) *TextSubspaceSplitter
NewTextSubspaceSplitter creates a splitter for TEXT index scans.
func (*TextSubspaceSplitter) SubspaceOf ¶
func (s *TextSubspaceSplitter) SubspaceOf(keyBytes []byte) (subspace.Subspace, error)
SubspaceOf extracts the subspace for a given FDB key by taking the first groupingColumns elements of the unpacked tuple.
func (*TextSubspaceSplitter) SubspaceTag ¶
SubspaceTag returns the grouping key tuple for a subspace.
type TextTokenizer ¶
type TextTokenizer interface {
// Name returns the tokenizer's name. Matches Java's getName().
Name() string
// Tokenize returns an iterator of tokens from the input text.
// Returns an error if the version is out of bounds.
// Matches Java's tokenize(String, int, TokenizerMode).
Tokenize(text string, version int, mode TokenizerMode) (TokenIterator, error)
// TokenizeToMap returns a map from token to position list (0-indexed).
// Returns an error if the version is out of bounds.
// Matches Java's tokenizeToMap(String, int, TokenizerMode).
TokenizeToMap(text string, version int, mode TokenizerMode) (map[string][]int, error)
// TokenizeToList returns all tokens as a list.
// Returns an error if the version is out of bounds.
// Matches Java's tokenizeToList(String, int, TokenizerMode).
TokenizeToList(text string, version int, mode TokenizerMode) ([]string, error)
// MaxVersion returns the maximum supported tokenizer version.
MaxVersion() int
// MinVersion returns the minimum supported tokenizer version.
MinVersion() int
}
TextTokenizer tokenizes text fields for full-text indexes. Matches Java's com.apple.foundationdb.record.provider.common.text.TextTokenizer.
func GetTextTokenizer ¶
func GetTextTokenizer(name string) (TextTokenizer, error)
GetTextTokenizer returns the tokenizer with the given name from the global registry. If name is empty, returns the default tokenizer.
type TextTokenizerFactory ¶
type TextTokenizerFactory interface {
// Name returns the tokenizer name.
Name() string
// GetTokenizer returns a tokenizer instance.
GetTokenizer() TextTokenizer
}
TextTokenizerFactory creates instances of a TextTokenizer. Matches Java's TextTokenizerFactory.
type TextTokenizerRegistry ¶
type TextTokenizerRegistry struct {
// contains filtered or unexported fields
}
TextTokenizerRegistry manages TextTokenizer instances by name. Matches Java's TextTokenizerRegistry / TextTokenizerRegistryImpl.
func GlobalTextTokenizerRegistry ¶
func GlobalTextTokenizerRegistry() *TextTokenizerRegistry
GlobalTextTokenizerRegistry returns the singleton tokenizer registry, pre-loaded with the default tokenizer.
func (*TextTokenizerRegistry) GetTokenizer ¶
func (r *TextTokenizerRegistry) GetTokenizer(name string) (TextTokenizer, error)
GetTokenizer returns the tokenizer with the given name. If name is empty, returns the default tokenizer. Returns an error if no tokenizer with that name exists.
func (*TextTokenizerRegistry) Register ¶
func (r *TextTokenizerRegistry) Register(factory TextTokenizerFactory) error
Register adds a tokenizer factory to the registry. Returns an error if a different factory with the same name is already registered.
func (*TextTokenizerRegistry) Reset ¶
func (r *TextTokenizerRegistry) Reset()
Reset clears and reinitializes the registry with only the default tokenizer.
type TimeLimitExceededError ¶
TimeLimitExceededError is returned when the OnlineIndexer's overall time limit is exceeded. Matches Java's com.apple.foundationdb.record.provider.foundationdb.IndexingBase.TimeLimitException.
func (*TimeLimitExceededError) Error ¶
func (e *TimeLimitExceededError) Error() string
type TimeWindowForFunction ¶
TimeWindowForFunction specifies a leaderboard time window for record/aggregate functions. Matches Java's com.apple.foundationdb.record.provider.foundationdb.leaderboard.TimeWindowForFunction.
type TimeWindowLeaderboardWindowUpdate ¶
type TimeWindowLeaderboardWindowUpdate struct {
UpdateTimestamp int64
HighScoreFirst bool
DeleteBefore int64
AllTime bool
Specs []TimeWindowSpec
NLevels int
Rebuild TimeWindowRebuild
}
TimeWindowLeaderboardWindowUpdate is an operation to manage active time windows. Matches Java's TimeWindowLeaderboardWindowUpdate.
type TimeWindowRebuild ¶
type TimeWindowRebuild int
TimeWindowRebuild controls when to rebuild the index after adding windows.
const ( TimeWindowRebuildNever TimeWindowRebuild = 0 TimeWindowRebuildAlways TimeWindowRebuild = 1 TimeWindowRebuildIfOverlappingChanged TimeWindowRebuild = 2 )
type TimeWindowSpec ¶
type TimeWindowSpec struct {
Type int
BaseTimestamp int64
StartIncrement int64
Duration int64
Count int
}
TimeWindowSpec defines parameters for creating a batch of time windows. Matches Java's TimeWindowLeaderboardWindowUpdate.TimeWindowSpec.
type TokenIterator ¶
type TokenIterator interface {
// HasNext returns true if there are more tokens.
HasNext() bool
// Next returns the next token. Panics if no more tokens.
Next() string
}
TokenIterator iterates over tokens produced by a TextTokenizer.
type TokenizerMode ¶
type TokenizerMode int
TokenizerMode controls whether tokenization is for indexing or querying. Some tokenizers may behave differently in each mode (e.g., n-gram tokenizers). Matches Java's TextTokenizer.TokenizerMode.
const ( // TokenizerModeIndex tokenizes for indexing documents. TokenizerModeIndex TokenizerMode = iota // TokenizerModeQuery tokenizes for query strings. TokenizerModeQuery )
type TransactionPriority ¶
type TransactionPriority int
TransactionPriority controls the priority of FDB transactions. Matches Java's FDBTransactionPriority.
const ( // PriorityDefault is the default transaction priority. PriorityDefault TransactionPriority = iota // PriorityBatch is a lower priority for background/batch operations. PriorityBatch // PrioritySystemImmediate is the highest priority, bypasses throttling. // Use with extreme care — only for system-level operations. PrioritySystemImmediate )
type TransactionSizeExceededError ¶
TransactionSizeExceededError is returned when the approximate transaction size exceeds the configured error threshold. Callers should commit the current transaction and start a new one.
func (*TransactionSizeExceededError) Error ¶
func (e *TransactionSizeExceededError) Error() string
type TransactionSizeWarningError ¶
TransactionSizeWarningError is returned once per transaction when the approximate size exceeds the configured warning threshold.
func (*TransactionSizeWarningError) Error ¶
func (e *TransactionSizeWarningError) Error() string
type TupleRange ¶
type TupleRange struct {
Low tuple.Tuple
High tuple.Tuple
LowEndpoint EndpointType
HighEndpoint EndpointType
}
TupleRange specifies a range of tuples for index scanning. Matches Java's com.apple.foundationdb.record.TupleRange.
func TupleRangeAllOf ¶
func TupleRangeAllOf(prefix tuple.Tuple) TupleRange
TupleRangeAllOf returns a range for all entries with the given tuple prefix. Matches Java's TupleRange.allOf(Tuple). For example, TupleRangeAllOf(tuple.Tuple{"alice"}) returns all index entries where the first indexed value is "alice".
func TupleRangeBetween ¶
func TupleRangeBetween(low, high tuple.Tuple) TupleRange
TupleRangeBetween returns a range [low, high) — low inclusive, high exclusive. Matches Java's TupleRange.between(Tuple, Tuple).
func TupleRangeBetweenInclusive ¶
func TupleRangeBetweenInclusive(low, high tuple.Tuple) TupleRange
TupleRangeBetweenInclusive returns a range [low, high] — both inclusive. Matches Java's TupleRange.betweenInclusive(Tuple, Tuple).
func TupleRangePrefixString ¶
func TupleRangePrefixString(token string) TupleRange
TupleRangePrefixString creates a range scanning all entries whose string element starts with the given prefix. Both endpoints use EndpointTypePrefixString so that the tuple-packed trailing null byte is stripped (low) or strinc'd (high). Matches Java's TupleRange.prefixedBy(String).
func VectorDistanceScanRange ¶
func VectorDistanceScanRange(queryVector []float64, k, efSearch int) TupleRange
VectorDistanceScanRange creates a TupleRange encoding a BY_DISTANCE kNN query. This is the Go equivalent of Java's VectorIndexScanBounds. The query vector, k, and efSearch are encoded into TupleRange fields so they can be passed through the standard ScanIndexByType API.
Usage:
store.ScanIndexByType(index, IndexScanByDistance,
VectorDistanceScanRange(queryVec, 10, 200),
nil, ForwardScan)
func VectorDistanceScanRangeOrdered ¶
func VectorDistanceScanRangeOrdered(queryVector []float64, k, efSearch, cRerank int, prefix tuple.Tuple) TupleRange
VectorDistanceScanRangeOrdered builds a BY_DISTANCE scan range for the RFC-156 Phase B distance-ORDERED stream. It DECOUPLES the re-rank budget from the probe width: cRerank (the re-rank budget c) rides the High-tuple's c slot (index 3 of the SPFresh (k, kc, w, c, ε) contract), while efSearch stays the index's TUNED probe width (SPFresh kc=64, HNSW ef) rather than being forced up to the horizon. Threading c directly avoids the efSearch>0 path's 4×k re-rank inflation and kc override (rejected in Phase B review). The intermediate w slot is 0 ("use the index default fine-probe width"). HNSW reads only (k, efSearch) and ignores the extra slots.
Who reads cRerank: ONLY the legacy self-limiting one-shot SPFresh path (ScanByDistance → searchCurrentGeneration, where c bounds the finalize re-rank). The STREAMING ordered path (IndexScanByDistanceOrderedStream → newOrderedStreamCursor) does NOT read slot 3 at all — its re-rank/candidate cap is the demand-driven stream budget (spfreshDefaultStreamCandidateBudget=4000 in defaultSPFreshStreamBudget), NOT this High-tuple slot. So cRerank/slot-3 is currently UNUSED by the streaming path; it is honoured only when this range feeds the one-shot reader, and is otherwise inert (carried for shape symmetry). Kept in the signature so the one-shot path stays expressible without a second builder; do not remove it just because the streaming path ignores it.
func VectorDistanceScanRangeWithPrefix ¶
func VectorDistanceScanRangeWithPrefix(queryVector []float64, k, efSearch int, prefix tuple.Tuple) TupleRange
VectorDistanceScanRangeWithPrefix creates a TupleRange encoding a BY_DISTANCE kNN query scoped to a specific prefix partition. The prefix identifies which independent HNSW graph to search (e.g., a specific group_id value).
Usage:
store.ScanIndexByType(index, IndexScanByDistance,
VectorDistanceScanRangeWithPrefix(queryVec, 10, 200, tuple.Tuple{int64(42)}),
nil, ForwardScan)
func (TupleRange) Contains ¶
func (r TupleRange) Contains(t tuple.Tuple) bool
Contains checks if a tuple falls within the range.
func (TupleRange) Prepend ¶
func (r TupleRange) Prepend(prefix tuple.Tuple) TupleRange
Prepend prepends a tuple prefix to both Low and High bounds. Matches Java's TupleRange.prepend(Tuple).
func (TupleRange) ToFDBRange ¶
func (r TupleRange) ToFDBRange(ss subspace.Subspace) fdb.KeyRange
ToFDBRange converts this TupleRange to an fdb.KeyRange relative to a subspace. Matches Java's TupleRange.toRange(Subspace).
type TypedFDBRecordStore ¶
TypedFDBRecordStore provides type-safe record operations with generics
func GetTypedRecordStore ¶
func GetTypedRecordStore[T proto.Message](store *FDBRecordStore, recordTypeName string) (*TypedFDBRecordStore[T], error)
GetTypedRecordStore creates a type-safe wrapper for a specific record type This follows Java's FDBRecordStore.getTypedRecordStore() pattern
func NewTypedRecordStore ¶
func NewTypedRecordStore[T proto.Message]( baseStore *FDBRecordStore, recordType *RecordType, unwrapFunc func(*gen.UnionDescriptor) (T, error), wrapFunc func(T) (*gen.UnionDescriptor, error), ) *TypedFDBRecordStore[T]
NewTypedRecordStore creates a new typed record store that wraps the base store
func (*TypedFDBRecordStore[T]) AddRecordReadConflict ¶
func (ts *TypedFDBRecordStore[T]) AddRecordReadConflict(primaryKey tuple.Tuple) error
AddRecordReadConflict adds a read conflict range for the given primary key
func (*TypedFDBRecordStore[T]) AddRecordWriteConflict ¶
func (ts *TypedFDBRecordStore[T]) AddRecordWriteConflict(primaryKey tuple.Tuple) error
AddRecordWriteConflict adds a write conflict range for the given primary key
func (*TypedFDBRecordStore[T]) Context ¶
func (ts *TypedFDBRecordStore[T]) Context() *FDBRecordContext
Context returns the record context this store is using
func (*TypedFDBRecordStore[T]) DeleteAllRecords ¶
func (ts *TypedFDBRecordStore[T]) DeleteAllRecords() error
DeleteAllRecords deletes all records from the store
func (*TypedFDBRecordStore[T]) DeleteRecord ¶
func (ts *TypedFDBRecordStore[T]) DeleteRecord(primaryKey tuple.Tuple) (bool, error)
DeleteRecord deletes a typed record by its primary key
func (*TypedFDBRecordStore[T]) GetRecordCount ¶
func (ts *TypedFDBRecordStore[T]) GetRecordCount() (int64, error)
GetRecordCount returns the total record count
func (*TypedFDBRecordStore[T]) GetSnapshotRecordCount ¶
func (ts *TypedFDBRecordStore[T]) GetSnapshotRecordCount(countKey tuple.Tuple) (int64, error)
GetSnapshotRecordCount returns the count for a specific count key
func (*TypedFDBRecordStore[T]) InsertRecord ¶
func (ts *TypedFDBRecordStore[T]) InsertRecord(record T) (*FDBStoredRecord[T], error)
InsertRecord saves a typed record and throws an error if it already exists
func (*TypedFDBRecordStore[T]) LoadRecord ¶
func (ts *TypedFDBRecordStore[T]) LoadRecord(primaryKey tuple.Tuple) (*FDBStoredRecord[T], error)
LoadRecord loads a record by its primary key with compile-time type safety
func (*TypedFDBRecordStore[T]) RecordExists ¶
func (ts *TypedFDBRecordStore[T]) RecordExists(primaryKey tuple.Tuple, isolationLevel IsolationLevel) (bool, error)
RecordExists checks if a record exists with the given primary key
func (*TypedFDBRecordStore[T]) SaveRecord ¶
func (ts *TypedFDBRecordStore[T]) SaveRecord(record T) (*FDBStoredRecord[T], error)
SaveRecord saves a typed record to the store
func (*TypedFDBRecordStore[T]) SaveRecordWithOptions ¶
func (ts *TypedFDBRecordStore[T]) SaveRecordWithOptions( record T, existenceCheck RecordExistenceCheck, ) (*FDBStoredRecord[T], error)
SaveRecordWithOptions saves a typed record with existence checking
func (*TypedFDBRecordStore[T]) ScanRecords ¶
func (ts *TypedFDBRecordStore[T]) ScanRecords(continuation []byte, scanProperties ScanProperties) RecordCursor[*FDBStoredRecord[T]]
ScanRecords returns a typed cursor scanning all records of this store's type. Records are auto-filtered to the store's type and type-asserted to T.
func (*TypedFDBRecordStore[T]) Subspace ¶
func (ts *TypedFDBRecordStore[T]) Subspace() subspace.Subspace
Subspace returns the subspace this store is using
func (*TypedFDBRecordStore[T]) UpdateRecord ¶
func (ts *TypedFDBRecordStore[T]) UpdateRecord(record T) (*FDBStoredRecord[T], error)
UpdateRecord saves a typed record and throws an error if it does not already exist or if its type has changed
type UniquenessViolation ¶
type UniquenessViolation struct {
IndexName string
IndexKey tuple.Tuple
PrimaryKey tuple.Tuple
ExistingKey tuple.Tuple // Conflicting PK stored by the other side (may be nil)
}
UniquenessViolation represents a recorded uniqueness violation entry. Matches Java's RecordIndexUniquenessViolation.
type UnknownIndexTypeError ¶
UnknownIndexTypeError is raised when no index maintainer implements an index's type. It is the port of Java's registry miss: IndexMaintainerFactoryRegistryImpl.getIndexMaintainerFactory looks the type up and throws MetaDataException("Unknown index type for " + index) when the lookup returns null (IndexMaintainerFactoryRegistryImpl.java:78-82).
It FAILS CLOSED, and the reason is a wire-format one rather than a tidiness one. Go used to answer an unrecognised type with the STANDARD maintainer — the VALUE-index one. An index whose type this build does not implement was therefore not rejected: it was silently maintained as a value index, writing value-index key bytes into that index's own subspace. Nothing surfaces at write time, because a value index is perfectly happy to serve those writes. The damage appears when a build that DOES implement the type reads that subspace and finds another format's entries, or when Java reads it and finds entries its maintainer never wrote. An index this process cannot maintain must stop the write, not receive a guess.
Unwraps to *MetaDataError so `errors.As` for the general metadata failure matches — the Go equivalent of Java's `catch (MetaDataException)`, which is what callers of the registry actually catch — while a caller that wants the index identity can match this type directly.
func (*UnknownIndexTypeError) Error ¶
func (e *UnknownIndexTypeError) Error() string
func (*UnknownIndexTypeError) Unwrap ¶
func (e *UnknownIndexTypeError) Unwrap() error
Unwrap reports this as a metadata failure. Java's exception IS a MetaDataException; in Go the identity fields need their own struct, so the relationship Java gets from inheritance is spelled out here.
type UnknownOrElseCursorStateError ¶
type UnknownOrElseCursorStateError struct{}
UnknownOrElseCursorStateError is returned when an OrElse continuation carries a state value outside the known OrElseContinuation_State range. Matches Java's OrElseCursor.UnknownOrElseCursorStateException.
func (*UnknownOrElseCursorStateError) Error ¶
func (e *UnknownOrElseCursorStateError) Error() string
type UnknownStoreLockStateError ¶
type UnknownStoreLockStateError struct {
LockStateValue int32
}
UnknownStoreLockStateError is returned when a store has an unrecognized lock state at FormatVersion >= FULL_STORE_LOCK (14). This prevents opening stores with lock states added by newer versions that we don't understand. Matches Java's com.apple.foundationdb.record.UnknownStoreLockStateException.
func (*UnknownStoreLockStateError) Error ¶
func (e *UnknownStoreLockStateError) Error() string
type UnsupportedFeatureForFormatVersionError ¶
type UnsupportedFeatureForFormatVersionError struct {
Feature string
Version int32
RequiredVersion int32
}
UnsupportedFeatureForFormatVersionError is returned when a version-gated store feature is used on a store whose header format version predates it.
Java raises a RecordCoreException with LogMessageKeys.FORMAT_VERSION at each such site — e.g. "Store does not support setting a store lock state" (FDBRecordStore.java:3478/:3494), "Store does not support updating record count state" (:3443), "Store does not support incarnation" (:3503/:3517), "cannot access header user fields at current format version" (:3222). The guard exists because these features WRITE new store-header fields: an instance still pinned at the older format can open the store and will simply not understand them, so a lock it cannot see is a lock it will not honour.
func (*UnsupportedFeatureForFormatVersionError) Error ¶
func (e *UnsupportedFeatureForFormatVersionError) Error() string
type UnsupportedFormatVersionError ¶
UnsupportedFormatVersionError is returned when a store header contains a format version higher than the maximum version this code supports. Matches Java's com.apple.foundationdb.record.provider.foundationdb.UnsupportedFormatVersionException.
func (*UnsupportedFormatVersionError) Error ¶
func (e *UnsupportedFormatVersionError) Error() string
type VectorMetric ¶
type VectorMetric int
VectorMetric identifies a distance metric for HNSW vector search.
const ( // VectorMetricEuclidean is true L2: sqrt(Σ(a_i−b_i)²). Matches Java's // EUCLIDEAN_METRIC (MetricDefinition.EuclideanMetric.distance = Math.sqrt(...)). VectorMetricEuclidean VectorMetric = iota VectorMetricCosine VectorMetricInnerProduct // VectorMetricEuclideanSquare is squared L2: Σ(a_i−b_i)² (no sqrt). Matches // Java's EUCLIDEAN_SQUARE_METRIC — same KNN ordering as L2, cheaper, but it is // NOT a true metric (does not satisfy the triangle inequality). Added at the end // so the existing iota values are unchanged (the int is never persisted; configs // round-trip via the option string, e.g. "EUCLIDEAN_SQUARE_METRIC"). VectorMetricEuclideanSquare )
type VectorQuantizer ¶
type VectorQuantizer interface {
// Encode quantizes a float64 vector into compact bytes for storage.
Encode(vector []float64) []byte
// Distance estimates the distance between a raw query vector and stored
// quantized bytes. Returns the estimated distance.
Distance(query []float64, storedBytes []byte, numDimensions int) (float64, error)
// Decode reconstructs an approximate float64 vector from stored quantized bytes.
// Used for pairwise distance in the neighbor selection heuristic.
Decode(storedBytes []byte, numDimensions int) ([]float64, error)
// GetTypeByte returns the type ordinal byte used as the first byte of encoded data.
// This is used to dispatch between raw and quantized storage.
GetTypeByte() byte
}
VectorQuantizer is an optional quantization strategy for HNSW vector storage. When set on HNSWConfig, HNSW uses it for encoding, distance estimation, and vector reconstruction instead of raw float64 storage.
This interface allows quantization implementations (like RaBitQ) to live in separate packages, matching Java's architecture where RaBitQ is in fdb-extensions.
type VectorScanBounds ¶
type VectorScanBounds struct {
QueryVector []float64 // The query vector for similarity search.
K int // Number of nearest neighbors to return.
EfSearch int // Search exploration factor (0 = auto from K).
}
VectorScanBounds carries the parameters for a BY_DISTANCE kNN scan. Matches Java's VectorIndexScanBounds (query vector, k limit, efSearch, options).
type VectorSearchResult ¶
VectorSearchResult is a single result from a vector similarity search.
func SearchSPFreshIndex ¶
func SearchSPFreshIndex(store *FDBRecordStore, indexName string, queryVector []float64, k int) ([]VectorSearchResult, error)
SearchSPFreshIndex runs a kNN search against a readable SPFresh index, returning up to k nearest primary keys (with exact, sidecar-re-ranked distances, ascending) to queryVector using the index's default probe budget. It is the SPFresh counterpart to FDBRecordStore.SearchVectorIndex (vector_index_maintainer.go), which type-asserts the HNSW maintainer and rejects SPFresh. Callers needing per-query probe knobs (k, kc, w, c, ε) drive ScanByDistance through the executor instead.
Returns *IndexNotReadableError if the index is not scannable (matching the HNSW SearchVectorIndex contract). NOT purely read-only: like the SPFresh read path it shares (searchCurrentGeneration), a probe that reads a posting at the 4×Lmax+1 cap re-files that posting's split task (the read-path envelope repair) — a write the surrounding transaction commits. On a maintained index no posting is over the cap, so the common path performs no writes.
type VersionKeyExpression ¶
type VersionKeyExpression struct{}
VersionKeyExpression extracts the record version as a Versionstamp tuple element. Used by VERSION indexes to index records by their commit version. Matches Java's com.apple.foundationdb.record.metadata.expressions.VersionKeyExpression.
func VersionKey ¶
func VersionKey() *VersionKeyExpression
VersionKey creates a key expression that evaluates to the record's version. Matches Java's Key.Expressions.version().
func (*VersionKeyExpression) ColumnSize ¶
func (v *VersionKeyExpression) ColumnSize() int
ColumnSize returns 1 — a version expression produces a single tuple element.
func (*VersionKeyExpression) Evaluate ¶
func (v *VersionKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], _ proto.Message) ([][]any, error)
Evaluate returns the record's version as a Versionstamp. For complete versions, returns a complete tuple.Versionstamp. For incomplete versions, returns an incomplete tuple.Versionstamp (with placeholder bytes). If record or version is nil, returns [[nil]]. Matches Java's VersionKeyExpression.evaluateMessage().
func (*VersionKeyExpression) FieldNames ¶
func (v *VersionKeyExpression) FieldNames() []string
FieldNames returns an empty slice — version expressions don't access proto fields.
func (*VersionKeyExpression) ToKeyExpression ¶
func (v *VersionKeyExpression) ToKeyExpression() *gen.KeyExpression
ToKeyExpression serializes a VersionKeyExpression to proto. Matches Java's VersionKeyExpression.toKeyExpression().
type VersionMutationType ¶
type VersionMutationType int
VersionMutationType represents the type of versionstamp mutation. Matches Java's MutationType used in FDBRecordContext.addVersionMutation().
const ( // MutationTypeSetVersionstampedValue queues a SET_VERSIONSTAMPED_VALUE mutation. MutationTypeSetVersionstampedValue VersionMutationType = iota // MutationTypeSetVersionstampedKey queues a SET_VERSIONSTAMPED_KEY mutation. MutationTypeSetVersionstampedKey )
type WeakReadSemantics ¶
type WeakReadSemantics struct {
// MinVersion is the minimum read version acceptable. If the cached read
// version is >= MinVersion, it will be reused without a GRV round-trip.
MinVersion int64
// StalenessBoundMillis is the maximum staleness (in ms) of a cached read
// version. If the cached version is older than this, a fresh GRV is fetched.
StalenessBoundMillis int64
// IsCausalReadRisky sets the FDB_TR_OPTION_CAUSAL_READ_RISKY flag.
// This allows the transaction to read from any storage replica, not
// just the one with the latest committed data.
IsCausalReadRisky bool
}
WeakReadSemantics configures relaxed read consistency for a transaction. When provided, the transaction may read at a slightly stale version, reducing GRV latency at the cost of freshness. Matches Java's FDBDatabase.WeakReadSemantics.
Source Files
¶
- aggregate_function.go
- aggregate_group_existence.go
- atomic_index_helpers.go
- atomic_mutation.go
- atomic_mutation_index_maintainer.go
- bitmap_value_index_maintainer.go
- bunched_map.go
- bunched_map_iterator.go
- chained_cursor.go
- collate_function_key_expression.go
- constants.go
- count_index_maintainer.go
- cursor.go
- cursor_combinators.go
- cursor_util.go
- database.go
- dedup_cursor.go
- dimensions_key_expression.go
- endpoint_type.go
- errors.go
- execute_state.go
- existence_check.go
- fallback_cursor.go
- fht_kac_rotator.go
- hnsw.go
- hnsw_distance_bytes.go
- hnsw_stats.go
- hnsw_vector.go
- index.go
- index_maintainer.go
- index_predicate.go
- index_scan.go
- index_state.go
- index_validation.go
- indexing_heartbeat.go
- indexing_mutual.go
- indexing_range_set.go
- indexing_throttle.go
- instrumented_cursor.go
- key_expression.go
- key_expression_cardinality.go
- key_expression_proto.go
- key_expression_validate.go
- key_value_cursor.go
- list_key_expression.go
- long_arithmetic_function.go
- max_ever_version_index_maintainer.go
- merge_cursor.go
- metadata.go
- metadata_evolution_validator.go
- metadata_export.go
- metadata_proto.go
- metadata_store.go
- multidimensional_index_maintainer.go
- online_indexer.go
- order_function_key_expression.go
- permuted_min_max_index_maintainer.go
- permuted_min_null_semantics.go
- primary_key_translation.go
- proto_names.go
- range_set.go
- rank_index_maintainer.go
- ranked_set.go
- record_count.go
- record_function.go
- record_key_cursor.go
- record_version.go
- rename_fields_visitor.go
- row_number_window_predicate.go
- rtree.go
- rtree_hilbert.go
- rtree_storage.go
- rtree_types.go
- runner.go
- scan_limiter_state.go
- scan_properties.go
- sliding_window_index_maintainer.go
- sliding_window_index_validation.go
- spfresh_build.go
- spfresh_cache.go
- spfresh_codec.go
- spfresh_config.go
- spfresh_csplit.go
- spfresh_gc.go
- spfresh_index_maintainer.go
- spfresh_kmeans.go
- spfresh_layout.go
- spfresh_merge.go
- spfresh_metrics.go
- spfresh_npa.go
- spfresh_query.go
- spfresh_rebalancer.go
- spfresh_recall.go
- spfresh_refine.go
- spfresh_split.go
- spfresh_storage.go
- spfresh_stream.go
- spfresh_sweeper.go
- spfresh_util.go
- spfresh_verify_api.go
- spfresh_worker.go
- spfresh_write.go
- split_helper.go
- split_key_expression.go
- statistics.go
- store.go
- store_api.go
- store_batch.go
- store_builder.go
- store_delete_where.go
- store_function.go
- store_state_cache.go
- store_timer.go
- store_typed.go
- store_version.go
- text_cursor.go
- text_index_maintainer.go
- text_index_serializer.go
- text_tokenizer.go
- time_window_leaderboard.go
- time_window_leaderboard_maintainer.go
- tuple_fast.go
- tuple_ordering.go
- vector_index_maintainer.go
- vector_index_validation.go
- version_index_maintainer.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package chaos provides model-based chaos testing for the FDB Record Layer.
|
Package chaos provides model-based chaos testing for the FDB Record Layer. |
|
Package keyspace provides a logical directory tree abstraction over FDB.
|
Package keyspace provides a logical directory tree abstraction over FDB. |
|
Package protoname is the protobuf identifier escaping shared by every descriptor emitter in the tree, and the DISPLAY policy that decides when an escaped name may safely be shown as the SQL identifier it came from.
|
Package protoname is the protobuf identifier escaping shared by every descriptor emitter in the tree, and the DISPLAY policy that decides when an escaped name may safely be shown as the SQL identifier it came from. |
|
query
|
|
|
executor
Package executor bridges RecordQueryPlan trees (Cascades planner output) and the FDBRecordStore scanning API to produce RecordCursor[QueryResult] streams.
|
Package executor bridges RecordQueryPlan trees (Cascades planner output) and the FDBRecordStore scanning API to produce RecordCursor[QueryResult] streams. |
|
plan/cascades
derivations_evaluator.go — evaluates DerivationsProperty for physical plan wrapper expressions.
|
derivations_evaluator.go — evaluates DerivationsProperty for physical plan wrapper expressions. |
|
plan/cascades/expressions
Package expressions ports the Cascades-side relational expression hierarchy from Java's `com.apple.foundationdb.record.query.plan.cascades.expressions`.
|
Package expressions ports the Cascades-side relational expression hierarchy from Java's `com.apple.foundationdb.record.query.plan.cascades.expressions`. |
|
plan/cascades/properties
Package properties — Cardinality and Cardinalities types.
|
Package properties — Cardinality and Cardinalities types. |
|
plan/cascades/values
Package values is the Value-tier of the Go Cascades planner port — scalar / row-context expressions that compose into predicates, projections, and join keys.
|
Package values is the Value-tier of the Go Cascades planner port — scalar / row-context expressions that compose into predicates, projections, and join keys. |
|
plan/plans
Go extension — no Java equivalent.
|
Go extension — no Java equivalent. |
|
Package rlmetrics exposes a record-layer StoreTimer (the Go port of Java's FDBStoreTimer) in the Prometheus text exposition format, ready to scrape — with zero dependencies.
|
Package rlmetrics exposes a record-layer StoreTimer (the Go port of Java's FDBStoreTimer) in the Prometheus text exposition format, ready to scrape — with zero dependencies. |
|
Package vectorcodec is the on-disk byte codec for HNSW vector columns, wire-compatible with Java's RealVector.fromBytes / VectorType.
|
Package vectorcodec is the on-disk byte codec for HNSW vector columns, wire-compatible with Java's RealVector.fromBytes / VectorType. |