recordlayer

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: Apache-2.0 Imports: 72 Imported by: 0

Documentation

Overview

Package recordlayer stores protobuf records in FoundationDB with secondary indexes, schema evolution and resumable cursors. It is a port of Apple's Java FoundationDB Record Layer; Go and Java can share record stores, subject to the exceptions that docs/compatibility.md lists.

Metadata comes from a protobuf file whose union message lists the record types. A store is opened inside a transaction, where records are saved, loaded, scanned and queried:

builder := recordlayer.NewRecordMetaDataBuilder().SetRecords(shoppb.File_shop_proto)
builder.GetRecordType("Order").SetPrimaryKey(recordlayer.Field("order_id"))
builder.AddIndex("Order", recordlayer.NewIndex("price_idx", recordlayer.Field("price")))
metadata, err := builder.Build()
if err != nil {
	return err
}

rdb := recordlayer.NewFDBDatabase(db)
_, err = rdb.Run(ctx, func(rtx *recordlayer.FDBRecordContext) (any, error) {
	store, err := recordlayer.NewStoreBuilder().
		SetContext(rtx).
		SetMetaDataProvider(metadata).
		SetSubspace(subspace.FromBytes([]byte("app"))).
		CreateOrOpen()
	if err != nil {
		return nil, err
	}
	return store.SaveRecord(&shoppb.Order{OrderId: proto.Int64(1), Price: proto.Int32(25)})
})

Run retries retryable errors in a fresh transaction, so keep external side effects outside its callback. The runnable example is example/getting_started.go; docs/operations.md covers online index builds and schema evolution.

Index

Constants

View Source
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.

View Source
const (
	DefaultMaxAttempts  = 10
	DefaultInitialDelay = 10 * time.Millisecond
	DefaultMaxDelay     = 1000 * time.Millisecond
)

Java's FDBDatabaseFactory defaults, which every FDBDatabaseRunner inherits (FDBDatabaseFactory.java: DEFAULT_MAX_ATTEMPTS, maxDelayMillis, initialDelayMillis).

View Source
const (
	CollateFuncJRE = "collate_jre"
	CollateFuncICU = "collate_icu"
)

Collation function names matching Java's CollateFunctionKeyExpressionFactory. Both names use the frozen x/text collator, not Java's JRE/ICU key formats. Persisting or querying those keys requires StoreBuilder.SetGoOnlyCollation.

View Source
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.

View Source
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.

View Source
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.

View Source
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.

View Source
const (
	IndexFetchScanAndFetch               = indexfetch.ScanAndFetch
	IndexFetchUseRemoteFetch             = indexfetch.UseRemoteFetch
	IndexFetchUseRemoteFetchWithFallback = indexfetch.UseRemoteFetchWithFallback
)
View Source
const (
	IndexOptionGuardiannPrimaryClusterMin                = "guardiannPrimaryClusterMin"
	IndexOptionGuardiannPrimaryClusterMax                = "guardiannPrimaryClusterMax"
	IndexOptionGuardiannPrimaryClusterHardMax            = "guardiannPrimaryClusterHardMax"
	IndexOptionGuardiannUnderreplicatedPrimaryClusterMax = "guardiannUnderreplicatedPrimaryClusterMax"
	IndexOptionGuardiannReplicatedClusterMaxWrites       = "guardiannReplicatedClusterMaxWrites"
	IndexOptionGuardiannReplicatedClusterTarget          = "guardiannReplicatedClusterTarget"
	IndexOptionGuardiannReplicationPriorityMin           = "guardiannReplicationPriorityMin"
	IndexOptionGuardiannInsertMaxCandidateClusters       = "guardiannInsertMaxCandidateClusters"
	IndexOptionGuardiannDeleteMaxCandidateClusters       = "guardiannDeleteMaxCandidateClusters"
	IndexOptionGuardiannSplitNumNearestClusters          = "guardiannSplitNumNearestClusters"
	IndexOptionGuardiannMergeNumNearestClusters          = "guardiannMergeNumNearestClusters"
	IndexOptionGuardiannReassignNumNeighboringClusters   = "guardiannReassignNumNeighboringClusters"
	IndexOptionGuardiannCollapseMinDuplicates            = "guardiannCollapseMinDuplicates"
)

GuardiANN option names (Java IndexOptions.GUARDIANN_*).

View Source
const (
	IndexOptionGuardiannMergeMaxEverFraction                = "guardiannMergeMaxEverFraction"
	IndexOptionGuardiannMinChildFraction                    = "guardiannMinChildFraction"
	IndexOptionGuardiannMaxRelativeImbalance                = "guardiannMaxRelativeImbalance"
	IndexOptionGuardiannSplitImbalancePenalty               = "guardiannSplitImbalancePenalty"
	IndexOptionGuardiannReplicationDistanceRatioWeight      = "guardiannReplicationDistanceRatioWeight"
	IndexOptionGuardiannReplicationZScoreWeight             = "guardiannReplicationZScoreWeight"
	IndexOptionGuardiannReplicationStatsMinSampleSize       = "guardiannReplicationStatsMinSampleSize"
	IndexOptionGuardiannDeterministicRandomness             = "guardiannDeterministicRandomness"
	IndexOptionGuardiannSampleBatchSize                     = "guardiannSampleBatchSize"
	IndexOptionGuardiannDeleteConcurrency                   = "guardiannDeleteConcurrency"
	IndexOptionGuardiannKMeansMaxIterations                 = "guardiannKMeansMaxIterations"
	IndexOptionGuardiannKMeansMaxRestarts                   = "guardiannKMeansMaxRestarts"
	IndexOptionGuardiannSplitMergeConcurrency               = "guardiannSplitMergeConcurrency"
	IndexOptionGuardiannReassignConcurrency                 = "guardiannReassignConcurrency"
	IndexOptionGuardiannCollapseConcurrency                 = "guardiannCollapseConcurrency"
	IndexOptionGuardiannBounceConcurrency                   = "guardiannBounceConcurrency"
	IndexOptionGuardiannConstructionCentroidEfRingSearch    = "guardiannConstructionCentroidEfRingSearch"
	IndexOptionGuardiannConstructionCentroidEfOutwardSearch = "guardiannConstructionCentroidEfOutwardSearch"
)

GuardiANN-only option names beyond those in vector_engine.go.

View Source
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.

View Source
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.

View Source
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.

View Source
const (
	IndexOptionRankNLevels         = "rankNLevels"
	IndexOptionRankHashFunction    = "rankHashFunction"
	IndexOptionRankCountDuplicates = "rankCountDuplicates"
)

Index option keys for RANK indexes. Matches Java's IndexOptions.RANK_*.

View Source
const (
	FunctionNameRank                   = "rank"
	FunctionNameTimeWindowRank         = "time_window_rank"
	FunctionNameTimeWindowRankAndEntry = "time_window_rank_and_entry"
)

Record function name constants matching Java's FunctionNames.

View Source
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
)
View Source
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.

View Source
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
)
View Source
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.

View Source
const (
	DeflaterDefaultCompression = -1
	DeflaterBestCompression    = 9
)

Java's java.util.zip.Deflater levels, which compress/zlib shares.

View Source
const AllTimeLeaderboardType = 0

AllTimeLeaderboardType is the type value for the all-time leaderboard. Matches Java's TimeWindowLeaderboard.ALL_TIME_LEADERBOARD_TYPE.

View Source
const DefaultCipher = "AES/CBC/PKCS5Padding"

DefaultCipher is Java's CipherPool.DEFAULT_CIPHER. Go implements every AES transformation Java's serializer can run (jce_cipher.go).

View Source
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.

View Source
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.

View Source
const DefaultMaterializationLimit = 100_000
View Source
const (
	// DefaultPipelineSize matches FDBRecordStore.DEFAULT_PIPELINE_SIZE in Java.
	DefaultPipelineSize = 10
)

Other constants from Java implementation

View Source
const DefaultTextTokenizerName = "default"

DefaultTextTokenizerName is the name of the default tokenizer.

View Source
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.

View Source
const (
	FunctionNameVersion = "version"
)

Store function name constants matching Java's FunctionNames.

View Source
const GlobalMinVersion = 0

GlobalMinVersion is the absolute minimum tokenizer version. All tokenizers should begin at this version. Matches Java's TextTokenizer.GLOBAL_MIN_VERSION.

View Source
const IndexOptionHNSWEfConstruction = "hnswEfConstruction"

IndexOptionHNSWEfConstruction specifies the search factor used during index construction. Matches Java's IndexOptions.HNSW_EF_CONSTRUCTION.

View Source
const IndexOptionHNSWEfRepair = "hnswEfRepair"

IndexOptionHNSWEfRepair specifies the search factor used during repair operations. Matches Java's IndexOptions.HNSW_EF_REPAIR.

View Source
const IndexOptionHNSWM = "hnswM"

IndexOptionHNSWM specifies the connectivity factor M for the HNSW graph. Matches Java's IndexOptions.HNSW_M.

View Source
const IndexOptionHNSWMMax = "hnswMMax"

IndexOptionHNSWMMax specifies the maximum number of connections for non-zero layers. Matches Java's IndexOptions.HNSW_M_MAX.

View Source
const IndexOptionHNSWMMax0 = "hnswMMax0"

IndexOptionHNSWMMax0 specifies the maximum number of connections for layer 0. Matches Java's IndexOptions.HNSW_M_MAX_0.

View Source
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.

View Source
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.

View Source
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.

View Source
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.

View Source
const IndexOptionHNSWRaBitQNumExBits = "hnswRaBitQNumExBits"

IndexOptionHNSWRaBitQNumExBits specifies the number of extra bits for RaBitQ. Matches Java's IndexOptions.HNSW_RABITQ_NUM_EX_BITS.

View Source
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.

View Source
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.

View Source
const IndexOptionHNSWUseInlining = "hnswUseInlining"

IndexOptionHNSWUseInlining controls whether vector data is inlined into the HNSW node. Matches Java's IndexOptions.HNSW_USE_INLINING.

View Source
const IndexOptionHNSWUseRaBitQ = "hnswUseRaBitQ"

IndexOptionHNSWUseRaBitQ enables RaBitQ quantization for approximate nearest neighbor. Matches Java's IndexOptions.HNSW_USE_RABITQ.

View Source
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.

View Source
const IndexOptionVectorEngine = "vectorEngine"

IndexOptionVectorEngine selects a VECTOR index's engine (Java IndexOptions.VECTOR_ENGINE); absent means HNSW.

View Source
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.

View Source
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.

View Source
const IndexOptionVectorMetric = "hnswMetric"

IndexOptionVectorMetric specifies the distance metric. Matches Java's IndexOptions.HNSW_METRIC.

View Source
const IndexOptionVectorNumDimensions = "hnswNumDimensions"

IndexOptionVectorNumDimensions specifies the number of vector dimensions. Matches Java's IndexOptions.HNSW_NUM_DIMENSIONS.

View Source
const InvalidHeartbeatInfo = "<< Invalid Heartbeat >>"

InvalidHeartbeatInfo is Java's IndexingHeartbeat.INVALID_HEARTBEAT_INFO: a heartbeat whose value does not parse is reported with this info and zero create/heartbeat times, so a caller sees it instead of losing it.

View Source
const PendingWritesQueueVersion = 1
View Source
const SPFreshStalledSealBound = 100

SPFreshStalledSealBound is SimFDB's former retry backstop: under a simulated environment, this many consecutive uncounted retries that each met the same sealed postings fail the call (SPFreshStalledSealError).

View Source
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

View Source
var (
	WriteOnlyIndexesUpdated          = ContextSessionKey[map[string]struct{}]{"writeOnlyIndexesUpdated"}
	WriteOnlyWithQueueIndexesUpdated = ContextSessionKey[map[string]struct{}]{"writeOnlyIndexesUpdated"}
	// ReadableIndexesUpdated holds READABLE and READABLE_UNIQUE_PENDING
	// indexes alike.
	ReadableIndexesUpdated = ContextSessionKey[map[string]struct{}]{"readableIndexesUpdated"}
)

The index-update sets Java 4.14 records per transaction (#4289, FDBRecordStore.updateSecondaryIndexes), for diagnosing conflicts with an indexer: the indexes a record write updated, by the state they were in.

WriteOnlyIndexesUpdated and WriteOnlyWithQueueIndexesUpdated share Java's name "writeOnlyIndexesUpdated" (ContextSessionKey.java:45,51), and keys are equal by name, so in Java both are one set holding the ordinary and the queued write-only indexes. Go keeps the shared name, so it reads the same.

View Source
var (
	CountPendingWritesQueueWrite                 = Event{"pending_writes_queue_write", "Pending writes queue write", KindCount}
	CountPendingWritesQueueClear                 = Event{"pending_writes_queue_clear", "Pending writes queue clear", KindCount}
	CountPendingWritesQueueOverflowDisabledIndex = Event{"pending_writes_queue_overflow_disabled_index", "Index disabled because pending writes queue overflowed", KindCount}
	SizePendingWritesQueueSize                   = Event{"pending_writes_queue_size", "Pending writes queue size", KindSizeDistribution}
)
View Source
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}
	CountSWReinsertAlreadyTracked   = Event{"sw_reinsert_already_tracked", "reinsert of an already-tracked entry, needing no window maintenance", 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.

View Source
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}
	// EventRetryDelay is Java's Events.RETRY_DELAY: the backoff between a runner's attempts and
	// before an online indexer's lessen-work retry (IndexingThrottle.buildCommitRetryAsync).
	EventRetryDelay = Event{"retry_delay", "Retry Delay", KindTimed}
	// EventScanRemoteFetchEntry is Java's Events.SCAN_REMOTE_FETCH_ENTRY, timing
	// each result of a remote-fetch index scan.
	EventScanRemoteFetchEntry = Event{"scan_remote_fetch_entry", "Remote Fetch Index Entry", 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.

View Source
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.
	CountBadIndexEntry         = Event{"bad_index_entry", "Bad Index Entry", KindCount}
	CountRemoteFetch           = Event{"remote_fetch", "Remote Fetch Reads", KindCount}
	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}

	// CountTransactionSizeWarning is Go-only: a transaction crossed
	// ContextConfig.TransactionSizeWarnBytes (Java has no such threshold).
	CountTransactionSizeWarning = Event{"transaction_size_warning", "Transaction Size Warning", KindCount}
)

Standard count events — matching Java's FDBStoreTimer.Counts. The KindSize entries are the ones whose Java constant is declared with isSize()==true.

View Source
var (
	// OrderAscNullsFirst: ascending order, nulls sort first (default tuple behavior).
	OrderAscNullsFirst = tupleordering.AscNullsFirst
	// OrderAscNullsLast: ascending order, nulls sort last (0xFE encoding).
	OrderAscNullsLast = tupleordering.AscNullsLast
	// OrderDescNullsFirst: descending order, nulls sort first.
	OrderDescNullsFirst = tupleordering.DescNullsFirst
	// OrderDescNullsLast: descending order, nulls sort last.
	OrderDescNullsLast = tupleordering.DescNullsLast
)

The four order directions matching Java's TupleOrdering.Direction enum values.

View Source
var EventWaitDeleteStore = Event{"wait_delete_store", "wait for delete store", KindTimed}

EventWaitDeleteStore is FDBStoreTimer.Waits.WAIT_DELETE_STORE, the wait a caller records around a store deletion (Java's relational DROP SCHEMA).

View Source
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 BitmapValueEntrySizeOption

func BitmapValueEntrySizeOption(index *Index) (int64, error)

BitmapValueEntrySizeOption is the entry size Java's BitmapValueIndexMaintainer constructor reads (BitmapValueIndexMaintainer.java:100-105): absent is 10000; present is Integer.parseInt'd, whose refusal is a NumberFormatError; above 250000 is refused with RecordCoreArgumentException "entry size option is too large". The size places every bit (the key's offset and the value's length), so a size read differently from Java's writes bytes Java does not.

Go-only: a size of zero or below is refused here, where the index is used. Java accepts it and fails at the first write with a JDK exception (a division by zero, or a negative array size); Go would panic there. DIVERGENCES.md, "A bitmap index's entry size is read as Java reads it".

func CheckAnyOngoingOnlineIndexBuilds

func CheckAnyOngoingOnlineIndexBuilds(tx fdb.ReadTransaction, storeSubspace subspace.Subspace, index *Index, leaseMs int64, nowMs int64) (bool, error)

CheckAnyOngoingOnlineIndexBuilds reports whether any indexer's heartbeat marks a live session at nowMs, mutual or exclusive: a heartbeat that PARSES and that exclusive session admission would refuse to start against, heartbeatBlocksSession(age, leaseMs) (mutual admission refuses no live peer, IndexingHeartbeat.java:90-93). It judges each indexer id's SURVIVING heartbeat (below), where admission judges every key, so over one key per id "ongoing" is "a new exclusive session would be refused", and over two keys for one id the two can differ.

Every heartbeat KEY is parsed first, as Java's getIndexingHeartbeats does before any time is compared (getUUID(0) sits outside its try, IndexingHeartbeat.java:148): a key whose first tuple element is not a UUID is an IndexingHeartbeatKeyError wherever it sits in the range (a string key sorts before every UUID key, a versionstamp key after it), whatever the other heartbeats say, and a (UUID, x) key is that UUID's heartbeat, as in Java. Admission fails closed on the same keys (heartbeatIndexerID), so a legacy string-keyed heartbeat cannot read "not ongoing" here while every session is refused.

DIVERGENCE (DIVERGENCES.md, "checkAnyOngoingOnlineIndexBuilds"): Java documents the same contract ("a heartbeat that is less than DEFAULT_LEASE_LENGTH_MILLIS old", OnlineIndexer.java:442) but computes heartbeatTime < now + lease over getIndexingHeartbeats (OnlineIndexer.java:459-462), where an unparseable heartbeat carries time 0. Over UUID-keyed heartbeats the engines therefore disagree on exactly three populations, each pinned against the JVM: a stale heartbeat (a crashed session: Java ongoing forever, Go not); an invalid-only heartbeat (Java ongoing, Go not: admission ignores it, IndexingHeartbeat.java:118-123); and a heartbeat dated more than the lease but less than a day ahead (Java not ongoing, Go ongoing: admission refuses a session against it, IndexingHeartbeat.java:107). A heartbeat more than a day ahead is bad data to both, and a non-UUID key is an error in both.

The rule is applied to the SAME population Java's check reads: each indexer id's surviving heartbeat after getIndexingHeartbeats' collapse (collectIndexingHeartbeats), not every key. When a (U) key and a (U, x) key both exist, the (U, x) value is the one both engines judge, so the three populations above are still the only differences between the engines: a live (U) beside a (U, x) a day ahead is not ongoing in either, and a live (U) beside an UNPARSEABLE (U, x) is the invalid-only population (Java ongoing, Go not), each pinned against the JVM. In both cases admission, which reads every key, refuses a new exclusive session over the live (U): that is where "ongoing" and "would be refused" part, in Java as in Go.

func CheckAnyOngoingOnlineIndexBuildsForStore

func CheckAnyOngoingOnlineIndexBuildsForStore(store *FDBRecordStore, index *Index) (bool, error)

CheckAnyOngoingOnlineIndexBuildsForStore is Java's static OnlineIndexer.checkAnyOngoingOnlineIndexBuildsAsync(recordStore, index): the check at Java's default lease, in the store's transaction and clock.

func CheckValidProtoBufCompliantName

func CheckValidProtoBufCompliantName(name string) error

CheckValidProtoBufCompliantName validates that name is a legal protobuf identifier. See protoname.CheckValidProtoBufCompliantName.

func CleanupAllHeartbeats

func CleanupAllHeartbeats(tx fdb.WritableTransaction, storeSubspace subspace.Subspace, index *Index)

CleanupAllHeartbeats removes ALL heartbeats for an index. Used during index rebuild or full clear operations.

func ClearIndexingHeartbeats

func ClearIndexingHeartbeats(tx fdb.WritableTransaction, storeSubspace subspace.Subspace, index *Index, minAgeMs int64, maxIteration int, nowMs int64) (int, error)

ClearIndexingHeartbeats clears the heartbeats of an index whose last beat is at least minAgeMs old at nowMs, and every heartbeat whose value does not parse. It examines at most maxIteration heartbeats when maxIteration > 0 and returns how many it cleared. Like Java it never parses the KEY, so it also clears legacy string-keyed heartbeats once their values are old or invalid. Matches Java's IndexingHeartbeat.clearIndexingHeartbeats (IndexingHeartbeat.java:165-195).

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

func DecodeOnceIfReversible(stored string) string

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 header-aware FDBRecordStore.deleteStoreAsync.

func Filter

func Filter[T any](seq iter.Seq[T], predicate func(T) bool) iter.Seq[T]

Filter returns a filtered sequence

func Filter2

func Filter2[T any](seq iter.Seq2[T, error], predicate func(T) bool) iter.Seq2[T, error]

Filter2 filters a Seq2 sequence

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 ForEach

func ForEach[T any](ctx context.Context, cursor RecordCursor[T], fn func(T) error) error

ForEach applies a function to each record in the cursor

func GeneratedMessageType

func GeneratedMessageType(desc protoreflect.MessageDescriptor) protoreflect.MessageType

GeneratedMessageType is the compiled Go type whose descriptor is desc, nil when there is none: a registered type that only shares desc's full name is another message. Build decodes a record type as it when there is one, and as dynamicpb over desc otherwise.

func GetCount

func GetCount[T any](ctx context.Context, cursor RecordCursor[T]) (int, error)

GetCount returns the number of elements in a cursor by consuming it. Matches Java's RecordCursor.getCount().

func GetInSession

func GetInSession[T any](rc *FDBRecordContext, key ContextSessionKey[T]) T

GetInSession is Java's getInSession(ContextSessionKey): the value stored under key in rc's session, or T's zero value (Java's null) when absent. A set is returned as a copy.

func GetIndexingHeartbeats

func GetIndexingHeartbeats(tx fdb.ReadTransaction, storeSubspace subspace.Subspace, index *Index, maxCount int) (map[uuid.UUID]*gen.IndexBuildHeartbeat, error)

