Documentation
¶
Overview ¶
Package placementprobe implements the multi-node campaign's placement probe (H5) and ballast/control writer (H6).
The probe lists every physical key of a Record Layer store's record subspace prefix+(1,) and index subspace prefix+(2,), the store's shard boundaries and the storage servers holding each key, as the fdb-bench-placement-probe/v3 document that tools/benchcampaign/multinode/placement_receipt.py judges. Store metadata (header (0,), index state and other subspaces (3..10,)) is out of scope by design and is never listed.
One snapshot. Everything the placement claim rests on is read in ONE transaction pinned at read version V1 with READ_SYSTEM_KEYS: the data-distribution mode, the moveKeysLock owner and write token, the \xff/keyServers entries of the store range (shard boundaries and team identities, compared as raw bytes, never decoded), every key of the two data subspaces, and every key's storage addresses. The production backend is libfdb_c (cmd/placementprobe, build tag libfdbc): its getAddressesForKey (NativeAPI.actor.cpp getAddressesForKeyActor) reads \xff/serverTag, \xff/keyServers and \xff/serverList transactionally, so addresses are those of the shard map at V1. The pure-Go client's LocalityGetAddressesForKey answers from its location cache instead (a divergence from libfdb_c); that backend is DIAGNOSTIC ONLY: its documents carry addresses_basis kind "location-cache (diagnostic)", the probe refuses it without --diagnostic, and placement_receipt.py fails such a document's integrity.
Stability over [V1, V2] is established by the moveKeysLock and the raw shard map, not by boundary identity (FoundationDB 7.3.77):
- `datadistribution off|on` (ManagementAPI setDDMode; SpecialKeySpace DataDistributionImpl::commit) writes the mode, the lock owner (dataDistributionModeLock) AND a fresh random write token;
- takeMoveKeysLock (MoveKeys.actor.cpp), which DataDistributor::init runs on every DD (re)start BEFORE it reads the mode, writes ONLY a random owner and leaves the write token unchanged; a healthy frozen cluster may therefore show any owner, and an owner-only change is caught solely by the owner-identity check;
- the relocation paths startMoveKeys, finishMoveKeys, startMoveShards, finishMoveShards, removeStorageServer, removeKeysFromFailedServer and cleanUpDataMove{Background,Core} call checkMoveKeysLock in their transaction, which writes a new token (and, when it takes the lock from the previous owner, the owner too). Not every keyServers write is guarded: cleanUpSingleShardDataMove (MoveKeys.actor.cpp:630-703) writes it without checkMoveKeysLock, though only with SHARD_ENCODE_LOCATION_METADATA, which is off by default.
The probe requires the mode key present and 0 at V1 and V2, the owner present and identical at V1 and V2 (any value, recorded), the write token present and identical, and the raw keyServers bytes identical, and emits nothing otherwise: a toggle writes a new token, a DD restart writes a new owner, a guarded relocation commits a new token, and any shard-map write, guarded or not, changes the raw keyServers bytes.
The ballast tool writes only into [prefix+(1,1000000), strinc(prefix+(1,))) and only while data distribution is on; it clears only that range and only while it is off, reading \xff/dataDistributionMode inside the committing transaction so a concurrent mode change conflicts the commit. Every destructive operation takes an OwnedStore, whose prefix can only come from the store's fixture receipt (OpenStore) or the fixed scratch prefix (OpenControlStore) and is re-validated at every call.
Index ¶
- Constants
- Variables
- func BallastKey(prefix []byte, i int) []byte
- func BallastRange(prefix []byte) (begin, end []byte, err error)
- func BallastValue(i int) []byte
- func DDMode(value []byte, present bool) (int32, error)
- func InsideGitWorktree(path string) (bool, error)
- func ResolvePrefix(store string, r FixtureReceipt) ([]byte, error)
- func Stores() []string
- func Subspaces(prefix []byte) (record, index []byte)
- func WriteControlFixture(c Cluster, s OwnedStore, rows int) (*BallastReceipt, FixtureReceipt, error)
- func WriteJSONExclusive(path string, v any) error
- type AddressBasis
- type BallastReceipt
- func ClearBallast(c Cluster, s OwnedStore) (*BallastReceipt, error)
- func ClearControl(c Cluster, s OwnedStore) (*BallastReceipt, error)
- func MutateControl(c Cluster, s OwnedStore, defect string) (*BallastReceipt, error)
- func VerifyBallastEmpty(c Cluster, s OwnedStore) (*BallastReceipt, error)
- func WriteBallast(c Cluster, s OwnedStore, totalBytes int64) (*BallastReceipt, error)
- type Cluster
- type ClusterIdentity
- type DDModeRead
- type DDModes
- type FixtureReceipt
- type GoCluster
- type KV
- type KeyServers
- type MoveKeysLock
- type Mutation
- type Op
- type OwnedStore
- type ProbeDoc
- type ProbeInput
- type ProbeKey
- type Reader
- type Recheck
- type Txn
Constants ¶
const ( ProbeFormat = "fdb-bench-placement-probe/v3" ReceiptFormat = "fdb-bench-ballast-receipt/v2" Tool = "placementprobe/v2" // AddressTransactional is the only address basis placement receipts accept. AddressTransactional = "transactional" // AddressLocationCache marks diagnostic documents from the pure-Go backend. AddressLocationCache = "location-cache (diagnostic)" RecordKey = 1 IndexKey = 2 // BallastFirstID is the first record primary key the ballast uses; every // fixture ID is below it. BallastFirstID = 1_000_000 // BallastValueBytes is the size of one ballast value. BallastValueBytes = 100_000 // BallastKeysPerTransaction keeps each write transaction near 5 MB, below // FoundationDB's 10 MB transaction limit. BallastKeysPerTransaction = 50 // ControlMutationID is the record the on-cluster mutation controls damage. ControlMutationID = 7 // IndexName is the fixtures' VALUE index on price (= order ID). IndexName = "price_idx" )
Formats and fixed layout constants. They mirror placement_receipt.py.
Variables ¶
var ( // DDModeKey is dataDistributionModeKey: a BinaryWriter int (4 bytes, little // endian); absent means 1 (on). DDModeKey = []byte("\xff/dataDistributionMode") // MoveKeysLockOwnerKey and MoveKeysLockWriteKey hold BinaryWriter UIDs. MoveKeysLockOwnerKey = []byte("\xff/moveKeysLock/Owner") MoveKeysLockWriteKey = []byte("\xff/moveKeysLock/Write") // KeyServersPrefix is keyServersKeys.begin. KeyServersPrefix = []byte("\xff/keyServers/") // DDModeLock is dataDistributionModeLock = UID(6345, 3425), serialized as // two little-endian uint64 (UID::serialize_unversioned): the owner setDDMode // writes. Informational only: a DD restart replaces it with a random owner. DDModeLock = uidBytes(6345, 3425) )
FoundationDB 7.3.77 system keys (fdbclient/SystemData.cpp).
var ErrDDMode = errors.New("data-distribution mode forbids this operation")
ErrDDMode reports a data-distribution mode that forbids the operation.
Functions ¶
func BallastKey ¶
BallastKey is ballast entry i: prefix+(1, 1000000+i).
func BallastRange ¶
BallastRange is [prefix+(1,1000000), strinc(prefix+(1,))).
func BallastValue ¶
BallastValue is ballast entry i's deterministic value.
func InsideGitWorktree ¶
InsideGitWorktree reports whether path (existing or not) lies inside a directory holding .git, after resolving symlinks of its parent directory.
func ResolvePrefix ¶
func ResolvePrefix(store string, r FixtureReceipt) ([]byte, error)
ResolvePrefix returns the owned store's key prefix, cross-checked against the fixture receipt. Unknown stores and any mismatch are refused.
func WriteControlFixture ¶
func WriteControlFixture(c Cluster, s OwnedStore, rows int) (*BallastReceipt, FixtureReceipt, error)
WriteControlFixture writes a canonical fixture into an empty scratch control store and returns its fixture receipt for the probe.
func WriteJSONExclusive ¶
WriteJSONExclusive writes v as indented JSON to a new file outside any Git work tree; it never overwrites.
Types ¶
type AddressBasis ¶
type AddressBasis struct {
Kind string `json:"kind"`
ReadVersion int64 `json:"read_version"`
Method string `json:"method"`
}
AddressBasis records how the addresses were obtained.
type BallastReceipt ¶
type BallastReceipt struct {
Format string `json:"format"`
Tool string `json:"tool"`
Action string `json:"action"`
Store string `json:"store"`
StorePrefixHex string `json:"store_prefix_hex"`
Cluster ClusterIdentity `json:"cluster"`
RangeHex [2]string `json:"range_hex"`
DDModeRequired string `json:"dd_mode_required"`
Defect string `json:"defect,omitempty"`
KeysWritten int `json:"keys_written,omitempty"`
ValueBytes int `json:"value_bytes,omitempty"`
TotalBytes int64 `json:"total_bytes,omitempty"`
Transactions int `json:"transactions,omitempty"`
CommittedVersions []int64 `json:"committed_versions,omitempty"`
ReadVersion int64 `json:"read_version,omitempty"`
KeysFound *int `json:"keys_found,omitempty"`
Empty *bool `json:"empty,omitempty"`
}
BallastReceipt is the H6 receipt for every write, clear and verification.
func ClearBallast ¶
func ClearBallast(c Cluster, s OwnedStore) (*BallastReceipt, error)
ClearBallast clears exactly the ballast range, only while data distribution is off (mode key present and 0, read in the clearing transaction).
func ClearControl ¶
func ClearControl(c Cluster, s OwnedStore) (*BallastReceipt, error)
ClearControl clears a whole scratch control store and verifies it is empty.
func MutateControl ¶
func MutateControl(c Cluster, s OwnedStore, defect string) (*BallastReceipt, error)
MutateControl applies one defect to the split control store.
func VerifyBallastEmpty ¶
func VerifyBallastEmpty(c Cluster, s OwnedStore) (*BallastReceipt, error)
VerifyBallastEmpty reads the whole ballast range at a fresh read version. It returns the receipt even when the range is not empty (with an error).
func WriteBallast ¶
func WriteBallast(c Cluster, s OwnedStore, totalBytes int64) (*BallastReceipt, error)
WriteBallast writes ceil(totalBytes / 100000) ballast values into the ballast range of an owned benchmark store, only while data distribution is on and only into an empty ballast range.
type Cluster ¶
type Cluster interface {
// ReadVersion returns a fresh read version.
ReadVersion() (int64, error)
// At opens one transaction at version.
At(version int64) (Txn, error)
// AddressBasis is AddressTransactional or AddressLocationCache.
AddressBasis() string
// Commit runs guard and then applies writes in one transaction, retrying
// retryable errors; guard errors abort without retry. It returns the
// committed version.
Commit(guard func(read Reader) error, writes []Mutation) (int64, error)
}
Cluster is everything the probe and the ballast tool need from FoundationDB. Production backends: cmd/placementprobe backend_cgo.go (libfdb_c, transactional addresses) and GoCluster (pure Go, diagnostic addresses). Tests use a fake.
type ClusterIdentity ¶
type ClusterIdentity struct {
ConnectionStringID string `json:"connection_string_id"`
ClusterFileSHA256 string `json:"cluster_file_sha256"`
}
ClusterIdentity names the cluster a document was taken on.
func ParseClusterIdentity ¶
func ParseClusterIdentity(data []byte) (ClusterIdentity, error)
ParseClusterIdentity derives the identity from cluster file bytes: the SHA-256 of the file and the description:id of its connection string.
type DDModeRead ¶
type DDModeRead struct {
ReadVersion int64 `json:"read_version"`
Mode int32 `json:"mode"`
KeyPresent bool `json:"key_present"`
}
DDModeRead is one observation of the data-distribution mode.
type DDModes ¶
type DDModes struct {
RequiredOff bool `json:"required_off"`
AtV1 DDModeRead `json:"at_v1"`
AtV2 DDModeRead `json:"at_v2"`
}
DDModes records the data-distribution mode at V1 and V2.
type FixtureReceipt ¶
type FixtureReceipt struct {
Phase string `json:"phase"`
Payload string `json:"payload,omitempty"`
PrefixBytes *int `json:"prefix_bytes"`
Rows *int `json:"rows"`
Chunks *int `json:"chunks,omitempty"`
StorePrefixHex string `json:"store_prefix_hex,omitempty"`
Source string `json:"source,omitempty"`
}
FixtureReceipt is the benchmark's untimed fixture receipt (the JSON after FDB_BENCH_AUDIT with phase "fixture"), or the H6 control equivalent.
func ParseFixtureReceipt ¶
func ParseFixtureReceipt(data []byte, store string) (FixtureReceipt, error)
ParseFixtureReceipt accepts either one JSON object or a benchmark log, from which it takes the FDB_BENCH_AUDIT lines with phase "fixture" (and, for stores that have one, the matching payload). Exactly one distinct receipt must remain; the per-benchmark "case" field is ignored for that comparison.
type GoCluster ¶
type GoCluster struct {
DB fdb.Database
// TimeoutMillis bounds each transaction (FDB transaction timeout option).
TimeoutMillis int64
// MaxAttempts bounds Commit retries.
MaxAttempts int
}
GoCluster implements Cluster over the pure-Go client. Its LocalityGetAddressesForKey answers from the client location cache, unlike libfdb_c's transactional getAddressesForKey, so its address basis is diagnostic: probes from it are refused without --diagnostic and never pass placement_receipt integrity. Ballast and control operations are exact.
func (GoCluster) AddressBasis ¶
AddressBasis implements Cluster.
func (GoCluster) Commit ¶
Commit implements Cluster with an explicit OnError loop so the committed version of the successful attempt is available.
func (GoCluster) ReadVersion ¶
ReadVersion implements Cluster.
type KeyServers ¶
type KeyServers struct {
BeginHex string `json:"begin_hex"`
EndHex string `json:"end_hex"`
Entries int `json:"entries"`
SHA256AtV1 string `json:"sha256_at_v1"`
SHA256AtV2 string `json:"sha256_at_v2"`
Unchanged bool `json:"unchanged"`
Description string `json:"description"`
}
KeyServers records the raw \xff/keyServers entries covering the store range: from the last entry <= keyServers+prefix to keyServers+strinc(prefix).
type MoveKeysLock ¶
type MoveKeysLock struct {
OwnerHexAtV1 string `json:"owner_hex_at_v1"`
OwnerHexAtV2 string `json:"owner_hex_at_v2"`
OwnerUnchanged bool `json:"owner_unchanged"`
WriteTokenHexAtV1 string `json:"write_token_hex_at_v1"`
WriteTokenHexAtV2 string `json:"write_token_hex_at_v2"`
WriteTokenUnchanged bool `json:"write_token_unchanged"`
}
MoveKeysLock records the moveKeysLock owner and write token at V1 and V2.
type Mutation ¶
type Mutation struct {
Op Op
Key []byte
End []byte // OpClearRange only
Value []byte // OpSet only
}
Mutation is one write applied by Cluster.Commit.
func ControlKeys ¶
func ControlKeys(s OwnedStore, rows int) ([]Mutation, int, error)
ControlKeys returns the canonical fixture keys of a control store: index prefix+(2,"price_idx",i,i) and records prefix+(1,i,0) (small) or prefix+(1,i,1), prefix+(1,i,2) (split).
type OwnedStore ¶
type OwnedStore struct {
// contains filtered or unexported fields
}
OwnedStore is an owned store with its validated prefix. Its fields are unexported: outside this package it can only be obtained from OpenStore or OpenControlStore, and every operation re-validates it (check).
func OpenControlStore ¶
func OpenControlStore(store string) (OwnedStore, error)
OpenControlStore returns a scratch control store with its fixed tuple prefix. Control stores have no benchmark fixture receipt until control-write emits one.
func OpenStore ¶
func OpenStore(store string, r FixtureReceipt) (OwnedStore, error)
OpenStore resolves a store's prefix from its fixture receipt.
func (OwnedStore) Prefix ¶
func (s OwnedStore) Prefix() []byte
Prefix returns a copy of the store prefix.
type ProbeDoc ¶
type ProbeDoc struct {
Format string `json:"format"`
Tool string `json:"tool"`
Store string `json:"store"`
StorePrefixHex string `json:"store_prefix_hex"`
FixtureReceiptSHA256 string `json:"fixture_receipt_sha256"`
Cluster ClusterIdentity `json:"cluster"`
ReadVersion int64 `json:"read_version"`
BoundariesReadVersion int64 `json:"boundaries_read_version"`
BoundaryRangeHex [2]string `json:"boundary_range_hex"`
BoundariesComplete bool `json:"boundaries_complete"`
BoundariesHex []string `json:"boundaries_hex"`
ScannedSubspacesHex [2]string `json:"scanned_subspaces_hex"`
KeysComplete bool `json:"keys_complete"`
Keys []ProbeKey `json:"keys"`
AddressesBasis AddressBasis `json:"addresses_basis"`
Recheck Recheck `json:"recheck"`
DDMode DDModes `json:"dd_mode"`
MoveKeysLock MoveKeysLock `json:"move_keys_lock"`
KeyServers KeyServers `json:"key_servers"`
}
ProbeDoc is the fdb-bench-placement-probe/v3 document.
func Probe ¶
func Probe(c Cluster, in ProbeInput) (*ProbeDoc, error)
Probe builds the placement probe document from one snapshot at V1 and a recheck snapshot at V2 >= V1. It never judges placement; the receipt does. It emits nothing when the recheck differs (lock owner, write token, keyServers bytes, boundaries), when data distribution is not off at V1 and V2, or when the backend's addresses are not transactional (unless Diagnostic).
type ProbeInput ¶
type ProbeInput struct {
Store OwnedStore
FixtureSHA256 string
Cluster ClusterIdentity
// Diagnostic permits a location-cache address source and data
// distribution on; such documents always fail placement_receipt integrity.
Diagnostic bool
}
ProbeInput selects the store to probe.
type ProbeKey ¶
type ProbeKey struct {
Kind string `json:"kind"`
ID *int64 `json:"id"`
KeyHex string `json:"key_hex"`
Addresses []string `json:"addresses"`
}
ProbeKey is one physical key with its storage addresses.
type Reader ¶
Reader reads a key inside the committing transaction (non-snapshot, so the key joins the read-conflict set; system keys are readable).
type Recheck ¶
type Recheck struct {
ReadVersion int64 `json:"read_version"`
BoundariesIdentical bool `json:"boundaries_identical"`
}
Recheck records the second snapshot.
type Txn ¶
type Txn interface {
// Get reads one key.
Get(key []byte) (value []byte, present bool, err error)
// Range returns every pair of [begin, end), without a limit. With
// fromLastLessOrEqual it starts at the last key <= begin instead (the
// keyServers entry covering begin).
Range(begin, end []byte, fromLastLessOrEqual bool) ([]KV, error)
// Addresses returns each key's storage addresses (LocalityGetAddressesForKey
// in this transaction), in the order of keys.
Addresses(keys [][]byte) ([][]string, error)
}
Txn is ONE backend transaction pinned at a read version with READ_SYSTEM_KEYS. Every method reads at that version.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
placementprobe
command
Command placementprobe is the multi-node campaign's placement probe (H5) and ballast/control writer (H6).
|
Command placementprobe is the multi-node campaign's placement probe (H5) and ballast/control writer (H6). |