GetIndexingHeartbeats reads an index's session heartbeats keyed by indexer id. maxCount > 0 reads at most that many (Java's safety valve); 0 or less reads all. A key that is not a UUID heartbeat key is an IndexingHeartbeatKeyError, as in admission: Java's getUUID on such a key throws too. Matches Java's IndexingHeartbeat.getIndexingHeartbeats (IndexingHeartbeat.java:135-163).

func HNSWEfSearch

func HNSWEfSearch(option *int, k int) int

HNSWEfSearch is HnswVectorIndexEngine.efSearch: the scan's option as given (even below k, or 0), else derived from the scan limit.

func IndexMaintainerAs

func IndexMaintainerAs[T any](m IndexMaintainer) (T, bool)

IndexMaintainerAs peels decorators off a maintainer until one of them satisfies T.

Every access method NOT declared on IndexMaintainer is reached by asking whether the maintainer satisfies some capability — a concrete type for the vector search entry points, a byDistanceScanner or orderedStreamScanner for the generic index scan. A decorator satisfies none of them, so wrapping an index silently REMOVES capabilities its delegate has, and the caller reports the index as one that never had them ("does not support BY_DISTANCE scan").

Asking through this helper makes the decorator's capability set exactly its delegate's, automatically. The alternative — forwarding each capability from the decorator by hand — breaks silently again the next time a capability interface is added, and the breakage looks like a missing feature rather than like a wrapper.

Java has no equivalent problem: its decorator extends the same abstract IndexMaintainer and overrides scan(), so nothing downstream ever asks what the concrete class is.

func IsLongArithmeticFunction

func IsLongArithmeticFunction(name string) bool

IsLongArithmeticFunction reports whether name is registered as one of the target's long-arithmetic key functions, not an application's function of the same name.

func IsMetaDataException

func IsMetaDataException(err error) bool

IsMetaDataException reports whether err's outermost Java exception is a MetaDataException, as Java's `re instanceof MetaDataException` tests the exception thrown and not its causes (ExceptionUtil.recordCoreToRelationalException). The outermost Java exception is the first error of this package met walking err's wrappers (fmt's %w, and the first of several), each of which is a Java exception class; a MetaDataError that is only the cause of another is not.

func IsPermutedMinIndex

func IsPermutedMinIndex(idx *Index) bool

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 JavaParseDouble

func JavaParseDouble(s string) (float64, error)

JavaParseDouble is Java's Double.parseDouble (javanum.ParseDouble), its NumberFormatException reported as this package's NumberFormatError.

func JavaParseInt

func JavaParseInt(s string) (int32, error)

JavaParseInt is Java's Integer.parseInt(s) (radix 10): an optional leading '+' or '-', then one or more decimal digits, within int32. A digit is what Character.digit(char, 10) accepts, any Unicode decimal digit (general category Nd) in the Basic Multilingual Plane: Java walks UTF-16 chars, so a supplementary digit is two surrogates, neither of them a digit.

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 Limit

func Limit[T any](seq iter.Seq[T], n int) iter.Seq[T]

Limit returns at most n values from a sequence

func ListCursorContinuation

func ListCursorContinuation(pos int) []byte

func LiteralToProtoValue

func LiteralToProtoValue(v any) (*gen.Value, error)

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 Map

func Map[T, R any](seq iter.Seq[T], fn func(T) R) iter.Seq[R]

Map transforms values in a sequence

func OutermostJavaError

func OutermostJavaError(err error) error

OutermostJavaError is the first error of this package (or of protoname, which it aliases) on err's chain of wrappers, following the first of several; nil when there is none.

func PendingWriteCommitCheckPrefix

func PendingWriteCommitCheckPrefix(ss subspace.Subspace) string

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 PermutedSizeOption

func PermutedSizeOption(index *Index) (int, error)

PermutedSizeOption is Java's PermutedMinMaxIndexMaintainer.getPermutedSize (PermutedMinMaxIndexMaintainer.java:107-113): an absent option is refused ("permuted size not specified"), and a present one is read by Integer.parseInt, whose refusal is a NumberFormatError. The range check against the grouping is the index validator's (validatePermutedIndex). Every reader of the option goes through it: the maintainer, Build's validator, the executor's permuted scan and the chaos model.

func PutInSession

func PutInSession[T any](rc *FDBRecordContext, key ContextSessionKey[T], value T)

PutInSession is Java's putInSession(ContextSessionKey, value): it replaces any value under key.

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 ReadRunner,
	stats StatisticsSubspace,
	storeSubspace subspace.Subspace,
	tags ...string,
) (StoreStatistics, StatisticsReadRefusal, int64, error)

ReadStatisticsAtWithRefusal is ReadStatistics plus the cluster version the read was taken at, from the SAME transaction, and why an unusable set was refused.

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 RecordCoreMessages

func RecordCoreMessages(err error) []string

RecordCoreMessages is the message of every RecordCoreError in err's tree, in errors.As order (depth first, each error before what it wraps), each once: the Java RecordCoreExceptions an error is, and wraps, as their messages. A test asserts with it which exceptions a refusal carries, where errors.As finds only the first.

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 RegisterFunction

func RegisterFunction(name string, evaluator FunctionEvaluator)

RegisterFunction registers a key function of one column, any number of arguments and a plain null (see FunctionSpec).

func RegisterFunctionSpec

func RegisterFunctionSpec(name string, spec FunctionSpec)

RegisterFunctionSpec registers a key function in the global registry. Call it before building metadata that uses the function.

func RegisterIndexMaintainerFactory

func RegisterIndexMaintainerFactory(f IndexMaintainerFactory)

RegisterIndexMaintainerFactory makes f the factory for each of its index types. It is called from the implementing package's init function and panics on a type registered twice, as database/sql.Register does: two implementations of one wire format in a binary is a build error.

func RemoveCommonEntries

func RemoveCommonEntries(idx *Index, old, new []EvaluatedIndexEntry) ([]EvaluatedIndexEntry, []EvaluatedIndexEntry, error)

RemoveCommonEntries filters out entries that are identical in both old and new. This avoids unnecessary FDB mutations when a record update doesn't change the indexed value. Matches Java's standardIndexMaintainer.commonKeys optimization.

func ReverseLookup

func ReverseLookup(rctx *FDBRecordContext, r LocatableResolver, value int64) (string, error)

ReverseLookup is LocatableResolver.reverseLookup: the name a value maps to, or NoSuchElementException "reverse lookup of <value>".

func SafeDecoderOver

func SafeDecoderOver(decoded, verbatim []string) func(string) string

SafeDecoderOver returns one decoding policy for a whole rendered output. See protoname.SafeDecoderOver.

func Seq2

func Seq2[T any](cursor RecordCursor[T], ctx context.Context) iter.Seq2[T, error]

Seq2 returns an iterator sequence over (value, error) pairs.

func SupportsRemoteFetch

func SupportsRemoteFetch(apiVersion int) bool

SupportsRemoteFetch reports whether apiVersion is at least Java's APIVersion.API_VERSION_7_1, the first with mapped reads.

func ToProtoBufCompliantName

func ToProtoBufCompliantName(name string) (string, error)

ToProtoBufCompliantName escapes a user identifier into a protobuf-compliant name. See protoname.ToProtoBufCompliantName.

func ToUserIdentifier

func ToUserIdentifier(protoIdentifier string) string

ToUserIdentifier reverses ToProtoBufCompliantName. See protoname.ToUserIdentifier.

func UnmarshalAsJava

func UnmarshalAsJava(b []byte, m proto.Message) error

UnmarshalAsJava decodes b into m, a message of a generated type, as protobuf-java parses it as the root of a parse (javaRootRule): meta-data, a catalog row's template, a pending write. Store headers, index-build stamps, heartbeats and continuations, all of generated types with a vtproto decoder, are read by UnmarshalVTAsJava.

func UnmarshalPendingQueueAny

func UnmarshalPendingQueueAny(data *anypb.Any, message proto.Message) error

func UnmarshalRecordAsJava

func UnmarshalRecordAsJava(b []byte, m proto.Message, partial bool) error

UnmarshalRecordAsJava decodes b into m, a record or a value of a record's field (a dynamic message, as a DynamicMessage), as protobuf-java parses a stored record: with the empty extension registry, a map entry kept, and protobuf-java's limit one level below a root. A partial decode skips the required-field check.

func UnmarshalVTAsJava

func UnmarshalVTAsJava(m interface {
	proto.Message
	UnmarshalVT([]byte) error
}, b []byte,
) error

UnmarshalVTAsJava is UnmarshalAsJava for the generated protos a store reads as the root of a parse with no extension registry (headers, stamps, heartbeats, continuations), through the type's vtproto decoder when that reads the bytes as Java does: vtproto keeps an extension as an unknown field, as Java's parse without a registry does, but has no recursion limit, so a type whose messages nest without bound, or deeper than protobuf-java's limit, is decoded by protobuf-go under the limit instead (vtBounded).

func UserDefinedFunctionName

func UserDefinedFunctionName(f *gen.PUserDefinedFunction) string

UserDefinedFunctionName is a stored SQL function's name.

func ValidateChangedIndexOptions

func ValidateChangedIndexOptions(oldIdx, newIdx *Index, changed map[string]bool) error

ValidateChangedIndexOptions validates only the supplied option names, without recomputing differences. Type-specific validators may remove handled names from the caller's mutable set before base validation. A nil or empty set is valid. Matches Java's IndexValidator.validateChangedOptions(Index, Set).

func ValidateEvolution

func ValidateEvolution(oldMetaData, newMetaData *RecordMetaData) error

ValidateEvolution is a convenience function using the default (strictest) validator.

func ValidateTags

func ValidateTags(tags []string) ([]string, error)

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 ValueFromProto

func ValueFromProto(p *gen.Value) (any, error)

ValueFromProto deserializes a Value proto to a Go value, as Java's LiteralKeyExpression.fromProtoValue does (protovalue.FromProto): the one field set, nil when none is, and a RecordCoreError "More than one value encoded in value" when several are.

func ValueToProto

func ValueToProto(v any) (*gen.Value, error)

ValueToProto serializes a Go value to a Value proto. Matches Java's LiteralKeyExpression.toProtoValue().

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. `fdb rl meta get --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

type AggregateFunctionNotSupportedError struct {
	Function string
	Operand  string
}

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 (*AggregateFunctionNotSupportedError) JavaRecordCoreException

func (*AggregateFunctionNotSupportedError) JavaRecordCoreException()

type AttemptCall

type AttemptCall struct {
	Route AttemptRoute
	// Owner is a stable label for the caller, such as "run" or "runner".
	Owner string
	// Execution counts every execution of this call, uncounted retries included.
	Execution int
	// Attempt is the number of counted attempts made before this execution,
	// the number MaxAttempts bounds; an uncounted retry repeats it.
	Attempt int
	// CallID is unique per attempt-loop call.
	CallID uint64
}

AttemptCall identifies one execution of an attempt-loop call to a transactor. A transactor that implements AttemptTransactor receives it.

type AttemptObserver

type AttemptObserver func(call AttemptCall, err error)

AttemptObserver, when installed on a database, is told the outcome of every attempt-loop execution, on the loop's goroutine, as the execution ends.

type AttemptRoute

type AttemptRoute int

AttemptRoute says how an attempt reaches the backend.

const (
	// RouteAttempt is one transactor call per attempt, with the backend's own
	// retry limit set to 0, so the loop counts every attempt.
	RouteAttempt AttemptRoute = iota
	// RouteClientLoop is the transactor's own unbounded retry loop
	// (runClientLoop), kept for SPFresh's background lifecycles.
	RouteClientLoop
	// RouteOwnTransaction is an owner that opens its transaction itself
	// (FDBDatabaseRunner.RunWithRetry); its attempts reach no transactor.
	RouteOwnTransaction
)

type AttemptTransactor

type AttemptTransactor interface {
	TransactAttempt(ctx context.Context, call AttemptCall, fn func(fdb.WritableTransaction) (any, error)) (any, error)
	ReadTransactAttempt(ctx context.Context, call AttemptCall, fn func(fdb.ReadTransaction) (any, error)) (any, error)
}

AttemptTransactor is a transactor that wants each attempt's identity. The database hands it every attempt of Run and its variants; a transactor that does not implement it is called through its TransactCtx (or Transact) per attempt, and sees every attempt but not the call's identity.

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

type BunchedEntry[K any, V any] struct {
	Key   K
	Value V
}

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

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

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

type BunchedSerializationError struct {
	Message string
	Data    []byte
}

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 ByDistanceScanner

type ByDistanceScanner interface {
	ScanByDistance(TupleRange, []byte, ScanProperties) RecordCursor[*IndexEntry]
}

ByDistanceScanner is the BY_DISTANCE access-method contract every vector index maintainer implements (RFC-094 §10): Low = (serialized query vector [, prefix...]), High = (k [, tuning...]); entries ascend by distance. Compile-time assertions catch signature drift at build time.

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

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 ClassCastError

type ClassCastError struct{ Message string }

ClassCastError corresponds to Java's ClassCastException, e.g. a vector index reading a value column that is not bytes (Tuple.getBytes).

func (*ClassCastError) Error

func (e *ClassCastError) Error() string

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 uses ScanLimiterState.Elapsed, so simulations use their own clock.
	TimeLimit time.Duration
	// ScannedBytesLimit bounds how many bytes ONE scan transaction reads before
	// it stops and hands back a continuation. Zero means
	// DefaultCollectScannedBytesLimit.
	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

type ComparisonKeyFunc[T any] func(T) (tuple.Tuple, error)

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 ContextSessionKey

type ContextSessionKey[T any] struct {
	// contains filtered or unexported fields
}

ContextSessionKey is Java's ContextSessionKey: a typed key for a well-known value in an FDBRecordContext's session. Keys are equal by name, as Java's equals is, and never equal a plain string session key.

func (ContextSessionKey[T]) Name

func (k ContextSessionKey[T]) Name() string

Name is the key's name.

type ContinuationEncodeError

type ContinuationEncodeError struct {
	Message string
}

ContinuationEncodeError reports a value whose encoder cannot supply a resumable continuation. Java requires a non-null ChainedCursor encoder and RecordCursorResult.withNextValue throws RecordCoreException if its encoding represents the end. Go reports these failures as errors rather than panics.

func (*ContinuationEncodeError) Error

func (e *ContinuationEncodeError) Error() string

func (*ContinuationEncodeError) JavaRecordCoreException

func (*ContinuationEncodeError) JavaRecordCoreException()

type ContinuationParseError

type ContinuationParseError struct {
	Message  string
	RawBytes []byte
	Cause    error
}

ContinuationParseError is returned when continuation bytes fail to parse as their wrapper proto or cursor-specific encoding. For proto wrappers, it matches Java's RecordCoreException("error parsing continuation") with the "raw_bytes" log info key (e.g. OrElseCursor's constructor, RecordCursor.fromList). Chained's bool-returning decoder cannot supply an underlying error, so Cause describes its rejection instead; Java propagates the decoder's exception. A corrupt continuation must surface, never silently become 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) JavaRecordCoreException

func (*ContinuationParseError) JavaRecordCoreException()

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) Count

func (c *Counter) Count() int64

Count returns the number of observations recorded.

func (*Counter) CumulativeValue

func (c *Counter) CumulativeValue() int64

CumulativeValue returns the sum of all recorded values.

func (*Counter) Event

func (c *Counter) Event() Event

Event returns the event this counter records.

func (*Counter) Increment

func (c *Counter) Increment(amount int64)

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).

func (*Counter) Record

func (c *Counter) Record(value int64)

Record records a single observation with the given value: one occurrence, plus value added to the cumulative total. Java's Counter.record (StoreTimer.java:473-477). For timed events, value is nanoseconds.

func (*Counter) Reset

func (c *Counter) Reset()

Reset zeroes the counter.

type CounterSnapshot

type CounterSnapshot struct {
	Event           Event
	Count           int64
	CumulativeValue int64
}

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 large batches (FDB SERIAL, not one record at a time)
	StreamingModeSerial
	// StreamingModeWantAll fetches as much as possible
	StreamingModeWantAll
	// StreamingModeIterator is the default iterator mode
	StreamingModeIterator
)

func (CursorStreamingMode) ToFDB

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:

  1. Segment text into words using UAX #29 word boundaries (Java's BreakIterator.getWordInstance(Locale.ROOT) differs; docs/compatibility.md)
  2. NFKD normalize each segment
  3. Filter segments without a letter or digit in the Basic Multilingual Plane
  4. 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

type DeferredMaintenanceStep

type DeferredMaintenanceStep int

DeferredMaintenanceStep identifies the operation whose budget needs reducing after a failed merge attempt, matching IndexDeferredMaintenanceControl.LastStep.

const (
	DeferredMaintenanceNone DeferredMaintenanceStep = iota
	DeferredMaintenanceRepartition
	DeferredMaintenanceMerge
)

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 DuplicateIndexOptionError

type DuplicateIndexOptionError struct {
	Key string
	// First and Second are the values in stored order.
	First, Second string
}

DuplicateIndexOptionError is returned when stored index metadata lists one option key twice. The Java counterpart is the IllegalArgumentException Guava's ImmutableMap.Builder.build throws from Index.buildOptions (Index.java:253-266); Error reproduces its message, which names the later entry first.

func (*DuplicateIndexOptionError) Error

func (e *DuplicateIndexOptionError) Error() string

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

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

	// 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 EvaluatedIndexEntry

type EvaluatedIndexEntry struct {
	// contains filtered or unexported fields
}

EvaluatedIndexEntry represents a single index entry (indexed values + record primary key).

func NewEvaluatedIndexEntry

func NewEvaluatedIndexEntry(key, value, primaryKey tuple.Tuple) EvaluatedIndexEntry

NewEvaluatedIndexEntry is the entry an index key expression evaluates to for one record.

func (EvaluatedIndexEntry) Key

Key is the entry's index key, without the primary key.

func (EvaluatedIndexEntry) PrimaryKey

func (e EvaluatedIndexEntry) PrimaryKey() tuple.Tuple

PrimaryKey is the record's primary key.

func (EvaluatedIndexEntry) Value

func (e EvaluatedIndexEntry) Value() tuple.Tuple

Value is the entry's value tuple (non-nil for a covering index).

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 property copies, 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) ClearSkipAndAdjustLimit

func (e ExecuteProperties) ClearSkipAndAdjustLimit() ExecuteProperties

ClearSkipAndAdjustLimit removes a positive skip and expands a finite child budget to include the skipped rows, like Java's clearSkipAndAdjustLimit. Nonpositive skips leave properties unchanged. Unlike a semantic offset, a read budget may saturate: hitting it produces a resumable page boundary.

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:

  1. 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.
  2. 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, closeHookCursor's close-time hook), 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 FDBClientKnob

type FDBClientKnob string

FDBClientKnob is Java's FDBClientKnob (#4488): a FoundationDB client knob the factory names and types. Its knob name is the lower-cased constant name.

const (
	KnobPacketLimit                              FDBClientKnob = "packet_limit"
	KnobPacketWarning                            FDBClientKnob = "packet_warning"
	KnobTLSClientHandshakeThreads                FDBClientKnob = "tls_client_handshake_threads"
	KnobDisableMainthreadTLSHandshake            FDBClientKnob = "disable_mainthread_tls_handshake"
	KnobTLSClientConnectionThrottleAttempts      FDBClientKnob = "tls_client_connection_throttle_attempts"
	KnobTLSClientConnectionThrottleTimeout       FDBClientKnob = "tls_client_connection_throttle_timeout"
	KnobMaxCommitProxyConnections                FDBClientKnob = "max_commit_proxy_connections"
	KnobMaxGRVProxyConnections                   FDBClientKnob = "max_grv_proxy_connections"
	KnobLocationCacheFailedEndpointRetryInterval FDBClientKnob = "location_cache_failed_endpoint_retry_interval"
	KnobLogConnectionAttemptsEnabled             FDBClientKnob = "log_connection_attempts_enabled"
	KnobConnectionLogDirectory                   FDBClientKnob = "connection_log_directory"
	KnobMaxReconnectionTime                      FDBClientKnob = "max_reconnection_time"
	KnobReconnectionTimeGrowthRate               FDBClientKnob = "reconnection_time_growth_rate"
	KnobReconnectionResetTime                    FDBClientKnob = "reconnection_reset_time"
	KnobLocationCachePeerEvictorEnabled          FDBClientKnob = "location_cache_peer_evictor_enabled"
	KnobLocationCachePeerEvictorDelay            FDBClientKnob = "location_cache_peer_evictor_delay"
	KnobLocationCachePeerEvictorFailedThreshold  FDBClientKnob = "location_cache_peer_evictor_failed_threshold"
	KnobLocationCachePeerEvictorScanChunk        FDBClientKnob = "location_cache_peer_evictor_scan_chunk"
	KnobShrinkProxyListClearCacheBelowThreshold  FDBClientKnob = "shrink_proxy_list_clear_cache_below_threshold"
)

The typed client knobs, FDBClientKnob.java:88-211.

func FDBClientKnobFromName

func FDBClientKnobFromName(name string) (FDBClientKnob, bool)

FDBClientKnobFromName is Java's fromKnobName: the typed knob of that name, or false.

func (FDBClientKnob) KnobName

func (k FDBClientKnob) KnobName() string

KnobName is the knob's name as the client knows it.

func (FDBClientKnob) ValueType

func (k FDBClientKnob) ValueType() KnobValueType

ValueType is the type the knob's value must parse as.

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) InitialDelay

func (d *FDBDatabase) InitialDelay() time.Duration

InitialDelay returns the first retry delay bound (default 10 ms).

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) MaxAttempts

func (d *FDBDatabase) MaxAttempts() int

MaxAttempts returns the attempt bound of Run and its variants (default 10).

func (*FDBDatabase) MaxDelay

func (d *FDBDatabase) MaxDelay() time.Duration

MaxDelay returns the retry delay cap (default 1 s).

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; one with a context (SQL's explicit BeginTx→COMMIT path) uses NewRecordContextIn.

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) NewRecordContextIn

func (d *FDBDatabase) NewRecordContextIn(ctx context.Context, tx fdb.WritableTransaction) *FDBRecordContext

NewRecordContextIn is NewRecordContext with ctx as the context's Context(), which bounds the reads and child transactions that take it from there.

func (*FDBDatabase) Run

func (d *FDBDatabase) Run(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, error)

Run executes fn in a transaction and commits it, retrying as Java's FDBDatabaseRunner does (FDBDatabaseRunnerImpl.RunRetriable): at most MaxAttempts attempts (default 10), each a fresh transaction, retried while some cause of the error is retriable, with Java's ExponentialDelay between attempts (attemptLoop). Before committing it runs the commit checks and flushes queued versionstamp mutations, as FDBRecordContext.commitAsync does; the post-commit hooks run once, after the attempt that committed.

func (*FDBDatabase) RunClientLoop

func (d *FDBDatabase) RunClientLoop(ctx context.Context, fn func(rtx *FDBRecordContext) (any, error)) (any, error)

RunClientLoop runs fn through the transactor's own retry loop, which is unbounded on the pure-Go client and libfdb_c and capped at 100 retries on SimFDB. Only SPFresh's background lifecycles use it (spfreshRun): RFC-094 keeps them on the client loop, and nothing else may.

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) RunWithMaxAttempts

func (d *FDBDatabase) RunWithMaxAttempts(ctx context.Context, maxAttempts int, fn func(rtx *FDBRecordContext) (any, error)) (any, error)

RunWithMaxAttempts is Run with its own attempt bound in place of the database's, as an FDBDatabaseRunner with setMaxAttempts runs. One attempt is how the relational layer runs a DDL statement: a conflict surfaces instead of re-executing the statement.

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) SetAttemptObserver

func (d *FDBDatabase) SetAttemptObserver(o AttemptObserver)

SetAttemptObserver installs an observer of every attempt-loop execution.

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) SetMaxAttempts

func (d *FDBDatabase) SetMaxAttempts(n int) error

SetMaxAttempts sets how many attempts Run and its variants make, Java's FDBDatabaseFactory.setMaxAttempts. Values below 1 are rejected as Java's are.

func (*FDBDatabase) SetRetryDelays

func (d *FDBDatabase) SetRetryDelays(initial, maxDelay time.Duration) error

SetRetryDelays sets the initial and maximum delay between attempts, Java's FDBDatabaseFactory.setInitialDelayMillis / setMaxDelayMillis.

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) ClearKnobs

func (f *FDBDatabaseFactory) ClearKnobs() error

ClearKnobs is Java's clearKnobs: refused once the client has started.

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).

func (*FDBDatabaseFactory) Knobs

func (f *FDBDatabaseFactory) Knobs() map[string]string

Knobs is Java's getKnobs: the knobs set so far, by name.

func (*FDBDatabaseFactory) SetKnob

func (f *FDBDatabaseFactory) SetKnob(knob FDBClientKnob, value string) error

SetKnob is Java's setKnob(FDBClientKnob, String): it checks value against the knob's type, records it, and sets it on the client at once when the client has started. A recorded knob is set before the client opens its first database. The pure-Go client honors no knob, so there a recorded knob fails the open (fdbclient.UnsupportedKnobError) rather than being ignored.

func (*FDBDatabaseFactory) SetKnobByName

func (f *FDBDatabaseFactory) SetKnobByName(name, value string) error

SetKnobByName is Java's setKnob(String, String): a typed knob's name is checked as SetKnob does; any other name only has to be nonblank and free of '=', and is passed to the client as given.

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 FDBIndexedRawRecord

type FDBIndexedRawRecord struct {
	IndexEntry *IndexEntry
	RawRecord  fdb.MappedKeyValue
}

FDBIndexedRawRecord is an index entry with the record rows the storage server returned for it. Matches Java's FDBIndexedRawRecord.

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):

  1. the new proto must build into a RecordMetaData;
  2. 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;
  3. 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
}

FDBRecordContext represents a transactional context for record operations. It wraps an FDB transaction and provides additional record layer functionality. Goroutine-safe: all mutable fields are protected by atomics, mutexes, or the lockRegistry. Multiple goroutines may safely operate on the same context within a single FDB transaction (matching Java's CompletableFuture model). Matches Java's FDBRecordContext.

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) APIVersion

func (c *FDBRecordContext) APIVersion() int

APIVersion is the FDB API version this context's transactions run at, or 0 if none was selected. Matches Java's FDBRecordContext.getAPIVersion.

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) []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. Returns the previous value for this key, or nil if absent, matching 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 returns TransactionSizeExceededError past the error threshold; past the warning threshold it logs and counts CountTransactionSizeWarning once per transaction.

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) ClearRange

func (rc *FDBRecordContext) ClearRange(keyRange fdb.ExactRange)

ClearRange clears transactional data and pending version state together, so flushing version mutations at commit cannot restore keys inside the range. Matches Java's FDBRecordContext.clear(Range).

func (*FDBRecordContext) Commit

func (rc *FDBRecordContext) Commit() error

Commit runs pre-commit checks, flushes pending version mutations, commits the transaction, and runs post-commit callbacks. All explicit commit APIs share this lifecycle, matching Java's FDBRecordContext.commitAsync().

func (*FDBRecordContext) CommitWithHooks

func (rc *FDBRecordContext) CommitWithHooks() error

CommitWithHooks is an alias for Commit; checks and hooks always run.

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) Configure

func (rc *FDBRecordContext) Configure(f TransactionConfigurer) error

Configure applies f and keeps it for child transactions, which Java's newRunner opens with the parent context's config.

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) GetDatabase

func (rc *FDBRecordContext) GetDatabase() *FDBDatabase

GetDatabase is the database that opened this context, Java's FDBRecordContext.getDatabase; nil for a context NewFDBRecordContext built over an external transaction.

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) GetOrCreateCommitCheck

func (rc *FDBRecordContext) GetOrCreateCommitCheck(name string, ifNotExists func(string) CommitCheckFunc) CommitCheckFunc

GetOrCreateCommitCheck returns the named check, invoking ifNotExists only when absent. The supplier runs under the registration lock and must not call back into context hook registration. The supplied check runs outside that lock. Matches Java's FDBRecordContext.getOrCreateCommitCheck().

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) HasVersionMutationsInRange

func (rc *FDBRecordContext) HasVersionMutationsInRange(begin, end fdb.Key) bool

HasVersionMutationsInRange checks surviving buffered mutations in [begin, end). It shares the registry and mutex used by context-aware clears.

func (*FDBRecordContext) PendingWriteQueueOptions

func (rc *FDBRecordContext) PendingWriteQueueOptions() PendingWriteQueueOptions

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) SetPendingWriteQueueOptions

func (rc *FDBRecordContext) SetPendingWriteQueueOptions(options PendingWriteQueueOptions)

SetPendingWriteQueueOptions replaces both context-scoped queue properties. Without an explicit value the Java defaults are 100000 entries and disable on overflow. The value is copied so concurrent callers cannot mutate it.

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)

AcquireReadLock takes the context's shared lock for key.

func (*FDBRecordStore) AcquireWriteLock

func (store *FDBRecordStore) AcquireWriteLock(key string)

AcquireWriteLock takes the context's exclusive lock for key.

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 with this store's configuration, in the same context. Matches Java's FDBRecordStore.asBuilder() (new Builder(this), Builder.copyFrom(FDBRecordStore)).

func (*FDBRecordStore) BuildSingleRecord

func (store *FDBRecordStore) BuildSingleRecord(raw *FDBIndexedRawRecord) (*FDBIndexedRecord, error)

BuildSingleRecord rebuilds the record of a remote-fetch result. It returns nil when the server found no record rows: the orphan behavior belongs to the scan. Matches Java's FDBRecordStore.buildSingleRecord.

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) ClearAndMarkIndexWriteOnlyWithQueue

func (store *FDBRecordStore) ClearAndMarkIndexWriteOnlyWithQueue(indexName string) (bool, error)

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; the configuration copied is AsBuilder's.

func (*FDBRecordStore) CountRecords

func (store *FDBRecordStore) CountRecords(
	ctx context.Context,
	low, high tuple.Tuple,
	lowEndpoint, highEndpoint EndpointType,
	continuation []byte,
	scanProperties ScanProperties,
) (int, error)

CountRecords is Java's FDBRecordStore.countRecords: skip moves the range's selector and row and time limits are cleared. An unsplit store counts its key-values, inline versions included, without charging the scan limits; a split store counts the unsplitter's records, which charge them. A count cut short by a scan limit also returns ScanLimitReachedError (RFC-106a).

func (*FDBRecordStore) CreateRemoteFetchMapper

func (store *FDBRecordStore) CreateRemoteFetchMapper(index *Index, commonPrimaryKeyLength int) (tuple.Tuple, error)

CreateRemoteFetchMapper returns the mapper this store's index sends with a remote-fetch scan.

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. Like Java's FDBRecordStore.getAllIndexStates (addStoreStateReadConflict, FDBRecordStore.java:4205-4213, 4610-4617), it adds ONE read-conflict range over the whole index-state subspace: any state change in the store conflicts with the caller's transaction.

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) GetCommonPrimaryKeyLength

func (store *FDBRecordStore) GetCommonPrimaryKeyLength(index *Index) int

GetCommonPrimaryKeyLength is the primary-key length shared by every record type of the index, or -1. Matches Java's FDBRecordStoreBase.getCommonPrimaryKeyLength.

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) GetIndexDeferredMaintenanceControl

func (store *FDBRecordStore) GetIndexDeferredMaintenanceControl() *IndexDeferredMaintenanceControl

GetIndexDeferredMaintenanceControl returns the control owned by this handle, matching Java's per-store transaction lifetime.

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) GetIndexMaintenanceFilter

func (store *FDBRecordStore) GetIndexMaintenanceFilter() IndexMaintenanceFilter

GetIndexMaintenanceFilter is Java's FDBRecordStore.getIndexMaintenanceFilter.

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) GetIndexesToBuild

func (store *FDBRecordStore) GetIndexesToBuild() ([]*Index, error)

GetIndexesToBuild returns eligible indexes that are not exactly READABLE. State reads are serializable, including decisions to omit readable indexes. Matches Java's FDBRecordStore.getIndexesToBuild().

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) GetPrimaryKeyBoundaries

func (store *FDBRecordStore) GetPrimaryKeyBoundaries(r TupleRange) ([]tuple.Tuple, error)

GetPrimaryKeyBoundaries returns, for each shard boundary in r, the primary key of the first record at or after it, sorted and without duplicates. Java's FDBRecordStore.getPrimaryKeyBoundaries.

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 is Java's getSnapshotRecordCountForRecordType (FDBRecordStoreBase.java:1856-1860): the filtered method with Java's IndexQueryabilityFilter.TRUE. A record type's count comes from a COUNT index, never from the record count key; with no index that answers it is Java's RecordCoreException "Require a COUNT index on X". A record count key grouped by record type is read with GetSnapshotRecordCount(tuple.Tuple{typeKey}), as Java's getSnapshotRecordCount reads it.

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 for either write-only state.

func (*FDBRecordStore) IsIndexWriteOnlyNoQueue

func (store *FDBRecordStore) IsIndexWriteOnlyNoQueue(indexName string) bool

func (*FDBRecordStore) IsIndexWriteOnlyWithQueue

func (store *FDBRecordStore) IsIndexWriteOnlyWithQueue(indexName string) bool

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) LoadRecordAsync

func (store *FDBRecordStore) LoadRecordAsync(primaryKey tuple.Tuple, scanState *ScanLimiterState) PendingRead[*FDBStoredRecord[proto.Message]]

LoadRecordAsync sends the record's reads now, like Java's loadRecordAsync; Get finishes materialization. A non-nil scanState is charged when the raw read completes, even if its issued load is never consumed.

func (*FDBRecordStore) LoadRecordVersion

func (store *FDBRecordStore) LoadRecordVersion(primaryKey tuple.Tuple, snapshot bool) (*FDBRecordVersion, error)

LoadRecordVersion returns the stored version, or nil when absent. Modern formats read explicit versions even without automatic versioning; legacy formats return nil when metadata disables it.

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) MarkIndexWriteOnlyWithQueue

func (store *FDBRecordStore) MarkIndexWriteOnlyWithQueue(indexName string) (bool, error)

MarkIndexWriteOnlyWithQueue requests deferred user maintenance. RFC-257 adds eligibility validation to Java's setter so unsupported requests cannot persist an index state that the store cannot maintain.

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) OverrideLockSaveRecordWithVersion

func (store *FDBRecordStore) OverrideLockSaveRecordWithVersion(
	record proto.Message,
	existenceCheck RecordExistenceCheck,
	version *FDBRecordVersion,
	behavior VersionstampSaveBehavior,
) (*FDBStoredRecord[proto.Message], error)

OverrideLockSaveRecordWithVersion is OverrideLockSaveRecord with SaveRecordWithVersion's version choice: Java's overrideLockSaveRecordAsync(rec, existenceCheck, version, behavior).

func (*FDBRecordStore) PeekIndexStates

func (store *FDBRecordStore) PeekIndexStates() map[string]IndexState

PeekIndexStates returns the state of every index the metadata names, an index with no stored state defaulted to READABLE, WITHOUT any read conflict: the states the store loaded at open, Java's getRecordStoreState().getState (PlanContext.java:237-260 plans from them and adds no conflict). It serves SQL planning and the per-page plan revalidation only; a scan takes its own per-index conflict key (ReadIndexState), so a state change of an index a statement never scans does not abort its transaction.

func (*FDBRecordStore) ReadIndexState

func (store *FDBRecordStore) ReadIndexState(indexName string) (IndexState, error)

ReadIndexState returns transaction-visible state with a serializable state-key conflict and propagates initialization and transaction-liveness errors.

func (*FDBRecordStore) RebuildAllIndexes

func (store *FDBRecordStore) RebuildAllIndexes() error

RebuildAllIndexes rebuilds eligible indexes that are not in READABLE state. Replaced originals are excluded, but explicit RebuildIndex remains supported. 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)

ReleaseReadLock releases the shared lock AcquireReadLock took for key.

func (*FDBRecordStore) ReleaseWriteLock

func (store *FDBRecordStore) ReleaseWriteLock(key string)

ReleaseWriteLock releases the exclusive lock AcquireWriteLock took for key.

func (*FDBRecordStore) ReloadRecordStoreState

func (store *FDBRecordStore) ReloadRecordStoreState() error

ReloadRecordStoreState forces a reload of the store state from FDB. Refreshes transaction-visible state, including explicit raw state mutations; it does not advance the transaction's read version. The loaded state is shared with other handles in this context. 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). This low-level utility removes only the named entry. Ordinary record deletion uses Java's removeUniquenessViolationsAsync algorithm, including survivor cleanup.

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 existing-record ranges 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 and the default version behavior.

Java equivalent: FDBRecordStoreBase.saveRecord(Message rec, RecordExistenceCheck existenceCheck)

Returns:

  • *FDBStoredRecord: The saved record with metadata
  • error: RecordAlreadyExistsError, RecordDoesNotExistError, or RecordTypeChangedError based on existenceCheck

func (*FDBRecordStore) SaveRecordWithVersion

func (store *FDBRecordStore) SaveRecordWithVersion(
	record proto.Message,
	existenceCheck RecordExistenceCheck,
	version *FDBRecordVersion,
	behavior VersionstampSaveBehavior,
) (*FDBStoredRecord[proto.Message], error)

SaveRecordWithVersion saves a record with the version behavior chooses from version (nil, complete, or incomplete from ClaimLocalVersion): Java's saveRecordAsync(rec, check, version, behavior).

func (*FDBRecordStore) SaveRecordsPipelined

func (store *FDBRecordStore) SaveRecordsPipelined(
	records []proto.Message,
	existenceCheck RecordExistenceCheck,
) ([]*FDBStoredRecord[proto.Message], error)

SaveRecordsPipelined saves records in order as SaveRecordWithOptions would one at a time, but sends the existing-record reads of each window of DefaultPipelineSize records together: Java's INSERT pipelines its saves (RecordQueryAbstractDataModificationPlan mapPipelined, at FDBRecordStore.DEFAULT_PIPELINE_SIZE). The first failing record stops the save and is the one reported; the reads already sent for the rest of its window stay in the transaction, as Java's do.

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) ScanIndexRecordsWithFetchMethod

func (store *FDBRecordStore) ScanIndexRecordsWithFetchMethod(index *Index, method IndexFetchMethod, scanType IndexScanType, scanRange TupleRange, commonPrimaryKeyLength int, continuation []byte, orphan IndexOrphanBehavior, props ScanProperties) RecordCursor[*FDBIndexedRecord]

ScanIndexRecordsWithFetchMethod scans the records an index points to with the given fetch method. WITH_FALLBACK falls back to SCAN_AND_FETCH when remote fetch cannot start, or fails later from the last result it returned. Matches Java's FDBRecordStoreBase.scanIndexRecords(Index, IndexFetchMethod, IndexScanBounds, int, byte[], IndexOrphanBehavior, ScanProperties).

func (*FDBRecordStore) ScanIndexRemoteFetch

func (store *FDBRecordStore) ScanIndexRemoteFetch(index *Index, scanType IndexScanType, scanRange TupleRange, commonPrimaryKeyLength int, continuation []byte, props ScanProperties, orphan IndexOrphanBehavior) RecordCursor[*FDBIndexedRecord]

ScanIndexRemoteFetch scans an index and has the storage server return each entry's record with it. Matches Java's FDBRecordStore.scanIndexRemoteFetch.

func (*FDBRecordStore) ScanRankIndex

func (store *FDBRecordStore) ScanRankIndex(index *Index, bounds RankScanBounds, continuation []byte, props ScanProperties) RecordCursor[*IndexEntry]

ScanRankIndex scans a RANK index, optionally enriching values with tuple(rank). Rank lookups remain serializable even when the underlying scan is snapshot.

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, resuming after continuation's key. Matches Java's FDBRecordStoreBase.scanRecords(continuation, scanProperties).

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) ScanVectorIndexWithOptions

func (store *FDBRecordStore) ScanVectorIndexWithOptions(
	index *Index,
	prefix tuple.Tuple,
	queryVector []float64,
	k int,
	opts VectorIndexScanOptions,
	continuation []byte,
	scanProperties ScanProperties,
) RecordCursor[*IndexEntry]

ScanVectorIndexWithOptions is ScanVectorIndexWithPrefix with the full set of per-scan options.

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 preserves the completeness of 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 complete or incomplete versions to an FDB tuple.Versionstamp. Incomplete versions preserve the placeholder and local version for key mutations. 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.
	// 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

	// VersionedInline reports a version stored with the record and counted in its sizes.
	VersionedInline bool
	// contains filtered or unexported fields
}

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) FanType

func (f *FieldKeyExpression) FanType() FanType

FanType is Java's FieldKeyExpression.getFanType().

func (*FieldKeyExpression) FieldName

func (f *FieldKeyExpression) FieldName() string

FieldName is Java's FieldKeyExpression.getFieldName().

func (*FieldKeyExpression) FieldNames

func (f *FieldKeyExpression) FieldNames() []string

FieldNames returns the field name accessed by this expression

func (*FieldKeyExpression) PackDirect

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 FixedZeroKeyManager

type FixedZeroKeyManager struct {
	// contains filtered or unexported fields
}

FixedZeroKeyManager is Java's FixedZeroKeyManager: one key, served as key number 0 only.

func NewFixedZeroKeyManager

func NewFixedZeroKeyManager(key []byte, cipherName string, random io.Reader) *FixedZeroKeyManager

NewFixedZeroKeyManager returns a key manager serving key as key number 0, with cipherName (DefaultCipher when empty) and random (the writing store's randomness when nil).

func (*FixedZeroKeyManager) GetCipher

func (m *FixedZeroKeyManager) GetCipher(keyNumber int32) (string, error)

func (*FixedZeroKeyManager) GetKey

func (m *FixedZeroKeyManager) GetKey(keyNumber int32) ([]byte, error)

func (*FixedZeroKeyManager) GetRandom

func (m *FixedZeroKeyManager) GetRandom(keyNumber int32) (io.Reader, error)

func (*FixedZeroKeyManager) GetSerializationKey

func (m *FixedZeroKeyManager) GetSerializationKey() int32

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

type FormerIndex struct {
	SubspaceKey    any
	AddedVersion   int
	RemovedVersion int
	FormerName     string
}

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) JavaRecordCoreException

func (*FoundSplitOutOfOrderError) JavaRecordCoreException()

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 (*FoundSplitWithoutStartError) JavaRecordCoreException

func (*FoundSplitWithoutStartError) JavaRecordCoreException()

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 is Java's FunctionKeyExpression.create(name, arguments). Java throws at the call for a name the registry lacks or an argument column size outside the function's bounds; FunctionExpr has no error channel, so it records the refusal in program order and Build returns it.

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 is the function's own column size, Java's getColumnSize. A loaded name the registry lacks has 1 (DIVERGENCES.md).

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 FunctionSpec

type FunctionSpec struct {
	// Evaluator computes the function over each evaluated argument row.
	Evaluator FunctionEvaluator
	// MinArguments and MaxArguments bound the argument expression's column
	// size, Java's getMinArguments and getMaxArguments, checked where Java's
	// FunctionKeyExpression.create checks them (FunctionKeyExpression.java:
	// 118-127).
	MinArguments, MaxArguments int
	// ColumnSize is the number of key columns the function produces, Java's
	// getColumnSize.
	ColumnSize int
	// NullIsNonUnique records that the function's null result is Java's
	// Key.Evaluated.NULL, the NullStandin.NULL a unique index ignores and
	// COUNT_NOT_NULL does not count, as CollateFunctionKeyExpression.java:169
	// and CardinalityFunctionKeyExpression.java:148 return it. Otherwise its
	// null is Key.Evaluated.scalar(null), a plain null
	// (LongArithmethicFunctionKeyExpression.java:98), which collides.
	NullIsNonUnique bool
	// contains filtered or unexported fields
}

FunctionSpec is a key function's registry entry: the Go form of what a Java FunctionKeyExpression subclass declares.

func LookupFunction

func LookupFunction(name string) (FunctionSpec, bool)

LookupFunction is the registry entry for name, Java's FunctionKeyExpression.Registry.getBuilder.

type GlobalDirectoryLayer

type GlobalDirectoryLayer struct{}

GlobalDirectoryLayer is ScopedDirectoryLayer.global: the FDB directory layer at the default node subspace (0xFE) with an empty content subspace, whose one-element directories' prefixes are tuple longs, plus the reverse directory cache entry each read or create writes.

type GoOnlyCollationError

type GoOnlyCollationError struct {
	Function       string
	IndexName      string // the refused index, or "" for a primary key
	RecordTypeName string // the record type whose primary key is refused
	RecordCountKey bool   // the legacy record-count expression is refused
}

GoOnlyCollationError rejects provider-specific collation keys without explicit Go-only opt-in. It unwraps to MetaDataError; Java has no equivalent refusal.

func (*GoOnlyCollationError) Error

func (e *GoOnlyCollationError) Error() string

func (*GoOnlyCollationError) JavaRecordCoreException

func (*GoOnlyCollationError) JavaRecordCoreException()

func (*GoOnlyCollationError) Unwrap

func (e *GoOnlyCollationError) Unwrap() error

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 IllegalArgumentError

type IllegalArgumentError = javanum.IllegalArgumentError

IllegalArgumentError is Java's IllegalArgumentException, raised by the option parsers Java runs through the JDK: an out-of-range RankedSet level count (RankedSet.ConfigBuilder.setNLevels) or an unknown enum name (Enum.valueOf, as RTree.Storage.valueOf).

type IllegalStateError

type IllegalStateError = javanum.IllegalStateError

IllegalStateError is Java's IllegalStateException.

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 a VERSION index whose version lands in the VALUE portion of a KeyWithValue split (IndexTest.createVersionIndexWithVersionInValue), or from ordering functions over versions in legal VALUE indexes and primary keys. A VERSION index rooted at an ordering function is instead refused at metadata validation because functions declare zero version columns.

func (*IncompleteVersionstampError) Error

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
}

Index represents a secondary index definition. Matches Java's com.apple.foundationdb.record.metadata.Index.

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 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 must be a KeyWithValue: key columns partition the index, and the first value column is the vector. numDimensions is the mandatory hnswNumDimensions; the metric (hnswMetric) is one of Java's four Metric constant names. 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

func (idx *Index) CanonicalType() string

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

func (i *Index) CreatesDuplicates() bool

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) EntryPrimaryKey

func (idx *Index) EntryPrimaryKey(entryKey tuple.Tuple) tuple.Tuple

EntryPrimaryKey reconstructs the full primary key from an index entry key. When primaryKeyComponentPositions is set, some PK components come from the index key portion and some from the appended portion. Returns an empty tuple if the entry key is truncated (fewer elements than expected). Matches Java's Index.getEntryPrimaryKey().

func (*Index) EntryPrimaryKeyPositions

func (idx *Index) EntryPrimaryKeyPositions(primaryKeyLength int) []int

EntryPrimaryKeyPositions returns the position of each primary-key component in an entry's key. Matches Java's Index.getEntryPrimaryKeyPositions: with an overlap mapping, its length wins over primaryKeyLength.

func (*Index) GetBooleanOption

func (idx *Index) GetBooleanOption(key string, defaultVal bool) bool

GetBooleanOption returns the boolean value of an index option. Returns the default value if the option is not set, and otherwise Boolean.valueOf's reading: "true" in any case is true, anything else false. Matches Java's Index.getBooleanOption(String, boolean).

func (*Index) GetPredicateProto

func (idx *Index) GetPredicateProto() *gen.Predicate

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

func (idx *Index) GetReplacedByIndexNames() []string

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, in option order. Matches Java's Index.getReplacedByIndexNames().

func (*Index) HasExplicitSubspaceKey

func (idx *Index) HasExplicitSubspaceKey() bool

HasExplicitSubspaceKey reports whether the subspace key was chosen rather than defaulted from the index name. Matches Java's Index.hasExplicitSubspaceKey().

func (*Index) HasFilteringPredicate

func (idx *Index) HasFilteringPredicate() bool

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

func (idx *Index) HasPredicate() bool

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

func (idx *Index) HasPrimaryKeyComponentPositions() bool

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

func (idx *Index) HasRowNumberWindowPredicate() bool

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

func (idx *Index) IsAtomicMutationIndex() bool

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

func (idx *Index) IsClearWhenZero() bool

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

func (idx *Index) IsUnique() bool

IsUnique returns whether this index enforces a uniqueness constraint. Matches Java's Index.isUnique() which checks IndexOptions.UNIQUE_OPTION.

func (*Index) OptionKeys

func (idx *Index) OptionKeys() []string

OptionKeys returns the option keys in stored order: the keys set through SetOption in the order they were first set (skipping any since deleted), then any key written into Options directly, sorted.

func (*Index) PrimaryKeyComponentPositions

func (idx *Index) PrimaryKeyComponentPositions() []int

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

func (idx *Index) SetClearWhenZero(clear bool) *Index

SetClearWhenZero enables or disables the clear-when-zero behavior. Matches Java's IndexOptions.CLEAR_WHEN_ZERO.

func (*Index) SetOption

func (idx *Index) SetOption(key, value string) *Index

SetOption sets an index option. A key set for the first time takes the next position in the stored option order, as Java's RecordLayerIndex.Builder.setOption and Index's ImmutableMap do; setting it again changes only its value.

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

func (idx *Index) SetPredicateProto(p *gen.Predicate) error

SetPredicateProto sets a predicate from a proto message. This both stores the proto for round-tripping and builds an evaluator function.

func (*Index) SetSubspaceKey

func (idx *Index) SetSubspaceKey(key any) *Index

SetSubspaceKey overrides the default subspace key (index name). Matches Java's Index.setSubspaceKey() (Index.java:413-416), including its side effect of MARKING the key explicit — see useExplicitSubspaceKey — and its normalization of the key (tupleEquivalentValue), so an int32 key is stored, and packed, as an int64. Java refuses a nil key with RecordCoreArgumentException "Index subspace key cannot be null" and keeps the key it had; a typed nil (a nil *big.Int or *FDBRecordVersion) is that null too. A Go setter returns the Index for chaining, so the refusal is kept on the Index and returned by every RecordMetaDataBuilder.Build that includes the index, whether the set came before or after AddIndex. It is STICKY: Java throws at the refused call, so no later call of that program runs, and a later valid set here does not clear it, and a refused set leaves the index as it was (Java normalizes before it assigns or marks anything, Index.java:413-416), explicit mark included. Build returns the refusal in program order among the builder's own faults, also for an index removed or refused as a duplicate after the set.

Divergence, Go-only: an index already inside a built RecordMetaData has no Build left to return the refusal. There the refused set records the error (SubspaceKeyError reports it) and changes nothing, where Java throws.

func (*Index) SetUnique

func (idx *Index) SetUnique() *Index

SetUnique marks this index as enforcing uniqueness.

func (*Index) SubspaceKeyError

func (idx *Index) SubspaceKeyError() error

SubspaceKeyError returns the refusal a SetSubspaceKey of a nil key recorded on this index, or nil. Build returns it for an index it builds; this is where the refusal of a set on an index of a built RecordMetaData is read.

func (*Index) SubspaceTupleKey

func (idx *Index) SubspaceTupleKey() any

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

func (idx *Index) TrimPrimaryKey(primaryKey tuple.Tuple) (tuple.Tuple, error)

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 IndexBuildOutcome

type IndexBuildOutcome int

IndexBuildOutcome is what a BuildIndex call did. It is a Go extension: Java's buildIndex returns nothing, and a session that left a READABLE index alone, one that only published, and a build over an empty store all return 0 records.

const (
	// IndexBuildOutcomeNone: no BuildIndex call has completed, or the last one
	// failed.
	IndexBuildOutcomeNone IndexBuildOutcome = iota
	// IndexBuildOutcomeBuilt: the call succeeded and built. Either the attempt
	// that ended it ran the build over the targets' ranges (published unless
	// publication was disabled), which it counts even when it indexed no
	// records, as over an empty store; or an earlier attempt indexed records
	// and failed into a retry, whatever the attempt that ended the call then
	// found: the targets published, which it may have done itself
	// (MARK_READABLE), or a mutual build its peers completed.
	IndexBuildOutcomeBuilt
	// IndexBuildOutcomeLeftAlone: the call neither built nor published. That
	// covers two cases: the primary index was READABLE under CONTINUE (what fdb
	// reports as already readable), or MARK_READABLE was resolved with
	// publication disabled (unreachable from fdb, which always publishes).
	IndexBuildOutcomeLeftAlone
	// IndexBuildOutcomePublished: the call published the targets without
	// building them (MARK_READABLE).
	IndexBuildOutcomePublished
	// IndexBuildOutcomeCompletedByPeers: a mutual build found every target
	// already published by its peers, and this call indexed nothing.
	IndexBuildOutcomeCompletedByPeers
)

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 IndexCarryClass

type IndexCarryClass int

IndexCarryClass is how a rebuilt index definition relates to the stored index of the same name (RFC-257 WS-J section 4): what a new template version carries for it, and what a template restore admits between two stored versions.

const (
	// IndexEquivalent: every compared field is equal, so the stored Index
	// message is carried as it was stored.
	IndexEquivalent IndexCarryClass = iota
	// IndexChanged: any other difference; the index is rebuilt.
	IndexChanged
)

func ClassifyIndexCarry

func ClassifyIndexCarry(stored, rebuilt *gen.Index) (IndexCarryClass, string, error)

ClassifyIndexCarry compares a stored Index message with a rebuilt one of the same name and returns its class and, for CHANGED, the name of the first Index field (in field-number order) that differs.

Each side is read as Java's Index(proto) reads it (Index.java:194-235, Go indexFromProto): the deprecated index_type becomes the type and options it names, and the stored option list beside it is not read; an absent type is VALUE; the deprecated value_expression is folded into the root; a RANK, COUNT, MAX_EVER, MIN_EVER or SUM root that is not a grouping is compared as the grouping Java wraps it in; an absent root is refused. A side that does not load returns its error. The comparison then walks the Index descriptor, so a field a later proto sync adds is compared (as proto equality of its stored value) without a code change:

  • record_type as a set;
  • name, and a field this function does not name, by proto equality;
  • index_type and value_expression through the fields they fold into;
  • root_expression as the root Java reads (the fold and the grouping wrap above), by proto equality: a literal whose carrier differs (long_value against int_value) is a changed key, as Java's validator reads it (MetaDataEvolutionValidator.java:719, LiteralKeyExpression's equals), and so is a root differing only in a field's null_interpretation, which Java's validator does not compare (FieldKeyExpression.equals leaves the standin out, FieldKeyExpression.java:406-410) but which changes what the index's readers do with a null (NullStandin): such an index is rebuilt;
  • type as Java reads it, options as a map, as Java's Index holds them;
  • predicate by proto equality, both absent included (a changed WHERE changes which records the index holds, and no validator compares predicates);
  • added_version, last_modified_version and subspace_key not at all: the carry assigns them.

Unknown fields and extensions are not compared: neither engine reads them.

func (IndexCarryClass) String

func (c IndexCarryClass) String() string

type IndexDeferredMaintenanceControl

type IndexDeferredMaintenanceControl struct {
	// contains filtered or unexported fields
}

IndexDeferredMaintenanceControl is a transaction-local exchange between index maintainers and the online merger. Its zero values match Java's initializer (auto-merge is false, despite the contradictory setter javadoc). Callbacks run outside the control's lock.

func (*IndexDeferredMaintenanceControl) GetLastStep

func (*IndexDeferredMaintenanceControl) GetMergeRequiredIndexes

func (c *IndexDeferredMaintenanceControl) GetMergeRequiredIndexes() []*Index

func (*IndexDeferredMaintenanceControl) GetMergeSessionID

func (c *IndexDeferredMaintenanceControl) GetMergeSessionID() *uuid.UUID

func (*IndexDeferredMaintenanceControl) GetMergesFound

func (c *IndexDeferredMaintenanceControl) GetMergesFound() int64

func (*IndexDeferredMaintenanceControl) GetMergesLimit

func (c *IndexDeferredMaintenanceControl) GetMergesLimit() int64

func (*IndexDeferredMaintenanceControl) GetMergesTried

func (c *IndexDeferredMaintenanceControl) GetMergesTried() int64

func (*IndexDeferredMaintenanceControl) GetPreCommitCallback

func (c *IndexDeferredMaintenanceControl) GetPreCommitCallback() func(*FDBRecordStore) error

func (*IndexDeferredMaintenanceControl) GetRepartitionDocumentCount

func (c *IndexDeferredMaintenanceControl) GetRepartitionDocumentCount() int

func (*IndexDeferredMaintenanceControl) GetSizeQuotaBytes

func (c *IndexDeferredMaintenanceControl) GetSizeQuotaBytes() int64

func (*IndexDeferredMaintenanceControl) GetTimeQuotaMillis

func (c *IndexDeferredMaintenanceControl) GetTimeQuotaMillis() int64

func (*IndexDeferredMaintenanceControl) GetTotalMerges

func (c *IndexDeferredMaintenanceControl) GetTotalMerges() int64

func (*IndexDeferredMaintenanceControl) IsExplicitMergePath

func (c *IndexDeferredMaintenanceControl) IsExplicitMergePath() bool

func (*IndexDeferredMaintenanceControl) MergeHadFailed

func (c *IndexDeferredMaintenanceControl) MergeHadFailed()

func (*IndexDeferredMaintenanceControl) RegisterPreCommit

func (c *IndexDeferredMaintenanceControl) RegisterPreCommit(store *FDBRecordStore, index *Index)

RegisterPreCommit registers the callback on the actual write transaction. A maintainer's merge calls it only if it must refresh the session heartbeat, as Java's Lucene queue drain does; no core merge calls it, as in Java. A backend that creates child transactions must call this for each child too; installing it on an outer coordinator alone does not protect child commits.

func (*IndexDeferredMaintenanceControl) RepartitionCapped

func (c *IndexDeferredMaintenanceControl) RepartitionCapped() bool

func (*IndexDeferredMaintenanceControl) SetAutoMergeDuringCommit

func (c *IndexDeferredMaintenanceControl) SetAutoMergeDuringCommit(value bool)

func (*IndexDeferredMaintenanceControl) SetExplicitMergePath

func (c *IndexDeferredMaintenanceControl) SetExplicitMergePath(value bool)

func (*IndexDeferredMaintenanceControl) SetLastStep

func (*IndexDeferredMaintenanceControl) SetMergeRequiredIndexes

func (c *IndexDeferredMaintenanceControl) SetMergeRequiredIndexes(index *Index) error

func (*IndexDeferredMaintenanceControl) SetMergeSessionID

func (c *IndexDeferredMaintenanceControl) SetMergeSessionID(id *uuid.UUID)

func (*IndexDeferredMaintenanceControl) SetMergesFound

func (c *IndexDeferredMaintenanceControl) SetMergesFound(value int64)

func (*IndexDeferredMaintenanceControl) SetMergesLimit

func (c *IndexDeferredMaintenanceControl) SetMergesLimit(value int64)

func (*IndexDeferredMaintenanceControl) SetMergesTried

func (c *IndexDeferredMaintenanceControl) SetMergesTried(count int64)

func (*IndexDeferredMaintenanceControl) SetPreCommitCallback

func (c *IndexDeferredMaintenanceControl) SetPreCommitCallback(value func(*FDBRecordStore) error)

func (*IndexDeferredMaintenanceControl) SetRepartitionCapped

func (c *IndexDeferredMaintenanceControl) SetRepartitionCapped(value bool)

func (*IndexDeferredMaintenanceControl) SetRepartitionDocumentCount

func (c *IndexDeferredMaintenanceControl) SetRepartitionDocumentCount(value int)

func (*IndexDeferredMaintenanceControl) SetSizeQuotaBytes

func (c *IndexDeferredMaintenanceControl) SetSizeQuotaBytes(value int64)

func (*IndexDeferredMaintenanceControl) SetTimeQuotaMillis

func (c *IndexDeferredMaintenanceControl) SetTimeQuotaMillis(value int64)

func (*IndexDeferredMaintenanceControl) ShouldAutoMergeDuringCommit

func (c *IndexDeferredMaintenanceControl) ShouldAutoMergeDuringCommit() bool

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 NewIndexEntry

func NewIndexEntry(index *Index, key, value, primaryKey tuple.Tuple) *IndexEntry

NewIndexEntry is Java's IndexEntry(index, key, value, primaryKey): an entry whose primary key is known rather than extracted from its key.

func (*IndexEntry) IndexEntryKey

func (e *IndexEntry) IndexEntryKey() tuple.Tuple

IndexEntryKey is the entry's raw KEY tuple, the tuple an index-entry reader Value's KEY source reads.

func (*IndexEntry) IndexEntryValue

func (e *IndexEntry) IndexEntryValue() tuple.Tuple

IndexEntryValue is the entry's raw VALUE tuple.

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 IndexFetchMethod

type IndexFetchMethod = indexfetch.Method

IndexFetchMethod is Java's com.apple.foundationdb.record.IndexFetchMethod.

type IndexKeySizeError

type IndexKeySizeError struct {
	IndexName  string
	PrimaryKey tuple.Tuple
	KeySize    int
	Limit      int
}

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

func (*IndexKeySizeError) JavaRecordCoreException

func (*IndexKeySizeError) JavaRecordCoreException()

type IndexMaintainer

type IndexMaintainer interface {
	// MergeIndex performs the backend's deferred maintenance, if any.
	MergeIndex() error

	// 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

	// Pending queue support is opt-in; serialization applies maintenance filters
	// now, while replay applies the captured entries without reevaluating them.
	IsPendingWriteQueueAllowed() bool
	SerializePendingWriteQueue(oldRecord, newRecord *FDBStoredRecord[proto.Message]) (*anypb.Any, error)
	UpdateFromQueue(data *anypb.Any) 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 IndexMaintainerFactory

type IndexMaintainerFactory interface {
	// IndexTypes is getIndexTypes: the types this factory maintains.
	IndexTypes() []string
	// NewIndexMaintainer is getIndexMaintainer(IndexMaintainerState).
	NewIndexMaintainer(state IndexMaintainerState) (IndexMaintainer, error)
	// ValidateIndexOptions is the option half of the type's
	// IndexValidator.validate, run at meta-data build.
	ValidateIndexOptions(index *Index) error
	// ValidateChangedOptions is IndexValidator.validateChangedOptions: it
	// checks the changed options the type owns and removes them from changed.
	ValidateChangedOptions(oldIndex, newIndex *Index, changed map[string]bool) error
}

IndexMaintainerFactory is Java's IndexMaintainerFactory for an index type implemented outside this package. Java finds its factories with a service loader; Go's register themselves from an init function, so a binary maintains such a type only when it links the implementing package. The built-in types are dispatched directly by createIndexMaintainer.

type IndexMaintainerNotLinkedError

type IndexMaintainerNotLinkedError struct {
	IndexName string
	IndexType string
	Package   string
}

IndexMaintainerNotLinkedError is raised when an index's type is implemented by a package this binary does not link (see linkedIndexTypePackages). Like UnknownIndexTypeError it unwraps to *MetaDataError, Java's registry miss.

func (*IndexMaintainerNotLinkedError) Error

func (*IndexMaintainerNotLinkedError) JavaRecordCoreException

func (*IndexMaintainerNotLinkedError) JavaRecordCoreException()

func (*IndexMaintainerNotLinkedError) Unwrap

Unwrap reports this as a metadata failure.

type IndexMaintainerState

type IndexMaintainerState struct {
	Store         *FDBRecordStore
	Context       *FDBRecordContext
	Index         *Index
	IndexSubspace subspace.Subspace
	Transaction   fdb.WritableTransaction
	Timer         *StoreTimer
}

IndexMaintainerState is Java's IndexMaintainerState: what a factory builds a maintainer from.

type IndexMaintenanceFilter

type IndexMaintenanceFilter interface {
	// MaintainIndex is Java's maintainIndex.
	MaintainIndex(index *Index, record proto.Message) IndexValues
	// MaintainIndexValue is Java's maintainIndexValue, asked of each entry
	// only when MaintainIndex returned IndexValuesSome. The entry's Key is the
	// evaluated index key, without the primary key, and its Value the
	// evaluated value (a key-with-value index's value columns), as Java's
	// IndexEntry is when the filter sees it.
	MaintainIndexValue(index *Index, record proto.Message, entry *IndexEntry) bool
}

IndexMaintenanceFilter is Java's IndexMaintenanceFilter (IndexMaintenanceFilter.java), a store option: per index and record, which index entries are maintained. An index's predicate is applied first; a record it refuses is IndexValuesNone whatever the filter says (IndexMaintenanceUtils.getFilterTypeForRecord). Set it with StoreBuilder.SetIndexMaintenanceFilter; the default is IndexMaintenanceFilterNormal.

var (
	// IndexMaintenanceFilterNormal is Java's NORMAL: every entry of every
	// record, the default.
	IndexMaintenanceFilterNormal IndexMaintenanceFilter = normalMaintenanceFilter{}
	// IndexMaintenanceFilterNoNulls is Java's NO_NULLS: no entry whose key
	// holds a NullStandin.NULL (IndexEntry.keyContainsNonUniqueNull).
	IndexMaintenanceFilterNoNulls IndexMaintenanceFilter = noNullsMaintenanceFilter{}
)

type IndexNotBuiltError

type IndexNotBuiltError struct {
	IndexName     string
	PendingWrites bool
}

IndexNotBuiltError is returned when trying to mark an index as readable but it has unbuilt ranges or pending index writes remain.

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

func (*IndexNotFoundError) JavaRecordCoreException

func (*IndexNotFoundError) JavaRecordCoreException()

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

func (*IndexNotReadableError) JavaRecordCoreException

func (*IndexNotReadableError) JavaRecordCoreException()

type IndexOrphanBehavior

type IndexOrphanBehavior int

IndexOrphanBehavior says what an index-to-record scan does with an entry whose record does not exist. Matches Java's IndexOrphanBehavior.

const (
	// IndexOrphanError fails the scan with a RecordCoreStorageError.
	IndexOrphanError IndexOrphanBehavior = iota
	// IndexOrphanSkip drops the entry.
	IndexOrphanSkip
	// IndexOrphanReturn returns the entry with a nil record.
	IndexOrphanReturn
)

func (IndexOrphanBehavior) String

func (b IndexOrphanBehavior) String() string

type IndexOutOfBoundsError

type IndexOutOfBoundsError struct{ Message string }

IndexOutOfBoundsError corresponds to Java's IndexOutOfBoundsException, e.g. a vector index entry without a value column or with an unknown vector type.

func (*IndexOutOfBoundsError) Error

func (e *IndexOutOfBoundsError) Error() string

type IndexPredicate

type IndexPredicate func(msg proto.Message) bool

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 IndexRangeClaimLostError

type IndexRangeClaimLostError struct {
	IndexName  string
	Begin, End []byte
}

IndexRangeClaimLostError prevents committing staged index writes when a target's range was already claimed. It is a failed batch, not successful progress or a reason to commit and jump to another fragment.

func (*IndexRangeClaimLostError) Error

func (e *IndexRangeClaimLostError) Error() string

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 [group..., numeric rank], using Java's Number.longValue().
	// A null rank bound is unbounded.
	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
	// IndexStateWriteOnlyWithQueue defers user maintenance to the pending queue.
	IndexStateWriteOnlyWithQueue IndexState = 4
)

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 for either write-only state.

func (IndexState) IsWriteOnlyNoQueue

func (s IndexState) IsWriteOnlyNoQueue() bool

func (IndexState) IsWriteOnlyWithQueue

func (s IndexState) IsWriteOnlyWithQueue() bool

func (IndexState) String

func (s IndexState) String() string

type IndexStoreContext

type IndexStoreContext interface {

	// AcquireWriteLock acquires an exclusive lock for the given subspace key.
	// Used by tree-structured indexes (HNSW, R-tree) to serialize mutations.
	// Matches Java's FDBRecordContext.doWithWriteLock(LockIdentifier).
	AcquireWriteLock(key string)
	ReleaseWriteLock(key string)
	// AcquireReadLock acquires a shared lock for the given subspace key.
	// Used by tree-structured indexes to allow concurrent reads during scans.
	// Matches Java's FDBRecordContext.doWithReadLock(LockIdentifier).
	AcquireReadLock(key string)
	ReleaseReadLock(key string)

	// Env exposes the DST Tier-0 environment (Clock + Randomness + Buggify)
	// inherited from the record context. Nil-safe: a nil *dst.Env means
	// production, and the *dst.Env accessors fall back to wall clock / crypto/rand.
	// Vector-index maintainers (HNSW, R-tree) draw node-ID and sample-key nonces
	// through Env().Read so a simulation run reproduces the persisted bytes.
	Env() *dst.Env
	// contains filtered or unexported methods
}

IndexStoreContext provides the store methods needed by index maintainers. Avoids circular dependency by using an interface instead of *FDBRecordStore directly.

type IndexValidationEntry

type IndexValidationEntry struct {
	IndexKey   tuple.Tuple
	PrimaryKey tuple.Tuple
}

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

type IndexValueSizeError struct {
	IndexName  string
	PrimaryKey tuple.Tuple
	ValueSize  int
	Limit      int
}

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

func (*IndexValueSizeError) JavaRecordCoreException

func (*IndexValueSizeError) JavaRecordCoreException()

type IndexValues

type IndexValues int

IndexValues is Java's IndexMaintenanceFilter.IndexValues: which of a record's index entries an index maintains.

const (
	// IndexValuesAll maintains every entry.
	IndexValuesAll IndexValues = iota
	// IndexValuesNone maintains none: the index is maintained as if the
	// record had no entries.
	IndexValuesNone
	// IndexValuesSome maintains the entries MaintainIndexValue admits.
	IndexValuesSome
)

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) JavaRecordCoreException

func (*IndexVersionTooNewError) JavaRecordCoreException()

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 IndexingDesiredAction

type IndexingDesiredAction int

IndexingDesiredAction is what a build session does with the index state it finds. Matches Java's OnlineIndexer.IndexingPolicy.DesiredAction.

const (
	// DesiredActionDefault leaves the choice to Java's builder default for the
	// state: REBUILD if disabled, CONTINUE if write-only or readable. It is the
	// zero value, so an IndexingPolicy that never mentions a state gets Java's
	// default for it.
	DesiredActionDefault IndexingDesiredAction = iota
	// DesiredActionError refuses to start a session over the state.
	DesiredActionError
	// DesiredActionRebuild clears the index and builds it from scratch.
	DesiredActionRebuild
	// DesiredActionContinue continues a write-only build, builds a disabled index
	// without clearing it, and leaves a readable index alone.
	DesiredActionContinue
	// DesiredActionMarkReadable publishes the index without building it.
	DesiredActionMarkReadable
)

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: validates key compatibility but permits active peers.

Used for admission and exclusive renewal. Already-admitted mutual sessions renew only their own key, matching Java's mutual checkAndUpdateHeartbeat path.

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 IndexingHeartbeatKeyError

type IndexingHeartbeatKeyError struct {
	IndexName string
	Key       []byte
}

IndexingHeartbeatKeyError rejects legacy or malformed heartbeat keys before admitting UUID-only builders. Old Go builders must be stopped and fenced before administrative cleanup; automatically expiring these keys cannot establish that.

func (*IndexingHeartbeatKeyError) Error

func (e *IndexingHeartbeatKeyError) Error() string

type IndexingPolicy

type IndexingPolicy struct {
	// IfDisabled, IfWriteOnly and IfReadable choose what a session does with the
	// primary index's state (Java ifDisabled/ifWriteOnly/ifReadable). The zero
	// value is Java's default for that state; see GetStateDesiredAction.
	IfDisabled  IndexingDesiredAction
	IfWriteOnly IndexingDesiredAction
	IfReadable  IndexingDesiredAction

	// IfMismatchPrevious chooses what BuildIndex does when the index is partly
	// built by a different method than the one requested (Java
	// ifMismatchPrevious, read by OnlineIndexer.indexingCatcher). CONTINUE, the
	// zero value's meaning, continues the previous method; REBUILD clears and
	// builds by the requested one; ERROR and MARK_READABLE return the
	// PartlyBuiltError. See GetIfMismatchPrevious.
	IfMismatchPrevious IndexingDesiredAction

	// ForbidRecordScan stops a BY_INDEX build whose source index cannot be used
	// from falling back to a records scan (Java forbidRecordScan).
	ForbidRecordScan bool

	// InitialMergesCountLimit is the initial deferred-merge budget (zero is unlimited).
	InitialMergesCountLimit int64
	// 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

	// PendingWriteQueueIndexes explicitly requests deferred maintenance by index name.
	PendingWriteQueueIndexes map[string]bool
	// Nil selects Java's default of 100 closeout attempts; zero remains explicit.
	PendingWriteQueueIndexesMaxDrainAttempts *int64
}

IndexingPolicy configures how the OnlineIndexer handles stamp conflicts, blocked stamps, and build method conversions. Matches Java's OnlineIndexer.IndexingPolicy.

func (*IndexingPolicy) GetIfMismatchPrevious

func (p *IndexingPolicy) GetIfMismatchPrevious() (IndexingDesiredAction, error)

GetIfMismatchPrevious resolves IfMismatchPrevious, with Java's builder default CONTINUE standing in for an unset field (IndexingPolicy.Builder). An action outside the enum is a RecordCoreError, as in GetStateDesiredAction.

func (*IndexingPolicy) GetPendingWriteQueueIndexesMaxDrainAttempts

func (p *IndexingPolicy) GetPendingWriteQueueIndexesMaxDrainAttempts() int64

func (*IndexingPolicy) GetStateDesiredAction

func (p *IndexingPolicy) GetStateDesiredAction(state IndexState) (IndexingDesiredAction, error)

GetStateDesiredAction resolves what a session does with an index in state. Matches Java's IndexingPolicy.getStateDesiredAction, with the builder defaults (IndexingPolicy.Builder: ifDisabled REBUILD, ifWriteOnly CONTINUE, ifReadable CONTINUE) standing in for an unset field. READABLE_UNIQUE_PENDING is always MARK_READABLE, as in Java: the index is built and only publication remains.

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().

func (*IndexingPolicy) ShouldUsePendingWriteQueue

func (p *IndexingPolicy) ShouldUsePendingWriteQueue(index *Index) bool

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) FirstMissingRangeInBytes

func (irs *IndexingRangeSet) FirstMissingRangeInBytes(tr fdb.WritableTransaction, begin, end []byte) (*RangeSetRange, error)

FirstMissingRangeInBytes returns the first gap within [begin, end), or nil, Java's IndexingRangeSet.firstMissingRangeAsync(begin, end).

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 the gaps within [begin, end), Java's public IndexingRangeSet.listMissingRangesAsync(begin, end), kept for API parity.

type IndexingValidationError

type IndexingValidationError struct {
	Message          string
	IndexName        string
	IndexVersion     int
	IndexState       IndexState
	TargetIndexName  string
	TargetIndexState IndexState
	SourceIndexName  string
	// IndexerID is Java's INDEXER_ID log key, which the source-index validations
	// carry (validateOrThrowEx, IndexingBase.java:1171-1174); the state checks do
	// not (:203-207, :237-241), and leave it nil.
	IndexerID uuid.UUID
}

IndexingValidationError matches Java's IndexingBase.ValidationException: a session precondition failed. It carries the log keys Java attaches at each throw site: the primary index (and, for "Index state is not as expected", its last-modified version), a disagreeing follower, and a BY_INDEX build's source index. The build catcher falls back from a BY_INDEX build on it.

func (*IndexingValidationError) Error

func (e *IndexingValidationError) Error() string

func (*IndexingValidationError) JavaRecordCoreException

func (*IndexingValidationError) JavaRecordCoreException()

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

type IntersectionChildResume struct {
	Continuation []byte
	Started      bool
}

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 InvalidUTF8StringError

type InvalidUTF8StringError struct {
	Field string
}

InvalidUTF8StringError is a record whose string field holds bytes that are not valid UTF-8. Java's strings are UTF-16 and protobuf-java writes them as valid UTF-8, so Java would read these bytes back as different text and compute different index keys; the save refuses them. Field is the dotted path from the record.

func (*InvalidUTF8StringError) Error

func (e *InvalidUTF8StringError) Error() string

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 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 KeyAlgorithmReporter

type KeyAlgorithmReporter interface {
	KeyAlgorithm(keyNumber int32) (string, error)
}

KeyAlgorithmReporter is implemented by a SerializationKeyManager that knows each key's algorithm, as a Java Key carries it (KeyStoreSerializationKeyManager does). Java's AES cipher refuses a key of another algorithm when it is initialized ("Wrong algorithm: AES or Rijndael required"); a manager that does not report algorithms hands Go raw AES keys.

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. It is Java's ThenKeyExpression constructor: a child that is itself a composite contributes its children, not itself (ThenKeyExpression.add, ThenKeyExpression.java:264-271), so no composite ever holds a composite and every Then Go writes has the flat shape Java writes.

Java's list constructor refuses a Then of fewer than two children with RecordCoreException "Then must have at least 2 children" (ThenKeyExpression.java:63-65), at the call. Concat has no error channel, so it records the place of that throw in program order, and Build returns it as the first builder fault when the Then reaches the builder (keyConstructionFault). A Then built from one that was refused keeps the earlier place, as the Java program would have died there.

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 FieldWithNullStandin

func FieldWithNullStandin(name string, fanType FanType, standin NullStandin) KeyExpression

FieldWithNullStandin is Java's Key.Expressions.field(name, fanType, nullStandin).

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).

func NormalizeKeyForPositions

func NormalizeKeyForPositions(expr KeyExpression) []KeyExpression

NormalizeKeyForPositions flattens a key expression into a list of atomic components for position matching. CompositeKeyExpression is flattened recursively; NestingKeyExpression re-wraps each child; all others return themselves as a single-element list. Matches Java's KeyExpression.normalizeKeyForPositions().

type KeyExpressionDeserializationError

type KeyExpressionDeserializationError struct {
	Message string
}

KeyExpressionDeserializationError is Java's KeyExpression.DeserializationException (a RecordCoreException): a serialized key expression that cannot be read back, as one with no root or with several (KeyExpression.java:404-405), a field without its name or fan type (FieldKeyExpression.java:122-128), a nesting without its parent (NestingKeyExpression.java:69) or a then of fewer than two children (ThenKeyExpression.java:84).

func (*KeyExpressionDeserializationError) Error

func (*KeyExpressionDeserializationError) JavaRecordCoreException

func (*KeyExpressionDeserializationError) JavaRecordCoreException()

func (*KeyExpressionDeserializationError) Unwrap

Unwrap reports it as the RecordCoreError Java's exception is, so a caller matching RecordCoreError catches it as `catch (RecordCoreException)` does.

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 KeyExpressionInvalidResultError

type KeyExpressionInvalidResultError struct {
	Function     string
	Index        int
	ExpectedType string
	ActualType   string
}

KeyExpressionInvalidResultError is Java's KeyExpression.InvalidResultException as Key.Evaluated.getObject raises it for an argument of the wrong class. The fields are the exception's addLogInfo keys ("index", expected_type, actual_type).

func (*KeyExpressionInvalidResultError) Error

func (*KeyExpressionInvalidResultError) JavaRecordCoreException

func (*KeyExpressionInvalidResultError) JavaRecordCoreException()

type KeyStoreSerializationKeyManager

type KeyStoreSerializationKeyManager struct {
	// contains filtered or unexported fields
}

KeyStoreSerializationKeyManager is Java's KeyStoreSerializationKeyManager: the keys are secret-key entries of a key store file, key number i the entry named by the i-th alias, and the serialization key the default alias's number. Go reads the key store types Java's KeyStore.getInstance(File, password) detects that can hold a secret key: PKCS12 (the JDK's default, and what keytool writes) and JCEKS (jceks.go).

func (*KeyStoreSerializationKeyManager) GetCipher

func (*KeyStoreSerializationKeyManager) GetKey

func (m *KeyStoreSerializationKeyManager) GetKey(keyNumber int32) ([]byte, error)

GetKey is Java's getKey. A key that does not decrypt is Java's UnrecoverableKeyException, "cannot load key". An alias with no secret-key entry is, in Java, a null entry dereferenced (a NullPointerException) or a ClassCastException; Go reports the same "cannot load key" as a structured error rather than panicking.

func (*KeyStoreSerializationKeyManager) GetRandom

func (*KeyStoreSerializationKeyManager) GetSerializationKey

func (m *KeyStoreSerializationKeyManager) GetSerializationKey() int32

func (*KeyStoreSerializationKeyManager) KeyAlgorithm

func (m *KeyStoreSerializationKeyManager) KeyAlgorithm(keyNumber int32) (string, error)

KeyAlgorithm is the key's algorithm, the name Java's key store gives the algorithm identifier it stored with the key ("AES" for an AES key), which the cipher checks (KeyAlgorithmReporter).

type KeyStoreSerializationKeyManagerBuilder

type KeyStoreSerializationKeyManagerBuilder struct {
	// contains filtered or unexported fields
}

KeyStoreSerializationKeyManagerBuilder is Java's KeyStoreSerializationKeyManager.Builder.

func NewKeyStoreSerializationKeyManagerBuilder

func NewKeyStoreSerializationKeyManagerBuilder() *KeyStoreSerializationKeyManagerBuilder

NewKeyStoreSerializationKeyManagerBuilder is KeyStoreSerializationKeyManager.newBuilder.

func (*KeyStoreSerializationKeyManagerBuilder) Build

Build is Java's build(): load the key store (its password "" when unset), then resolve the aliases and the default key number as Java does.

func (*KeyStoreSerializationKeyManagerBuilder) SetCipherName

func (*KeyStoreSerializationKeyManagerBuilder) SetDefaultKeyEntryAlias

func (*KeyStoreSerializationKeyManagerBuilder) SetKeyEntryAliases

func (*KeyStoreSerializationKeyManagerBuilder) SetKeyEntryPassword

func (*KeyStoreSerializationKeyManagerBuilder) SetKeyStoreFileName

func (*KeyStoreSerializationKeyManagerBuilder) SetKeyStorePassword

func (*KeyStoreSerializationKeyManagerBuilder) SetRandom

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
)

func (Kind) String

func (k Kind) String() string

String renders the kind for diagnostics.

type KnobValueType

type KnobValueType string

KnobValueType is Java's FDBClientKnob.KnobValueType.

const (
	KnobValueInt     KnobValueType = "INT"
	KnobValueLong    KnobValueType = "LONG"
	KnobValueDouble  KnobValueType = "DOUBLE"
	KnobValueBoolean KnobValueType = "BOOLEAN"
	KnobValueString  KnobValueType = "STRING"
)

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

Evaluate returns the constant value regardless of the record. Matches Java's LiteralKeyExpression.evaluateMessage() which ignores the record parameter.

The value is the one the tuple layer encodes: Java's Key.Evaluated.scalar holds the literal's Integer, which Tuple packs as the integer it is, while Go's tuple encoder takes integers as int64 and refuses an int32. The literal keeps its carrier (an int32 is written as int_value, the target's width) for ToProto.

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 LocatableResolver

type LocatableResolver interface {
	// contains filtered or unexported methods
}

LocatableResolver is a scope that maps names to longs.

type LocatableResolverLockedError

type LocatableResolverLockedError struct{ Message string }

LocatableResolverLockedError is Java's LocatableResolverLockedException.

func (*LocatableResolverLockedError) Error

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
	// Cause is Java's exception cause, when the MetaDataException was built with
	// one (MetaDataException(message, cause)); Error is the message alone, as
	// Java's getMessage is.
	Cause error
}

MetaDataError is returned for metadata validation failures. Matches Java's com.apple.foundationdb.record.metadata.MetaDataException.

func (*MetaDataError) Error

func (e *MetaDataError) Error() string

func (*MetaDataError) JavaRecordCoreException

func (*MetaDataError) JavaRecordCoreException()

func (*MetaDataError) Unwrap

func (e *MetaDataError) Unwrap() []error

Unwrap reports this as the RecordCoreError Java's MetaDataException is (it extends RecordCoreException), so a caller matching RecordCoreError catches it as `catch (RecordCoreException)` does, and returns the cause, so errors.As reaches it as Java's getCause does.

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) AsBuilder

AsBuilder copies all configuration without sharing mutable option storage.

func (*MetaDataEvolutionValidator) GetIgnoredIndexOptions

func (v *MetaDataEvolutionValidator) GetIgnoredIndexOptions() []string

GetIgnoredIndexOptions returns a sorted, independent copy of the ignored names.

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 (*MetaDataEvolutionValidatorBuilder) GetIgnoredIndexOptions

func (b *MetaDataEvolutionValidatorBuilder) GetIgnoredIndexOptions() []string

GetIgnoredIndexOptions returns a sorted, independent copy of the ignored names.

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

SetAllowFieldRenames permits any field to be renamed (same field number, new name) across a metadata evolution. Matches Java's setAllowFieldRenames.

func (*MetaDataEvolutionValidatorBuilder) SetAllowIndexRebuilds

func (*MetaDataEvolutionValidatorBuilder) SetAllowMissingFormerIndexNames

func (b *MetaDataEvolutionValidatorBuilder) SetAllowMissingFormerIndexNames(v bool) *MetaDataEvolutionValidatorBuilder

func (*MetaDataEvolutionValidatorBuilder) SetAllowNoSinceVersion

func (*MetaDataEvolutionValidatorBuilder) SetAllowNoVersionChange

func (*MetaDataEvolutionValidatorBuilder) SetAllowOlderFormerIndexAddedVersion

func (b *MetaDataEvolutionValidatorBuilder) SetAllowOlderFormerIndexAddedVersion(v bool) *MetaDataEvolutionValidatorBuilder

func (*MetaDataEvolutionValidatorBuilder) SetAllowUndeprecatingFields

SetAllowUndeprecatingFields permits a field that was deprecated to become non-deprecated. Matches Java's setAllowUndeprecatingFields.

func (*MetaDataEvolutionValidatorBuilder) SetAllowUnsplitToSplit

func (*MetaDataEvolutionValidatorBuilder) SetDisallowTypeRenames

func (*MetaDataEvolutionValidatorBuilder) SetIgnoredIndexOptions

func (b *MetaDataEvolutionValidatorBuilder) SetIgnoredIndexOptions(options []string) *MetaDataEvolutionValidatorBuilder

SetIgnoredIndexOptions copies the exact, case-sensitive option names excluded from evolution validation. A nil slice clears the set.

type MetaDataProtoDeserializationError

type MetaDataProtoDeserializationError struct {
	Cause error
}

MetaDataProtoDeserializationError is Java's RecordMetaDataBuilder.MetaDataProtoDeserializationException, a MetaDataException "Error converting from protobuf" whose cause is the failure: a key expression of the meta-data proto that cannot be read (an index's root, a record type's primary key, the record-count key; a KeyExpressionDeserializationError), or the subspace-key counter settings disagreeing (RecordMetaDataBuilder.java:187-292).

func (*MetaDataProtoDeserializationError) Error

func (*MetaDataProtoDeserializationError) JavaRecordCoreException

func (*MetaDataProtoDeserializationError) JavaRecordCoreException()

func (*MetaDataProtoDeserializationError) Unwrap

Unwrap reports it as the MetaDataError Java's exception is, and its cause.

type MetaDataProtoOption

type MetaDataProtoOption func(*metaDataProtoOptions)

MetaDataProtoOption is a RecordMetaDataBuilder setting Java applies before setRecords(MetaData), for RecordMetaDataFromProto.

func WithEvolutionValidator

func WithEvolutionValidator(v *MetaDataEvolutionValidator) MetaDataProtoOption

WithEvolutionValidator is Java's RecordMetaDataBuilder.setEvolutionValidator: the validator that checks the local file descriptor against the stored one (the default instance otherwise).

func WithLocalFileDescriptor

func WithLocalFileDescriptor(local protoreflect.FileDescriptor) MetaDataProtoOption

WithLocalFileDescriptor is Java's RecordMetaDataBuilder.setLocalFileDescriptor: the loaded meta-data's record types and union take their descriptors from local (typically the compiled file), once it validates as an evolution of the stored records, so records of the compiled types can be saved. Such meta-data cannot be written back with ToProto.

type MetaDataVersionMustIncreaseError

type MetaDataVersionMustIncreaseError struct {
	OldVersion int32
	NewVersion int32
}

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 (*MetaDataVersionMustIncreaseError) JavaRecordCoreException

func (*MetaDataVersionMustIncreaseError) JavaRecordCoreException()

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

Clear removes all cached entries.

func (*MetaDataVersionStampStoreStateCache) Get

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

WithExpireAfterAccess sets the TTL for cache entries since last access. Default: 1 minute (matches Java's default).

func WithMaxSize

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) Child

Child is Java's NestingKeyExpression.getChild().

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) FanType

func (n *NestingKeyExpression) FanType() FanType

FanType is the fan type of Java's NestingKeyExpression.getParent().

func (*NestingKeyExpression) FieldNames

func (n *NestingKeyExpression) FieldNames() []string

FieldNames returns the parent field name plus child field names.

func (*NestingKeyExpression) ParentField

func (n *NestingKeyExpression) ParentField() string

ParentField is the field name of Java's NestingKeyExpression.getParent().

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 NoSuchElementError

type NoSuchElementError struct{ Message string }

NoSuchElementError is Java's NoSuchElementException.

func (*NoSuchElementError) Error

func (e *NoSuchElementError) Error() string

type NullStandin

type NullStandin uint8

NullStandin is Java's Key.Evaluated.NullStandin (Key.java:394-421).

const (
	// NullStandinNull is a null that a unique index ignores: two records whose
	// keys hold it do not collide. Java's NULL, the default, stored as
	// NOT_UNIQUE.
	NullStandinNull NullStandin = iota
	// NullStandinNullUnique is a null that a unique index does not ignore: two
	// records whose keys hold it collide. Java's NULL_UNIQUE, stored as UNIQUE.
	NullStandinNullUnique
	// NullStandinNotNull evaluates an absent field as its type's default value.
	// Java's NOT_NULL, stored as NOT_NULL. A field of a message that is itself
	// null still evaluates to null (FieldKeyExpression.java:80-89, the target's
	// issue #4141), and a unique index does not ignore it.
	NullStandinNotNull
)

type NumberFormatError

type NumberFormatError struct {
	// Input is the value Integer.parseInt or Double.parseDouble refused
	// (Double.parseDouble's trimmed).
	Input string
	// Text, when set, is the exception's own message instead of
	// forInputString's: Double.parseDouble's "empty String" for a value that
	// trims to nothing and "multiple points" for a second decimal point in the
	// significand (FloatingDecimal.readJavaFormatString).
	Text string
}

NumberFormatError is Java's NumberFormatException, raised by Integer.parseInt on an index option that is not a decimal int. Java's class extends IllegalArgumentException, so errors.As matches it as an *IllegalArgumentError too.

func (*NumberFormatError) As

func (e *NumberFormatError) As(target any) bool

As lets errors.As match a NumberFormatError as the IllegalArgumentError its Java class extends.

func (*NumberFormatError) Error

func (e *NumberFormatError) Error() string

Error is NumberFormatException.forInputString's text for radix 10, or Text.

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

func (oi *OnlineIndexer) BlockIndex(ctx context.Context, blockID string, ttl time.Duration) error

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 index build and returns the number of records scanned. Matches Java's OnlineIndexer.buildIndex: every attempt resolves the session against the primary index's state, which may build (and then publish), only publish, or leave a READABLE index alone, and a failed attempt goes to indexingCatcher, which may retry it by another method.

The count is every record scanned by every attempt, a retried one included. LastBuildOutcome reports what the call did.

func (*OnlineIndexer) CheckAnyOngoingOnlineIndexBuilds

func (oi *OnlineIndexer) CheckAnyOngoingOnlineIndexBuilds(ctx context.Context) (bool, error)

CheckAnyOngoingOnlineIndexBuilds reports whether the primary target index has a session heartbeat younger than this indexer's lease. Matches Java's OnlineIndexer.checkAnyOngoingOnlineIndexBuilds() (OnlineIndexer.java:426-438), with the documented-contract divergence described on the package-level function.

func (*OnlineIndexer) ClearIndexingHeartbeats

func (oi *OnlineIndexer) ClearIndexingHeartbeats(ctx context.Context, minAgeMs int64, maxIteration int) (int, error)

ClearIndexingHeartbeats clears the primary target index's heartbeats older than minAgeMs (and invalid ones), examining at most maxIteration when positive, and returns how many it cleared. Matches Java's OnlineIndexer.clearIndexingHeartbeats (IndexingBase.java:1240-1243).

func (*OnlineIndexer) GetIndexingHeartbeats

func (oi *OnlineIndexer) GetIndexingHeartbeats(ctx context.Context, maxCount int) (map[uuid.UUID]*gen.IndexBuildHeartbeat, error)

GetIndexingHeartbeats reads the primary target index's session heartbeats in one transaction. Matches Java's OnlineIndexer.getIndexingHeartbeats(maxCount) (IndexingBase.java:1235-1238).

func (*OnlineIndexer) LastBuildOutcome

func (oi *OnlineIndexer) LastBuildOutcome() IndexBuildOutcome

LastBuildOutcome reports what the last BuildIndex call did, over all of its attempts, when it returned no error; IndexBuildOutcomeNone before any call, and after a call that failed, whatever an earlier call of the same indexer did.

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) MergeIndexes

func (oi *OnlineIndexer) MergeIndexes(ctx context.Context) error

MergeIndexes explicitly runs deferred maintenance for all configured targets. Synchronous maintainers report no work; this does not substitute for a backend adapter capable of performing real deferred work. Like Java's mergeIndex it holds no session: no heartbeat, no index-state check.

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. Matches Java's OnlineIndexer.Builder.addTargetIndex(), which checks nothing.

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

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) SetIncreaseLimitAfter

func (b *OnlineIndexerBuilder) SetIncreaseLimitAfter(n int) *OnlineIndexerBuilder

SetIncreaseLimitAfter is Java's setIncreaseLimitAfter: the consecutive successful transactions after which a lowered limit re-increases toward the limit.

func (*OnlineIndexerBuilder) SetIndex

func (b *OnlineIndexerBuilder) SetIndex(index *Index) *OnlineIndexerBuilder

SetIndex adds the index to build, as Java's setIndex does (OnlineIndexer.java:668-676): it is refused when targets are already set ("setIndex may not be used when other target indexes are already set", an IndexingValidationError that Build returns), a nil index is skipped (Build then reports "index must be set"), and nothing stops AddTargetIndex after it.

func (*OnlineIndexerBuilder) SetIndexMaintenanceFilter

func (b *OnlineIndexerBuilder) SetIndexMaintenanceFilter(filter IndexMaintenanceFilter) *OnlineIndexerBuilder

SetIndexMaintenanceFilter sets the IndexMaintenanceFilter of the stores the indexer opens, mirroring StoreBuilder.SetIndexMaintenanceFilter; Java reads it off the caller's record-store builder (IndexingCommon.getRecordStoreBuilder).

func (*OnlineIndexerBuilder) SetInitialLimit

func (b *OnlineIndexerBuilder) SetInitialLimit(limit int) *OnlineIndexerBuilder

SetInitialLimit is Java's setInitialLimit: the per-transaction record limit a build starts at, at most the limit; 0 starts at the limit.

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 Java's 10000 (defaultLeaseLengthMs). 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) SetMaxAttempts

func (b *OnlineIndexerBuilder) SetMaxAttempts(maxAttempts int) *OnlineIndexerBuilder

SetMaxAttempts sets how many attempts each of the indexer's transactions makes, as Java's OnlineIndexOperationBaseBuilder.setMaxAttempts sets its runner's (default: the database's, 10). The lessen-work retries of SetMaxRetries run over each attempt-bounded transaction.

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) SetMaxWriteLimitBytes

func (b *OnlineIndexerBuilder) SetMaxWriteLimitBytes(n int64) *OnlineIndexerBuilder

SetMaxWriteLimitBytes is Java's setMaxWriteLimitBytes: a range commits once its transaction's approximate size passes this many bytes (default 900,000; 0 or less disables the check).

func (*OnlineIndexerBuilder) SetMetaData

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 boundaries are the primary keys at the shard boundaries of the indexed records (GetPrimaryKeyBoundaries). Matches Java's OnlineIndexer.Builder.setMutualIndexingBoundaries().

func (*OnlineIndexerBuilder) SetPolicy

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) SetRecordStore

func (b *OnlineIndexerBuilder) SetRecordStore(store *FDBRecordStore) *OnlineIndexerBuilder

SetRecordStore is Java's setRecordStore (OnlineIndexOperationBaseBuilder.java: 138-143): the store as a template, SetRecordStoreBuilder(store.AsBuilder()), which carries the store's format version, and, when no database is set, the database of the store's context, as Java takes its runner from it.

func (*OnlineIndexerBuilder) SetRecordStoreBuilder

func (b *OnlineIndexerBuilder) SetRecordStoreBuilder(builder *StoreBuilder) *OnlineIndexerBuilder

SetRecordStoreBuilder is Java's OnlineIndexOperationBaseBuilder.setRecordStoreBuilder: the indexer opens every store through a copy of builder's configuration (copyBuilder), in its own transaction (the builder's context is dropped), so the stores carry the caller's configuration, the serializer included. The builder's metadata, subspace, format version and maintenance filter become the indexer's (a later setter overrides them). When no database is set, the indexer takes the builder's, else that of the builder's context, as Java takes its runner from recordStoreBuilder.getContext() (OnlineIndexOperationBaseBuilder.java:124-128).

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. Build refuses it with several targets or a mutual policy. Everything else about it is checked when BuildIndex runs, as Java checks it: the source must be a scannable VALUE index on the target's one record type whose root expression creates no duplicates, and a source that is not is answered by the build catcher with a records-scan fallback (or an IndexingValidationError under IndexingPolicy.ForbidRecordScan). Matches Java's OnlineIndexer.Builder.setSourceIndex().

func (*OnlineIndexerBuilder) SetSubspace

SetSubspace sets the store subspace.

func (*OnlineIndexerBuilder) SetTargetIndexes

func (b *OnlineIndexerBuilder) SetTargetIndexes(indexes []*Index) *OnlineIndexerBuilder

SetTargetIndexes replaces the target list. Matches Java's OnlineIndexer.Builder.setTargetIndexes().

func (*OnlineIndexerBuilder) SetTimeLimit

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().

func (*OnlineIndexerBuilder) SetTransactionTimeLimitMilliseconds

func (b *OnlineIndexerBuilder) SetTransactionTimeLimitMilliseconds(ms int64) *OnlineIndexerBuilder

SetTransactionTimeLimitMilliseconds is Java's setTransactionTimeLimitMilliseconds: a range commits once its transaction is older than this (default 4,000 ms; 0 or less disables the check).

type OrderDirection

type OrderDirection = tupleordering.Direction

OrderDirection specifies how tuple values are encoded for ordered storage. Matches Java's TupleOrdering.Direction enum.

type OrderedStreamScanner

type OrderedStreamScanner interface {
	ScanByDistanceOrderedStream(TupleRange, []byte, ScanProperties) RecordCursor[*IndexEntry]
}

OrderedStreamScanner is the RFC-156 Phase C distance-ordered STREAMING scan (demand-driven widening + budget-bounded honest truncation). Same TupleRange/ IndexEntry contract as ScanByDistance; only partition indices with a widenable posting structure (SPFresh) implement it — others use the ScanByDistance fixed-horizon fallback.

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
	// Saved and Expected are the stamps themselves (Java getSavedStamp and
	// getExpectedStamp). The build catcher resumes the saved stamp's method.
	Saved    *gen.IndexBuildIndexingStamp
	Expected *gen.IndexBuildIndexingStamp
	// IndexerID is the refusing indexer's identity, Java's INDEXER_ID log key
	// (IndexingBase.java:604, :1011-1012).
	IndexerID uuid.UUID
	// IndexVersion is the index's last-modified version, Java's INDEX_VERSION
	// log key (IndexingBase.java:1291).
	IndexVersion int
}

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

func (*PartlyBuiltError) JavaRecordCoreException

func (*PartlyBuiltError) JavaRecordCoreException()

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

Clear is a no-op.

func (*PassThroughRecordStoreStateCache) Get

Get always loads fresh state from FDB. Skips the metadata version stamp read since PassThrough has no cache to validate against.

type PendingRead

type PendingRead[V any] interface {
	Get() (V, error)
	IsReady() bool
}

PendingRead is an issued read. Get waits for and returns its result, once; IsReady reports that Get would not wait.

func MapPendingRead

func MapPendingRead[T, V any](p PendingRead[T], f func(T, error) (V, error)) PendingRead[V]

MapPendingRead applies f to p's result when it is read.

func NewPendingRead

func NewPendingRead[V any](get func() (V, error), ready func() bool) PendingRead[V]

NewPendingRead wraps get; a nil ready means the result never waits.

type PendingWriteQueueOptions

type PendingWriteQueueOptions struct {
	MaximumSize            int64
	DisableIndexOnOverflow bool
}

PendingWriteQueueOptions corresponds to the context's Java pending queue properties. A nonpositive maximum disables the capacity check.

type PendingWritesQueue

type PendingWritesQueue[T proto.Message] struct {
	// contains filtered or unexported fields
}

PendingWritesQueue stores Java-compatible, versionstamped protobuf payloads. Entry and counter subspaces must be disjoint. Capacity is deliberately soft: snapshot checks do not serialize concurrent producers.

func NewPendingWritesQueue

func NewPendingWritesQueue[T proto.Message](entries, counter subspace.Subspace, maximum int64, prototype T) *PendingWritesQueue[T]

func (*PendingWritesQueue[T]) ClearEntry

func (q *PendingWritesQueue[T]) ClearEntry(rc *FDBRecordContext, entry *PendingWritesQueueEntry[T]) error

func (*PendingWritesQueue[T]) Enqueue

func (q *PendingWritesQueue[T]) Enqueue(rc *FDBRecordContext, payload T, incarnation int32) error

func (*PendingWritesQueue[T]) GetQueueCursor

func (q *PendingWritesQueue[T]) GetQueueCursor(rc *FDBRecordContext, props ScanProperties, continuation []byte) RecordCursor[*PendingWritesQueueEntry[T]]

func (*PendingWritesQueue[T]) GetQueueSizeNoConflict

func (q *PendingWritesQueue[T]) GetQueueSizeNoConflict(rc *FDBRecordContext) (*int64, error)

func (*PendingWritesQueue[T]) IsQueueEmpty

func (q *PendingWritesQueue[T]) IsQueueEmpty(rc *FDBRecordContext) (bool, error)

type PendingWritesQueueEntry

type PendingWritesQueueEntry[T proto.Message] struct {
	Key              tuple.Tuple
	Payload          T
	PayloadTypeURL   string
	EnqueueTimestamp int64
}

type PendingWritesQueueTooLargeError

type PendingWritesQueueTooLargeError struct{ CurrentSize, MaxQueueSize int64 }

PendingWritesQueueTooLargeError matches Java's queue capacity exception.

func (*PendingWritesQueueTooLargeError) Error

type PostCommitFunc

type PostCommitFunc func()

PostCommitFunc is a callback that runs after a successful commit. Matches Java's PostCommit interface.

type QueryInvalidExpressionError

type QueryInvalidExpressionError struct {
	Message string
}

QueryInvalidExpressionError is Java's com.apple.foundationdb.record.query.expressions.Query.InvalidExpressionException, an IllegalStateException (Query.java:273), not a RecordCoreException and not KeyExpression's: key validation raises it for a message field read as a scalar.

func (*QueryInvalidExpressionError) Error

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

func NewRangeSet(ss subspace.Subspace) *RangeSet

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

func (rs *RangeSet) Contains(tr fdb.WritableTransaction, key []byte) (bool, error)

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

type RangeSetInvertedRangeError struct {
	Begin []byte
	End   []byte
}

RangeSetInvertedRangeError is returned when begin > end in a range operation.

func (*RangeSetInvertedRangeError) Error

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

type RangeSetRange struct {
	Begin []byte
	End   []byte
}

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 RankScanBounds

type RankScanBounds struct {
	ScanType           IndexScanType
	RankRange          TupleRange
	IncludeRankAsValue bool
}

RankScanBounds selects score or rank bounds and optionally returns each entry's absolute rank in its value. Matches Java's RankScanBounds.

func NewRankScanBounds

func NewRankScanBounds(scanType IndexScanType, rankRange TupleRange, includeRankAsValue bool) (RankScanBounds, error)

NewRankScanBounds accepts only BY_VALUE and BY_RANK, even without rank values.

type ReadRunner

type ReadRunner interface {
	RunRead(ctx context.Context, fn func(fdb.ReadTransaction) (any, error)) (any, error)
}

ReadRunner runs a read-only body with retries: an *FDBDatabase, or a caller's runner that configures each transaction (timeout, tags) first.

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

func (*RecordAlreadyExistsError) JavaRecordCoreException

func (*RecordAlreadyExistsError) JavaRecordCoreException()

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 (Go-only): past it, a save or delete logs and counts
	// CountTransactionSizeWarning once per transaction, and still succeeds. Zero disables it.
	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 RecordContextNotActiveError

type RecordContextNotActiveError struct{ Message string }

RecordContextNotActiveError is Java's RecordContextNotActiveException, a RecordCoreStorageException: the context's transaction is no longer active. A context is deactivated by its commit whatever the outcome, and a context a transaction route (FDBDatabase.Run and its variants, the runner) hands its body is the route's to commit, so a commit there is refused before anything commits. errors.As finds it as itself and as a *RecordCoreStorageError.

func (*RecordContextNotActiveError) Error

func (*RecordContextNotActiveError) JavaRecordCoreException

func (*RecordContextNotActiveError) JavaRecordCoreException()

func (*RecordContextNotActiveError) Unwrap

func (e *RecordContextNotActiveError) Unwrap() error

Unwrap exposes the RecordCoreStorageException superclass.

type RecordCoreArgumentError

type RecordCoreArgumentError struct {
	Message   string
	ScanType  IndexScanType
	IndexName string
	// SubspaceKey is the offending subspace key of a subspace-key refusal
	// (Index.normalizeSubspaceKey, FormerIndex's constructor;
	// LogMessageKeys.SUBSPACE_KEY), and HasSubspaceKey says the site attached
	// one: the offending key is often nil, so nil cannot mean "not attached".
	SubspaceKey    any
	HasSubspaceKey bool
	// Plan is the refused plan's class name (LogMessageKeys.PLAN).
	Plan string
	// ClientKnobName, ClientKnobValue and Expected are a refused client knob's
	// log keys (CLIENT_KNOB_NAME, CLIENT_KNOB_VALUE, EXPECTED).
	ClientKnobName  string
	ClientKnobValue string
	Expected        string
	// Cause is the exception Java's constructor chains (the key store's
	// IOException / GeneralSecurityException in KeyStoreSerializationKeyManager).
	Cause error
}

RecordCoreArgumentError reports an invalid argument with its context. Matches Java's RecordCoreArgumentException; the fields are the log keys the raising sites attach (SCAN_TYPE, INDEX_NAME, SUBSPACE_KEY).

func (*RecordCoreArgumentError) Error

func (e *RecordCoreArgumentError) Error() string

Error renders the message and, in parentheses, only the fields its site set.

func (*RecordCoreArgumentError) JavaRecordCoreException

func (*RecordCoreArgumentError) JavaRecordCoreException()

func (*RecordCoreArgumentError) Unwrap

func (e *RecordCoreArgumentError) Unwrap() error

Unwrap exposes the chained cause to errors.Is / errors.As.

type RecordCoreError

type RecordCoreError struct {
	IndexOption string
	Message     string
	IndexName   string
	Cause       error
}

RecordCoreError carries Java's base RecordCoreException diagnostics and cause.

func (*RecordCoreError) Error

func (e *RecordCoreError) Error() string

func (*RecordCoreError) JavaRecordCoreException

func (*RecordCoreError) JavaRecordCoreException()

func (*RecordCoreError) Unwrap

func (e *RecordCoreError) Unwrap() error

type RecordCoreException

type RecordCoreException interface {
	error
	JavaRecordCoreException()
}

RecordCoreException is implemented by every error type porting a Java RecordCoreException subclass. The relational layer gives one that none of its specific arms claims ErrorCode.UNKNOWN, as ExceptionUtil does.

type RecordCoreInternalError

type RecordCoreInternalError struct {
	Message string
}

RecordCoreInternalError reports an internal invariant violation, matching Java's RecordCoreInternalException.

func (*RecordCoreInternalError) Error

func (e *RecordCoreInternalError) Error() string

func (*RecordCoreInternalError) JavaRecordCoreException

func (*RecordCoreInternalError) JavaRecordCoreException()

type RecordCoreRetriableTransactionError

type RecordCoreRetriableTransactionError struct {
	Message string
	Cause   error
}

RecordCoreRetriableTransactionError is Java's RecordCoreRetriableTransactionException: a failure the transaction runner retries like a retryable FDB error.

func (*RecordCoreRetriableTransactionError) Error

func (*RecordCoreRetriableTransactionError) JavaRecordCoreException

func (*RecordCoreRetriableTransactionError) JavaRecordCoreException()

func (*RecordCoreRetriableTransactionError) Unwrap

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
	KeyTuple      tuple.Tuple // LogMessageKeys.KEY_TUPLE
	Version       *int32      // LogMessageKeys.VERSION (reader version)
	StoredVersion *int32      // LogMessageKeys.STORED_VERSION
	ExpectedType  string      // Bound protobuf full name, the language-independent message identity
	ActualType    string      // LogMessageKeys.ACTUAL_TYPE (stored Any type URL)
	Cause         error       // the exception's cause, e.g. the store header's parse error
}

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

func (*RecordCoreStorageError) JavaRecordCoreException

func (*RecordCoreStorageError) JavaRecordCoreException()

func (*RecordCoreStorageError) Unwrap

func (e *RecordCoreStorageError) Unwrap() error

Unwrap returns the cause.

type RecordCountKeySizeMismatchError

type RecordCountKeySizeMismatchError struct {
	KeyColumnSize int
	ValueSize     int
}

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

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 must produce non-nil bytes for every generated value; a missing encoder or nil encoding causes OnNext to fail rather than emit an unusable position. encode/decode serialize/deserialize values for continuations. Only a nil continuation starts a fresh cursor; a non-nil continuation requires a decoder that returns true. Decoding failures are returned by OnNext without calling the generator. 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 FilterCursor

func FilterCursor[T any](inner RecordCursor[T], predicate func(T) bool) RecordCursor[T]

FilterCursor is Java's RecordCursor.filter: the elements of inner that satisfy predicate.

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 MapPipelined

func MapPipelined[T, V any](inner RecordCursor[T], issue func(T) PendingRead[V], pipelineSize int) RecordCursor[V]

MapPipelined keeps up to pipelineSize mappings issued, counting the one being returned, and yields them in source order with their source continuations. It runs on the caller's goroutine; the overlap comes from reads in flight. Matches Java's post-insertion head-readiness ordering; the synchronous source cannot race a pending source advance against completion of a mapping.

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 NewErrorCursor

func NewErrorCursor[T any](err error) RecordCursor[T]

NewErrorCursor is a cursor whose every OnNext fails with err: a scan that cannot start.

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 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 (*RecordDeserializationError) JavaRecordCoreException

func (*RecordDeserializationError) JavaRecordCoreException()

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

func (*RecordDoesNotExistError) JavaRecordCoreException

func (*RecordDoesNotExistError) JavaRecordCoreException()

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 (*RecordIndexUniquenessViolationError) JavaRecordCoreException

func (*RecordIndexUniquenessViolationError) JavaRecordCoreException()

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, opts ...MetaDataProtoOption) (*RecordMetaData, error)

RecordMetaDataFromProto deserializes a MetaData proto back into a RecordMetaData. Matches Java's RecordMetaDataBuilder.loadFromProto(), with opts the builder settings Java applies first (WithLocalFileDescriptor).

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: the stored records file even under WithLocalFileDescriptor, as Java's getRecordsDescriptor (RecordMetaDataBuilder.java:275).

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. Java's RecordMetaData.getIndexFromSubspaceKey (RecordMetaData.java:329-336) compares each index's normalized key with the ARGUMENT AS GIVEN by equals. Go normalizes the argument too (subspaceKeyIdentity), so two arguments differ from Java's: an int argument finds an index whose key is int64, where Java's Integer argument misses a Long key, and a tuple argument finds an index whose key is the same list, where Java's Tuple argument never equals a List key. The second is reached by the one non-test caller, savedSourceIndex, which passes a decoded stamp item as Java's OnlineIndexer passes Index.decodeSubspaceKey's (OnlineIndexer.java:205-208): for a source index keyed by a nested tuple Java fails the BY_INDEX resume with an unknown key and Go resumes from the index the stamp names (DIVERGENCES.md, "BY_INDEX resume over a nested-tuple source key"). Java throws MetaDataException on a miss; Go returns nil.

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) GetIndexesSince

func (m *RecordMetaData) GetIndexesSince(version int) []*Index

GetIndexesSince returns all indexes modified since the given metadata version, including replaced originals whose state still needs reconciliation. Matches Java's RecordMetaData.getIndexesSince(int).

func (*RecordMetaData) GetIndexesToBuildSince

func (m *RecordMetaData) GetIndexesToBuildSince(version int) []*Index

GetIndexesToBuildSince excludes replaced originals from changed indexes. 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) GetRecordTypeForDescriptor

func (m *RecordMetaData) GetRecordTypeForDescriptor(descriptor protoreflect.MessageDescriptor) (*RecordType, error)

GetRecordTypeForDescriptor is Java's RecordMetaData.getRecordTypeForDescriptor (RecordMetaData.java:219-223): the record type of descriptor's name, which must hold that very descriptor; a same-named message of another descriptor (a compiled type over loaded meta-data, without WithLocalFileDescriptor) is not it.

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 records file's union message (never nil on a built RecordMetaData: a records file without one is refused). 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. Every record type of a built RecordMetaData is a union field (validateRecordUnion refuses a RECORD-usage message that is not), so this is nil only for a record type the metadata does not hold. 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.

It returns the live map, not a copy. Build derives ambiguousNames from the map's key set, so changing keys after Build leaves AmbiguousDeclaredNames describing the set Build saw. Constructing a RecordMetaData literal bypasses that derivation entirely; copying here would not protect direct field writes.

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).

The types come in name order, so a caller reporting the first of them that violates something names the same one on every run.

func (*RecordMetaData) StoredQueries

func (m *RecordMetaData) StoredQueries() []*gen.PStoredQuery

StoredQueries returns the stored queries (MetaData field 16).

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:

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
16  stored_queries

Carried is not supported. The port does not model synthetic record types, user-defined functions, views or stored queries; 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.

Fields 12-16 are not covered by unknown-field preservation either, for the opposite reason: they are declared fields of a message this code parses, so they are never unknown. Both halves of the message need explicit carrying.

func (*RecordMetaData) UserDefinedFunctions

func (m *RecordMetaData) UserDefinedFunctions() []*gen.PUserDefinedFunction

UserDefinedFunctions returns the schema's SQL functions (MetaData field 14).

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

func (*RecordMetaData) Views

func (m *RecordMetaData) Views() []*gen.PView

Views returns the schema's SQL views (MetaData field 15), in stored order.

func (*RecordMetaData) WithUserDefinedFunctions

func (m *RecordMetaData) WithUserDefinedFunctions(fns []*gen.PUserDefinedFunction) *RecordMetaData

WithUserDefinedFunctions is m with fns added, each replacing a function of its name: the schema as a transaction that declared temporary functions sees it.

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) AddStoredQuery

AddStoredQuery appends a stored query (MetaData field 16).

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) AddUserDefinedFunction

func (b *RecordMetaDataBuilder) AddUserDefinedFunction(fn *gen.PUserDefinedFunction) *RecordMetaDataBuilder

AddUserDefinedFunction appends a SQL function.

func (*RecordMetaDataBuilder) AddView

func (b *RecordMetaDataBuilder) AddView(name, definition string) *RecordMetaDataBuilder

AddView appends a SQL view (name and query text), as Java's RecordLayerView.asRawView.

func (*RecordMetaDataBuilder) Build

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. 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.

A name no record type has is Java's MetaDataException "Unknown record type <name>" (RecordMetaDataBuilder.java:986-996), thrown at the call. Go records it in program order, as every builder fault is, for Build to return, and hands back a builder over a record type the meta-data does not hold, so a chained setter changes nothing.

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), including its refusal of a name no index has (RecordMetaDataBuilder.java:1199-1203), which Go records in program order for Build to return, as every builder fault is.

func (*RecordMetaDataBuilder) SetDependenciesSourceProtos

func (b *RecordMetaDataBuilder) SetDependenciesSourceProtos(files []*descriptorpb.FileDescriptorProto) *RecordMetaDataBuilder

SetDependenciesSourceProtos retains original imported descriptors for serialization. Only transitive dependencies of the records descriptor are emitted.

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

SetRecords sets the protobuf file descriptor containing record definitions. The union is found as Java's setRecords finds it (fetchUnionDescriptor: the one message with (record).usage = UNION, else the one named RecordTypeUnion).

func (*RecordMetaDataBuilder) SetRecordsSourceProto

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 for a caller that names the union message it expects. The union is still found as Java finds it (fetchUnionDescriptor: the one message with (record).usage = UNION, else the one named RecordTypeUnion), and a name that differs from the one found is refused: metadata built around any other message would be refused by this same binary when it is loaded back (RecordMetaDataFromProto runs the same search), and by the target. An empty name names no union and is refused: it would otherwise accept whatever union the search finds, which is SetRecords.

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 controls automatic version assignment under DEFAULT. Per-save behaviors and supplied versions override this metadata setting.

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 {
	Message string
	Cause   error
	// RetryCount and RetryResult are the log keys Java's
	// decryptAndDecompressWithRetries adds to a read's failure: the configured
	// reattempt count and "failure" when every attempt failed, or the attempt
	// that succeeded and "success" when failOnDeserializeReattempt refuses a
	// reattempt's success. RetryResult is "" on every other error.
	RetryCount  int
	RetryResult string
	// MetaDataVersion is the reading store's metadata version on a refused
	// reattempt (Java's META_DATA_VERSION log key), when a store read it.
	MetaDataVersion int
	// contains filtered or unexported fields
}

RecordSerializationError is Java's com.apple.foundationdb.record.provider.common.RecordSerializationException: a record's bytes could not be produced, or a transformation's could not be read back (a compression, encryption or prefix failure on either path). Message is the exception's message; one with only a cause (a protobuf marshal failure, Java's RecordSerializationException(Throwable)) renders as "failed to serialize record".

func (*RecordSerializationError) Error

func (e *RecordSerializationError) Error() string

func (*RecordSerializationError) JavaRecordCoreException

func (*RecordSerializationError) JavaRecordCoreException()

func (*RecordSerializationError) Unwrap

func (e *RecordSerializationError) Unwrap() error

type RecordSerializationValidationError

type RecordSerializationValidationError struct {
	Message    string
	RecordType string
	PrimaryKey tuple.Tuple
	Cause      error
}

RecordSerializationValidationError is Java's com.apple.foundationdb.record.provider.common.RecordSerializationValidationException: a sampled write-time validation found a record's stored bytes would not read back as the record ("cannot deserialize record", "record serialization mismatch") or its encryption would not decrypt to its input ("encryption validation error: ..."). Like Java's, it is a RecordCoreException and not a RecordSerializationException. RecordType and PrimaryKey are its log keys.

func (*RecordSerializationValidationError) Error

func (*RecordSerializationValidationError) JavaRecordCoreException

func (*RecordSerializationValidationError) JavaRecordCoreException()

func (*RecordSerializationValidationError) Unwrap

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 (*RecordStoreAlreadyExistsError) JavaRecordCoreException

func (*RecordStoreAlreadyExistsError) JavaRecordCoreException()

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 (*RecordStoreDoesNotExistError) JavaRecordCoreException

func (*RecordStoreDoesNotExistError) JavaRecordCoreException()

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 (*RecordStoreNoInfoButNotEmptyError) JavaRecordCoreException

func (*RecordStoreNoInfoButNotEmptyError) JavaRecordCoreException()

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 (*RecordStoreStateNotLoadedError) JavaRecordCoreException

func (*RecordStoreStateNotLoadedError) JavaRecordCoreException()

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, refusing declared version columns as Java does.

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

func (*RecordTypeChangedError) JavaRecordCoreException

func (*RecordTypeChangedError) JavaRecordCoreException()

type RecordTypeKeyExpression

type RecordTypeKeyExpression struct{}

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 is 1, Java's getColumnSize.

func (*RecordTypeKeyExpression) Evaluate

func (r *RecordTypeKeyExpression) Evaluate(record *FDBStoredRecord[proto.Message], msg proto.Message) ([][]any, error)

Evaluate returns the record type key (integer). 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.

func (*RecordTypeKeyExpression) EvaluateScalar

func (r *RecordTypeKeyExpression) EvaluateScalar(record *FDBStoredRecord[proto.Message], msg proto.Message) (any, error)

EvaluateScalar returns the type key directly — zero alloc.

func (*RecordTypeKeyExpression) FieldNames

func (r *RecordTypeKeyExpression) FieldNames() []string

FieldNames returns no field names: the record type key reads no field.

func (*RecordTypeKeyExpression) Nest

Nest is Concat(RecordTypeKey(), expr), Java's concat(recordType(), expr). Java's RecordTypeKeyExpression has no children, so this is a Go spelling of that Then, not a second shape: it builds the Then (flattened as Concat flattens) and leaves the receiver unchanged.

func (*RecordTypeKeyExpression) PackDirect

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.

func (*RecordTypeKeyExpression) ToKeyExpression

func (r *RecordTypeKeyExpression) ToKeyExpression() *gen.KeyExpression

ToKeyExpression serializes a RecordTypeKeyExpression to proto.

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

func (*RecordTypeKeyTypeError) JavaRecordCoreException

func (*RecordTypeKeyTypeError) JavaRecordCoreException()

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

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 RemoteFetchIndexMaintainer

type RemoteFetchIndexMaintainer interface {
	RemoteFetchMapper(scanType IndexScanType, commonPrimaryKeyLength int) (tuple.Tuple, error)
}

RemoteFetchIndexMaintainer is the optional form of Java's IndexMaintainer.scanRemoteFetch. The maintainer checks the scan and supplies the mapper, as StandardIndexMaintainer.scanRemoteFetchByValue does before it builds its cursor; the store issues the mapped read. A maintainer without it has Java's default, which throws UnsupportedRemoteFetchIndexException.

type ResolverResult

type ResolverResult struct {
	Value    int64
	Metadata []byte
}

ResolverResult is Java's ResolverResult: the mapped value and the metadata stored with it.

func ReadInTransaction

func ReadInTransaction(rctx *FDBRecordContext, r LocatableResolver, name string) (ResolverResult, bool, error)

ReadInTransaction is LocatableResolver.readInTransaction: the cached or stored mapping, read in the caller's transaction, never created. ok is false when the name has no mapping.

func ResolveWithMetadata

func ResolveWithMetadata(rctx *FDBRecordContext, r LocatableResolver, name string) (ResolverResult, error)

ResolveWithMetadata is LocatableResolver.resolveWithMetadata: the cached mapping, else the stored one, else a new one, read and created in a child transaction that commits on its own (runAsyncBorrowingReadVersion), so the mapping survives the caller's rollback. Without a database (a context over an external transaction) it resolves in the caller's transaction.

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 RunnerClosedError

type RunnerClosedError struct{}

RunnerClosedError corresponds to FDBDatabaseRunner.RunnerClosed.

func (*RunnerClosedError) Error

func (*RunnerClosedError) Error() string

func (*RunnerClosedError) JavaRecordCoreException

func (*RunnerClosedError) JavaRecordCoreException()

type SPFreshSealedPosting

type SPFreshSealedPosting struct {
	CellID, PostingID, Epoch int64
}

SPFreshSealedPosting names a posting an SPFresh write found SEALED.

type SPFreshSplitWindowError

type SPFreshSplitWindowError struct {
	Sealed []SPFreshSealedPosting
}

SPFreshSplitWindowError is the retryable conflict an SPFresh foreground write raises when every posting its routing reaches is SEALED by a split in progress. It wraps not_committed (1020), so every owner and the SQL mapping read it as a retryable conflict, but the attempt loop retries it without counting an attempt: the write re-runs until the split publishes (RFC-094 §6), bounded by the caller's context.

func (*SPFreshSplitWindowError) Error

func (e *SPFreshSplitWindowError) Error() string

func (*SPFreshSplitWindowError) Unwrap

func (e *SPFreshSplitWindowError) Unwrap() error

type SPFreshStalledSealError

type SPFreshStalledSealError struct {
	Sealed  []SPFreshSealedPosting
	Retries int
}

SPFreshStalledSealError fails a call whose SPFresh write met the same sealed postings on spfreshStalledSealBound consecutive retries under a simulated environment, where no second actor can take the stalled lease over. It is not retriable, so a simulation that stalls a seal fails instead of hanging.

func (*SPFreshStalledSealError) Error

func (e *SPFreshStalledSealError) Error() string

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

func (*ScanLimitReachedError) JavaRecordCoreException

func (*ScanLimitReachedError) JavaRecordCoreException()

type ScanLimiterState

type ScanLimiterState struct {
	// contains filtered or unexported fields
}

ScanLimiterState shares Java ExecuteState's scan/byte budgets and a transaction-anchored time limit. Property copies must retain it: separate IN-join/IN-union leg budgets can overrun the transaction's limit.

Auto-commit pages/retries get fresh state; explicit transactions share it at the read-version instant. Without ExecuteProperties.ScanState each leaf has private state.

Byte charges may complete on record-read workers. Other fields remain owned by the single-threaded executor; this does not permit concurrent cursor use.

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 without resetting records/bytes counters; explicit transactions use the read-version instant. Nil receivers and zero t are ignored.

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 current time-budget anchor, or zero for a nil receiver. Use Elapsed for limit checks so the anchor and measurement use the same clock.

func (*ScanLimiterState) WaitForIssuedRecordLoadCharges

func (s *ScanLimiterState) WaitForIssuedRecordLoadCharges()

WaitForIssuedRecordLoadCharges waits for already-issued raw record reads and their byte accounting, not deserialization or separate legacy-version reads. Stop issuing loads before calling this; issuance must not overlap the wait. The transaction must remain open until its outstanding reads complete.

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 ScopedInterningLayer

type ScopedInterningLayer struct {
	// contains filtered or unexported fields
}

ScopedInterningLayer is Java's ScopedInterningLayer over a resolved path: its StringInterningLayer keeps the counters at base/0, the reverse mapping (the allocator's allocation subspace) at base/1, the mapping at base/2, and the resolver state at base/-10.

func NewScopedInterningLayer

func NewScopedInterningLayer(base subspace.Subspace) *ScopedInterningLayer

NewScopedInterningLayer is the interning layer scoped to the path whose resolved subspace is base.

type SerializationKeyManager

type SerializationKeyManager interface {
	GetSerializationKey() int32
	GetKey(keyNumber int32) ([]byte, error)
	GetCipher(keyNumber int32) (string, error)
	GetRandom(keyNumber int32) (io.Reader, error)
}

SerializationKeyManager is Java's SerializationKeyManager: the key number a record is written with, and per key number the key, the cipher name and the random source the IV is drawn from. A nil random source (Java always has a SecureRandom) is the writing store's randomness: its DST env's, crypto/rand in production, so a seeded simulation replays the IV like every other persisted random byte.

type SlidingWindowCorruptionError

type SlidingWindowCorruptionError struct {
	IndexName string
	Message   string
}

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 (*SlidingWindowCorruptionError) JavaRecordCoreException

func (*SlidingWindowCorruptionError) JavaRecordCoreException()

type SlidingWindowDeleteWhereError

type SlidingWindowDeleteWhereError struct {
	IndexName string
	Message   string
}

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

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

type StaleMetaDataVersionError struct {
	LocalVersion  int
	StoredVersion int
}

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

func (*StaleMetaDataVersionError) JavaRecordCoreException

func (*StaleMetaDataVersionError) JavaRecordCoreException()

type StandardIndexMaintainer

type StandardIndexMaintainer struct {
	// contains filtered or unexported fields
}

StandardIndexMaintainer handles VALUE index maintenance. Evaluates the index key expression against records, then sets/clears entries in the index subspace. Matches Java's standardIndexMaintainer.

func NewStandardIndexMaintainer

func NewStandardIndexMaintainer(state IndexMaintainerState) *StandardIndexMaintainer

NewStandardIndexMaintainer is the StandardIndexMaintainer a maintainer implemented outside this package embeds, as Java's maintainers extend it.

func (*StandardIndexMaintainer) CanDeleteWhere

func (m *StandardIndexMaintainer) CanDeleteWhere(prefix tuple.Tuple) error

CanDeleteWhere bounds a prefix by the index's matchable width. Every maintainer embedding standardIndexMaintainer inherits this — which is how RANK's ranked sets, MULTIDIMENSIONAL's R-trees and TIME_WINDOW_LEADERBOARD's directory get a bound without each restating it, exactly as they inherit StandardIndexMaintainer.canDeleteWhere in Java. The types whose secondary layout is narrower still (permuted min/max, sliding window) override.

func (*StandardIndexMaintainer) DeleteWhere

func (m *StandardIndexMaintainer) DeleteWhere(prefix tuple.Tuple) error

DeleteWhere clears all index entries whose key starts with the given prefix. Matches Java's standardIndexMaintainer.deleteWhere().

func (*StandardIndexMaintainer) FilteredIndexEntries

func (m *StandardIndexMaintainer) FilteredIndexEntries(record *FDBStoredRecord[proto.Message]) ([]EvaluatedIndexEntry, error)

FilteredIndexEntries is Java's StandardIndexMaintainer.filteredIndexEntries (:348-384): nil for a nil record or one the index does not maintain (indexValuesFor), otherwise its evaluated entries, only those the store's filter admits under IndexValuesSome. Every maintainer's update path reads a record's entries through it, as Java's StandardIndexMaintainer.update does.

func (*StandardIndexMaintainer) Index

func (m *StandardIndexMaintainer) Index() *Index

Index is the maintained index (Java's state.index).

func (*StandardIndexMaintainer) IndexSubspace

func (m *StandardIndexMaintainer) IndexSubspace() subspace.Subspace

IndexSubspace is the index's primary subspace (Java's state.indexSubspace).

func (*StandardIndexMaintainer) IsPendingWriteQueueAllowed

func (m *StandardIndexMaintainer) IsPendingWriteQueueAllowed() bool

func (*StandardIndexMaintainer) MergeIndex

func (m *StandardIndexMaintainer) MergeIndex() error

MergeIndex has no deferred work for synchronous standard maintainers. HNSW inherits this behavior; SPFresh retains its separate rebalance lifecycle.

func (*StandardIndexMaintainer) ReadTransaction

func (m *StandardIndexMaintainer) ReadTransaction(scanProperties ScanProperties) fdb.ReadTransaction

ReadTransaction resolves the transaction a SCAN's reads go through, from the caller's isolation level. Every maintainer that performs a query read uses this — it is the one mechanism, inherited rather than re-decided per leaf, which is the whole point: an index type that reads through tx.Snapshot() directly silently overrides the statement's isolation, and nothing about the leaf's own code looks wrong when it does.

Java's shape exactly: IndexMaintainerState.context.readTransaction( scanProperties.getExecuteProperties().getIsolationLevel().isSnapshot()) — VectorIndexMaintainer.java:201-202, TextIndexMaintainer.java:542, RankIndexMaintainer.java:292, and the generic leaf at KeyValueCursorBase.java:358 all spell it the same way.

func (*StandardIndexMaintainer) RemoteFetchMapper

func (m *StandardIndexMaintainer) RemoteFetchMapper(scanType IndexScanType, commonPrimaryKeyLength int) (tuple.Tuple, error)

RemoteFetchMapper is Java's ValueIndexMaintainer.scanRemoteFetch. Go shares one maintainer type between VALUE and the types built on it, which keep Java's unsupported default.

func (*StandardIndexMaintainer) Scan

func (m *StandardIndexMaintainer) Scan(scanRange TupleRange, continuation []byte, scanProperties ScanProperties) RecordCursor[*IndexEntry]

Scan scans index entries within the given tuple range. Creates a KeyValueCursor over the index subspace and maps KVs to IndexEntry. Matches Java's standardIndexMaintainer.scan().

func (*StandardIndexMaintainer) SerializePendingWriteQueue

func (m *StandardIndexMaintainer) SerializePendingWriteQueue(_, _ *FDBStoredRecord[proto.Message]) (*anypb.Any, error)

func (*StandardIndexMaintainer) Store

Store is the record store the index belongs to (Java's state.store).

func (*StandardIndexMaintainer) Transaction

Transaction is the transaction the maintainer writes through (Java's state.transaction).

func (*StandardIndexMaintainer) Update

func (m *StandardIndexMaintainer) Update(oldRecord, newRecord *FDBStoredRecord[proto.Message]) error

Update handles insert (old=nil), delete (new=nil), or update (both non-nil). Matches Java's standardIndexMaintainer.update().

func (*StandardIndexMaintainer) UpdateFromQueue

func (m *StandardIndexMaintainer) UpdateFromQueue(_ *anypb.Any) error

func (*StandardIndexMaintainer) UpdateWhileWriteOnly

func (m *StandardIndexMaintainer) UpdateWhileWriteOnly(oldRecord, newRecord *FDBStoredRecord[proto.Message]) error

UpdateWhileWriteOnly updates the index during WRITE_ONLY state. standardIndexMaintainer is idempotent, so this is a pass-through to Update(). Matches Java's standardIndexMaintainer.updateWhileWriteOnly() + isIdempotent() = true.

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) GetIndexMaintenanceFilter

func (b *StoreBuilder) GetIndexMaintenanceFilter() IndexMaintenanceFilter

GetIndexMaintenanceFilter is Java's FDBRecordStore.Builder.getIndexMaintenanceFilter.

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) SetGoOnlyCollation

func (b *StoreBuilder) SetGoOnlyCollation(goOnly bool) *StoreBuilder

SetGoOnlyCollation opts into x/text collation keys for a store never shared with Java. Without it, collated index access and evaluation of collated primary or record-count keys return GoOnlyCollationError. Metadata and raw record reads remain available. This option is not persisted and does not migrate existing keys.

func (*StoreBuilder) SetIndexMaintenanceFilter

func (b *StoreBuilder) SetIndexMaintenanceFilter(filter IndexMaintenanceFilter) *StoreBuilder

SetIndexMaintenanceFilter sets the store's IndexMaintenanceFilter, Java's FDBRecordStore.Builder.setIndexMaintenanceFilter: which index entries of each record the store's indexes maintain. Nil is IndexMaintenanceFilterNormal.

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) SetSerializer

SetSerializer is Java's Builder.setSerializer for a TransformedRecordSerializer: the store writes every record through it (compressed, encrypted, prefixed as configured). Unset, a store writes the bare union message, as Java's default DynamicMessageRecordSerializer does. Every store reads a transformed record whatever it writes with, decrypting with this serializer's key manager (FDBRecordStore.readStoredRecord).

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.

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

type StoreIsFullyLockedError struct {
	Reason    string
	Timestamp int64
}

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

func (*StoreIsFullyLockedError) JavaRecordCoreException

func (*StoreIsFullyLockedError) JavaRecordCoreException()

type StoreIsLockedForRecordUpdatesError

type StoreIsLockedForRecordUpdatesError struct {
	Reason    string
	Timestamp int64
}

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 (*StoreIsLockedForRecordUpdatesError) JavaRecordCoreException

func (*StoreIsLockedForRecordUpdatesError) JavaRecordCoreException()

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 reduces ReadStatisticsAtWithRefusal to a usability boolean. Use the WithRefusal form to distinguish or report absent, torn, and unreadable sets.

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 NewStoreTimer

func NewStoreTimer() *StoreTimer

NewStoreTimer creates a new StoreTimer.

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) Reset

func (t *StoreTimer) Reset()

Reset clears all counters from the timer.

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 {
	IndexerID         uuid.UUID
	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, with its log keys (indexing/IndexingHeartbeat.java:111-115): INDEXER_ID (IndexerID, the refused indexer's own identity), EXISTING_INDEXER_ID, AGE_MILLISECONDS and TIME_LIMIT_MILLIS. ExistingInfo, the holder's heartbeat info, is a Go addition: Java's exception carries no info key.

func (*SynchronizedSessionLockedError) Error

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

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

func (s *TextIndexBunchedSerializer) SerializeEntry(key tuple.Tuple, value []int) ([]byte, error)

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

func (s *TextSubspaceSplitter) SubspaceTag(ss subspace.Subspace) (tuple.Tuple, error)

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

type TimeLimitExceededError struct {
	TimeLimit time.Duration
	Elapsed   time.Duration
}

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

func (*TimeLimitExceededError) JavaRecordCoreException

func (*TimeLimitExceededError) JavaRecordCoreException()

type TimeWindowForFunction

type TimeWindowForFunction struct {
	LeaderboardType      int
	LeaderboardTimestamp int64
}

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 TransactionConfigurer

type TransactionConfigurer func(fdb.TransactionOptions) error

TransactionConfigurer is the opener's part of Java's FDBRecordContextConfig.

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

type TransactionSizeExceededError struct {
	CurrentBytes int64
	LimitBytes   int64
}

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

type TransformedRecordSerializer

type TransformedRecordSerializer struct {
	// contains filtered or unexported fields
}

TransformedRecordSerializer is Java's TransformedRecordSerializer and, built with NewTransformedRecordSerializerJCEBuilder, TransformedRecordSerializerJCE: a record's serialized union message is compressed, then encrypted, then prefixed on the way out, and the reverse on the way in (TransformedRecordSerializer.java:213-240, :360-406). A store configured with one writes through it (StoreBuilder.SetSerializer); every store reads through it, whatever it writes with (readStoredRecord).

type TransformedRecordSerializerBuilder

type TransformedRecordSerializerBuilder struct {
	// contains filtered or unexported fields
}

TransformedRecordSerializerBuilder is Java's TransformedRecordSerializer.Builder (and TransformedRecordSerializerJCE.Builder for a JCE builder).

func NewTransformedRecordSerializerBuilder

func NewTransformedRecordSerializerBuilder() *TransformedRecordSerializerBuilder

NewTransformedRecordSerializerBuilder is TransformedRecordSerializer.newDefaultBuilder: no compression, level BEST_COMPRESSION, no encryption.

func NewTransformedRecordSerializerJCEBuilder

func NewTransformedRecordSerializerJCEBuilder() *TransformedRecordSerializerBuilder

NewTransformedRecordSerializerJCEBuilder is TransformedRecordSerializerJCE.newDefaultBuilder.

func (*TransformedRecordSerializerBuilder) Build

Build is Java's build(): the plain class refuses to encrypt, and the JCE class resolves its key manager (resolveKeyManager). A compression level outside Deflater's range is not refused here; as in Java, the first record compressed fails (compress).

func (*TransformedRecordSerializerBuilder) SetCipherName

func (*TransformedRecordSerializerBuilder) SetCompressWhenSerializing

func (*TransformedRecordSerializerBuilder) SetCompressionLevel

SetCompressionLevel takes Java's Deflater levels: -1 (the default) or 0-9.

func (*TransformedRecordSerializerBuilder) SetDeserializeReattemptCount

func (*TransformedRecordSerializerBuilder) SetEncryptWhenSerializing

func (*TransformedRecordSerializerBuilder) SetEncryptionKey

func (*TransformedRecordSerializerBuilder) SetFailOnDeserializeReattempt

func (b *TransformedRecordSerializerBuilder) SetFailOnDeserializeReattempt(v bool) *TransformedRecordSerializerBuilder

func (*TransformedRecordSerializerBuilder) SetKeyManager

SetKeyManager, SetEncryptionKey, SetCipherName and SetRandom are the JCE builder's; a key manager and the three single-key settings are exclusive, as Java's resolveKeyManager has them (TransformedRecordSerializerJCE.java:325-349).

func (*TransformedRecordSerializerBuilder) SetRandom

func (*TransformedRecordSerializerBuilder) SetWriteEncryptionValidationRatio

func (b *TransformedRecordSerializerBuilder) SetWriteEncryptionValidationRatio(r float64) *TransformedRecordSerializerBuilder

func (*TransformedRecordSerializerBuilder) SetWriteValidationRatio

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) (TupleRange.java:160-186): an open bound becomes the prefix itself, inclusive.

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

type TypedFDBRecordStore[T proto.Message] struct {
	// contains filtered or unexported fields
}

TypedFDBRecordStore is Java's FDBTypedRecordStore: the untyped store, read and written through a typedRecordSerializer, so records come back as T.

func GetTypedRecordStore

func GetTypedRecordStore[T proto.Message](store *FDBRecordStore, recordTypeName string) (*TypedFDBRecordStore[T], error)

GetTypedRecordStore is Java's FDBRecordStore.getTypedRecordStore for a TypedRecordSerializer over recordTypeName's union field, with T its record message type. The union is the metadata's, whatever it is named.

func NewTypedRecordStore

func NewTypedRecordStore[T proto.Message](baseStore *FDBRecordStore, recordType *RecordType) (*TypedFDBRecordStore[T], error)

NewTypedRecordStore is a typed store over baseStore for recordType, which must be a record type of baseStore's metadata. A T of another message than recordType's is refused, as Java's TypedRecordSerializer constructor refuses a getter of another field (TypedRecordSerializer.java:77-80).

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 the record with primaryKey, false when there is none.

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 the record with primaryKey, nil when there is none.

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]) SaveRecordWithVersion

func (ts *TypedFDBRecordStore[T]) SaveRecordWithVersion(
	record T,
	existenceCheck RecordExistenceCheck,
	version *FDBRecordVersion,
	behavior VersionstampSaveBehavior,
) (*FDBStoredRecord[T], error)

SaveRecordWithVersion saves a typed record with the version that behavior chooses, as FDBRecordStore.SaveRecordWithVersion does.

func (*TypedFDBRecordStore[T]) ScanRecords

func (ts *TypedFDBRecordStore[T]) ScanRecords(continuation []byte, scanProperties ScanProperties) RecordCursor[*FDBStoredRecord[T]]

ScanRecords scans every record of the store as T, Java's typed scanRecords: a record of another type fails the scan where it is read, with RecordDeserializationError ("Specified union field was not set").

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 UnexpectedReadableError

type UnexpectedReadableError struct {
	AllReadable bool
	Message     string
	IndexNames  []string
	IndexStates []IndexState
}

UnexpectedReadableError matches Java's IndexingBase.UnexpectedReadableException: a build transaction found some (AllReadable false) or all of its targets already published, typically by a mutual peer. Under a mutual policy the build catcher treats the second as success and falls back to a records scan on the first; any other build returns it.

func (*UnexpectedReadableError) Error

func (e *UnexpectedReadableError) Error() string

func (*UnexpectedReadableError) JavaRecordCoreException

func (*UnexpectedReadableError) JavaRecordCoreException()

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

type UnknownIndexTypeError struct {
	IndexName string
	IndexType string
}

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) JavaRecordCoreException

func (*UnknownIndexTypeError) JavaRecordCoreException()

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 (*UnknownOrElseCursorStateError) JavaRecordCoreException

func (*UnknownOrElseCursorStateError) JavaRecordCoreException()

type UnknownStoreLockStateError

type UnknownStoreLockStateError struct {
	// LockStateValue is the state as read: UNSPECIFIED (0) for a stored
	// number the enum does not declare, which Java's parse leaves in the
	// unknown fields and reads as the default.
	LockStateValue int32
	// UnknownFields is the lock-state message's unknown fields, Java's
	// LogMessageKeys.VALUE (UnknownStoreLockStateException.java:49): an
	// undeclared state number is there.
	UnknownFields []byte
}

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 (*UnknownStoreLockStateError) JavaRecordCoreException

func (*UnknownStoreLockStateError) JavaRecordCoreException()

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 (*UnsupportedFeatureForFormatVersionError) JavaRecordCoreException

func (*UnsupportedFeatureForFormatVersionError) JavaRecordCoreException()

type UnsupportedFormatVersionError

type UnsupportedFormatVersionError struct {
	Version    int32
	MaxVersion int32
}

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 (*UnsupportedFormatVersionError) JavaRecordCoreException

func (*UnsupportedFormatVersionError) JavaRecordCoreException()

type UnsupportedMethodError

type UnsupportedMethodError struct{ Message string }

UnsupportedMethodError is Java's UnsupportedMethodException.

func (*UnsupportedMethodError) Error

func (e *UnsupportedMethodError) Error() string

func (*UnsupportedMethodError) JavaRecordCoreException

func (*UnsupportedMethodError) JavaRecordCoreException()

type UnsupportedOperationError

type UnsupportedOperationError struct{ Message string }

UnsupportedOperationError corresponds to Java's UnsupportedOperationException.

func (*UnsupportedOperationError) Error

func (e *UnsupportedOperationError) Error() string

type UnsupportedRemoteFetchIndexError

type UnsupportedRemoteFetchIndexError struct {
	Message   string
	IndexName string
}

UnsupportedRemoteFetchIndexError is Java's UnsupportedRemoteFetchIndexException: the index maintainer, or the transaction's client, cannot fetch remotely.

func (*UnsupportedRemoteFetchIndexError) Error

func (*UnsupportedRemoteFetchIndexError) JavaRecordCoreException

func (*UnsupportedRemoteFetchIndexError) JavaRecordCoreException()

type UnsupportedValueTypeError

type UnsupportedValueTypeError struct {
	JavaClass string
}

UnsupportedValueTypeError is the RecordCoreException Java's LiteralKeyExpression.toProtoValue throws for a value no Value field holds (LiteralKeyExpression.java:192-194), with its message: "Unsupported value type " and the value's Class (`class java.util.UUID`). JavaClass is the Java class the value would be in the target, or the Go type where it has none.

func (*UnsupportedValueTypeError) Error

func (e *UnsupportedValueTypeError) Error() string

func (*UnsupportedValueTypeError) JavaRecordCoreException

func (*UnsupportedValueTypeError) JavaRecordCoreException()

type VectorIndexScanOptions

type VectorIndexScanOptions struct {
	ReturnVectors                           *bool // nil defaults to !useRaBitQ
	EfSearch                                *int  // HNSW; nil derives it from k
	GuardiannCandidatePoolFactor            *float64
	GuardiannSearchMaxClusters              *int
	GuardiannSearchMinClustersBeforePruning *int
	GuardiannSearchDistanceRatioCutoff      *float64
	GuardiannCentroidEfRingSearch           *int
	GuardiannCentroidEfOutwardSearch        *int
	GuardiannSearchConcurrency              *int
	// contains filtered or unexported fields
}

VectorIndexScanOptions is Java's VectorIndexScanOptions: per-scan search knobs. A nil GuardiANN field keeps the SearchConfig default; each applies only to an index of its engine.

func VectorIndexScanOptionsFromProto

func VectorIndexScanOptionsFromProto(p *gen.PVectorIndexScanOptions) (VectorIndexScanOptions, error)

VectorIndexScanOptionsFromProto accepts canonical and legacy names, rejecting duplicate aliases as Java does. An explicit NULL retains its presence. Invalid value types are rejected at this typed Go boundary rather than at Java's later getOption Class.cast call.

func (VectorIndexScanOptions) ToProto

ToProto writes Java VectorIndexScanOptions, using Integer (not Long) for integer options and canonical names. Entries have a deterministic order.

type VectorIndexSearcher

type VectorIndexSearcher interface {
	// SearchKNN is the k nearest neighbours of queryVector in the prefix's
	// partition, closest first, read at snapshot isolation.
	SearchKNN(prefix tuple.Tuple, queryVector []float64, k, efSearch int) ([]VectorSearchResult, error)
	// ScanVectorIndex is the BY_DISTANCE scan of the prefix's partition with
	// the full per-scan options.
	ScanVectorIndex(prefix tuple.Tuple, queryVector []float64, k int, opts VectorIndexScanOptions, continuation []byte, scanProperties ScanProperties) RecordCursor[*IndexEntry]
}

VectorIndexSearcher is the kNN surface of a VECTOR index maintainer, which package vectorindex implements; the store's vector search entry points reach it through any decorator (IndexMaintainerAs).

type VectorSearchResult

type VectorSearchResult struct {
	PrimaryKey tuple.Tuple
	Distance   float64
}

VectorSearchResult is a single result from a vector similarity search.

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 VersionstampSaveBehavior

type VersionstampSaveBehavior int

VersionstampSaveBehavior is Java's FDBRecordStoreBase.VersionstampSaveBehavior: how a save chooses the version stored with the record.

const (
	// VersionstampSaveBehaviorDefault stores the supplied version; without one it
	// assigns an incomplete version when the metadata stores record versions.
	VersionstampSaveBehaviorDefault VersionstampSaveBehavior = iota
	// VersionstampSaveBehaviorNoVersion stores no version; supplying one is an error.
	VersionstampSaveBehaviorNoVersion
	// VersionstampSaveBehaviorWithVersion always stores a version, assigning an
	// incomplete one when none is supplied, even if the metadata stores none.
	VersionstampSaveBehaviorWithVersion
	// VersionstampSaveBehaviorIfPresent stores exactly the supplied version, if any.
	VersionstampSaveBehaviorIfPresent
)

func (VersionstampSaveBehavior) String

func (b VersionstampSaveBehavior) String() string

String returns the Java enum constant's name.

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

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 indexfetch is Java's IndexFetchMethod, shared by the record layer's scans and the planner's index plans.
Package indexfetch is Java's IndexFetchMethod, shared by the record layer's scans and the planner's index plans.
Package indexpredicate classifies stored index predicates the way Java's IndexPredicate.toPredicate constructors would (record.metadata.IndexPredicate).
Package indexpredicate classifies stored index predicates the way Java's IndexPredicate.toPredicate constructors would (record.metadata.IndexPredicate).
internal
protovalue
Package protovalue reads a key expression's Value proto as Java's LiteralKeyExpression.fromProtoValue does (LiteralKeyExpression.java:134-173), the one reader of both the meta-data loader (a literal key, a record type's explicit key, an index predicate's operand) and the planner's translation of an index predicate, which cannot import the record layer.
Package protovalue reads a key expression's Value proto as Java's LiteralKeyExpression.fromProtoValue does (LiteralKeyExpression.java:134-173), the one reader of both the meta-data loader (a literal key, a record type's explicit key, an index predicate's operand) and the planner's translation of an index predicate, which cannot import the record layer.
tuplefast
Package tuplefast is a zero-allocation FDB tuple decoder, shared by the record layer and the vector index package.
Package tuplefast is a zero-allocation FDB tuple decoder, shared by the record layer and the vector index package.
Package javanum ports the JDK's floating-point text parsers, Double.parseDouble and Float.parseFloat (FloatingDecimal .readJavaFormatString), which Java's record layer uses for CAST(string AS DOUBLE/FLOAT) and for index options.
Package javanum ports the JDK's floating-point text parsers, Double.parseDouble and Float.parseFloat (FloatingDecimal .readJavaFormatString), which Java's record layer uses for CAST(string AS DOUBLE/FLOAT) and for index options.
Package keyspace provides a logical directory tree abstraction over FDB.
Package keyspace provides a logical directory tree abstraction over FDB.
Package keystoretest writes PKCS12 key stores for tests, in the layout the JDK's PKCS12KeyStore writes since JDK 12: each AES secret key in a secret bag (a PKCS #8 PrivateKeyInfo shrouded under PBES2: PBKDF2 with HmacSHA256, AES-256-CBC), the bags in one unencrypted data safe, and an HmacSHA256 MAC keyed by the PKCS #12 KDF.
Package keystoretest writes PKCS12 key stores for tests, in the layout the JDK's PKCS12KeyStore writes since JDK 12: each AES secret key in a secret bag (a PKCS #8 PrivateKeyInfo shrouded under PBES2: PBKDF2 with HmacSHA256, AES-256-CBC), the bags in one unencrypted data safe, and an HmacSHA256 MAC keyed by the PKCS #12 KDF.
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.
Package protoscope lets protobuf-go build a descriptor from a file that protobuf-java accepts and protoc refuses: one whose enums share a value name.
Package protoscope lets protobuf-go build a descriptor from a file that protobuf-java accepts and protoc refuses: one whose enums share a value name.
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/internal/fnv64
Package fnv64 hashes planner identity streams without string-to-byte copies.
Package fnv64 hashes planner identity streams without string-to-byte copies.
plan/cascades/internal/fuzzfloor
Package fuzzfloor decides whether a fuzz target's seed-corpus coverage floor should be enforced on this run.
Package fuzzfloor decides whether a fuzz target's seed-corpus coverage floor should be enforced on this run.
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/constfoldcensus
Package constfoldcensus enumerates every call site that simplifies or evaluates a constant at planning (RFC-257 WS-E design 5.4(b)): the value and predicate simplification entry points, the constant evaluators, the predicate simplifier driver, and every `Evaluate(nil)` / `Eval(nil)` call.
Package constfoldcensus enumerates every call site that simplifies or evaluates a constant at planning (RFC-257 WS-E design 5.4(b)): the value and predicate simplification entry points, the constant evaluators, the predicate simplifier driver, and every `Evaluate(nil)` / `Eval(nil)` call.
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 tupleordering is Java's TupleOrdering: tuples packed so that their byte order is a chosen direction and NULL placement, the encoding order functions store in index keys.
Package tupleordering is Java's TupleOrdering: tuples packed so that their byte order is a chosen direction and NULL placement, the encoding order functions store in index keys.
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.
Package vectorindex implements the record layer's vector indexes: Java's VECTOR index (VectorIndexMaintainer) with its HNSW and GuardiANN engines, and Go's SPFresh index (RFC-094).
Package vectorindex implements the record layer's vector indexes: Java's VECTOR index (VectorIndexMaintainer) with its HNSW and GuardiANN engines, and Go's SPFresh index (RFC-094).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL