Documentation
¶
Overview ¶
Package namespaces owns the namespace control-plane state and exposes a typed domain API for callers that need direct existence checks. Lookups return the RAFT subcommand namespace type.
Index ¶
- Variables
- func AdmitDestructiveApply(e Exister, name string) error
- func AdmitReplicationTarget(state cmd.NamespaceState) error
- func AppliedChangeMayOpenShard(state cmd.NamespaceState) bool
- func PublicMessage(err error) (msg string, ok bool)
- func RequireActive(e Exister, name string) error
- func RequireAllExisting(e Exister, names []string) error
- func RequireExisting(e Exister, name string) error
- func RequireShardLoadable(state cmd.NamespaceState) error
- func ShardsShouldBeOpen(state cmd.NamespaceState) bool
- func ValidateName(name string) error
- type Controller
- func (c *Controller) ChangeState(name string, target cmd.NamespaceState, sc StateChange) error
- func (c *Controller) Count() int
- func (c *Controller) Create(ns cmd.Namespace, index uint64) error
- func (c *Controller) Get(names ...string) []cmd.Namespace
- func (c *Controller) GetNamespace(name string) (ns cmd.Namespace, ok bool)
- func (c *Controller) List() []cmd.Namespace
- func (c *Controller) ListDeleting() []string
- func (c *Controller) RemoveEntity(name string) error
- func (c *Controller) Restore(snapshot []byte) error
- func (c *Controller) Snapshot() ([]byte, error)
- func (c *Controller) Update(ns cmd.Namespace) error
- type Exister
- type MockExister
- type MockExister_Expecter
- type MockExister_GetNamespace_Call
- func (_c *MockExister_GetNamespace_Call) Return(_a0 api.Namespace, _a1 bool) *MockExister_GetNamespace_Call
- func (_c *MockExister_GetNamespace_Call) Run(run func(name string)) *MockExister_GetNamespace_Call
- func (_c *MockExister_GetNamespace_Call) RunAndReturn(run func(string) (api.Namespace, bool)) *MockExister_GetNamespace_Call
- type StateChange
Constants ¶
This section is empty.
Variables ¶
var ( // ErrBadRequest signals a malformed RAFT command payload or an invalid // argument so the apply path can classify it distinctly from // legitimate-but-rejected operations. ErrBadRequest = errors.New("bad request") // ErrAlreadyExists is returned by Create when a namespace with the given // name is already present. Callers that need a distinct status for // duplicates (e.g. an HTTP handler mapping to 409) should check with // errors.Is rather than string-matching the error message. ErrAlreadyExists = errors.New("namespace already exists") // ErrNotFound is returned by ChangeState and RemoveEntity when the // target namespace does not exist. Callers that need a distinct status // for missing entries (e.g. an HTTP handler mapping to 404) should // check with errors.Is. ErrNotFound = errors.New("namespace not found") // ErrNamespaceDeleting is returned when a create-like operation, or a // shard decision, targets a namespace that exists but is currently being // torn down. Distinct from ErrAlreadyExists so REST can render a // different conflict message. ErrNamespaceDeleting = errors.New("namespace is being deleted") // ErrNamespaceGone is returned by apply-time checks when a namespace // the caller validated earlier no longer exists. ErrNamespaceGone = errors.New("namespace no longer exists") // ErrNamespaceNotEmpty is returned by RemoveEntity at the apply layer // when the namespace still owns classes, aliases, or DB users. ErrNamespaceNotEmpty = errors.New("namespace still has owned resources") // ErrInvalidState is a defense-in-depth sentinel for operations called // on a namespace whose current state forbids them (e.g. RemoveEntity on // an active namespace). ErrInvalidState = errors.New("namespace is in an invalid state for this operation") // ErrInvalidStateTransition is returned by ChangeState when the target // state is unreachable from the namespace's current state. ErrInvalidStateTransition = errors.New("invalid namespace state transition") // ErrNamespaceSuspended is returned when an operation targets a suspended // namespace. ErrNamespaceSuspended = errors.New("namespace is suspended") // ErrCollectionSuspended is returned when an operation targets a suspended // collection. ErrCollectionSuspended = errors.New("collection is suspended") // ErrNamespaceResuming is returned when an operation targets a namespace // that is resuming. ErrNamespaceResuming = errors.New("namespace is resuming") // ErrStateChangedConcurrently is returned by ChangeState when the stored // StateChangeIndex no longer matches the one the caller read before // proposing, meaning another state change applied in between. Callers // re-read and decide again rather than retrying blindly. ErrStateChangedConcurrently = errors.New("namespace state changed concurrently") )
Functions ¶
func AdmitDestructiveApply ¶ added in v1.39.1
AdmitDestructiveApply returns nil for an empty name and for the active and deleting states, and an error for every other state and for a missing namespace. Deleting must pass so the cleanup cascade can empty a namespace. A miss refuses rather than admits, so the answer does not rest on nothing being able to exist under a prefix naming no live namespace.
func AdmitReplicationTarget ¶ added in v1.39.1
func AdmitReplicationTarget(state cmd.NamespaceState) error
AdmitReplicationTarget returns nil in every state but deleting, so suspending or resuming a namespace does not fail a replica movement loading or writing to its target shard. It does not verify that a movement is under way, and it decides the target only: a movement is still refused when it opens change capture or snapshots its source, which it re-runs on every dispatch for as long as it is hydrating. The drain that follows reads the source unchecked.
func AppliedChangeMayOpenShard ¶ added in v1.39.1
func AppliedChangeMayOpenShard(state cmd.NamespaceState) bool
AppliedChangeMayOpenShard reports whether an apply whose schema half has already committed may open the shard it just recorded. A suspended namespace allows it even though it holds no shards open: the schema now names a shard this node owns, and a read that finds none answers "shard not found" until a write or a restart under an active namespace registers one. Reclaiming the shard falls to a sweep, which unloads what a suspended namespace should not hold open. Deleting refuses, since that namespace's data is being removed.
func PublicMessage ¶ added in v1.38.6
PublicMessage returns the user-facing text for a namespace lifecycle sentinel. Every caller outside the namespace-management API must render this instead of err: it names neither the namespace nor the concept. ok is false for errors that are not lifecycle sentinels, so callers keep the detail of a genuine internal failure.
func RequireActive ¶ added in v1.38.6
RequireActive returns nil for an empty name or an active namespace, and the error for the namespace's actual state otherwise. Pass "" only for an entity that belongs to no namespace, never for one whose namespace is unknown.
func RequireAllExisting ¶ added in v1.38.12
RequireAllExisting returns nil when every name passes RequireExisting, otherwise one error naming every failing namespace and its state, sorted so the message is stable.
func RequireExisting ¶ added in v1.38.12
RequireExisting returns nil for an empty name or a namespace that exists and is not deleting, and refuses anything else: rows written for a namespace that is gone or going would outlive every cleanup path. Restore uses this rather than RequireActive because a suspended namespace keeps its rows.
func RequireShardLoadable ¶ added in v1.39.1
func RequireShardLoadable(state cmd.NamespaceState) error
RequireShardLoadable returns nil when a request may load one of this namespace's shards. Resuming is refused even though its shards stay open: the namespace is not serving requests yet, so only the resume path may load them.
func ShardsShouldBeOpen ¶ added in v1.39.1
func ShardsShouldBeOpen(state cmd.NamespaceState) bool
ShardsShouldBeOpen reports whether this namespace's state allows a node to hold its shards open. A resuming namespace allows it: the shards have to reopen for the resume to finish.
func ValidateName ¶
ValidateName enforces the package's naming contract. It is the single source of truth for namespace name validation and is called both from the REST handler (for fast 422 rejection without a RAFT round-trip) and from the apply path (as a defense-in-depth check).
Types ¶
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller owns the namespace control-plane state.
Concurrency contract: hashicorp RAFT invokes Snapshot from a goroutine that may run concurrently with Apply, so the RLock inside Snapshot is load-bearing, not cosmetic. Applies are serialized by RAFT (write-lock semantics); queries take the read-lock. Do not remove the Snapshot RLock in a future refactor.
func NewController ¶
func NewController(logger logrus.FieldLogger) *Controller
NewController returns an empty, ready-to-use controller.
func (*Controller) ChangeState ¶
func (c *Controller) ChangeState(name string, target cmd.NamespaceState, sc StateChange) error
ChangeState transitions a namespace into target and records sc.AppliedIndex as the index of that flip. Same-state transitions are idempotent and leave the recorded index alone.
A nonzero sc.ExpectedIndex makes the flip conditional: refused with ErrStateChangedConcurrently unless the stored StateChangeIndex still matches, which stops a re-proposed command from undoing a later flip. It is checked after the same-state short-circuit, so re-applying a committed command still returns nil.
Returns ErrBadRequest when target is unknown or sc.AppliedIndex is 0, ErrNotFound for a missing namespace, and ErrInvalidStateTransition for a forbidden transition.
func (*Controller) Count ¶
func (c *Controller) Count() int
Count returns the number of known namespaces. Used by the startup invariant check.
func (*Controller) Create ¶
func (c *Controller) Create(ns cmd.Namespace, index uint64) error
Create inserts a namespace in the cmd.NamespaceStateActive state, recording index — the RAFT log index of the create command — as its StateChangeIndex. The input's State and StateChangeIndex are ignored, so a caller cannot choose either. HomeNodes must contain exactly one non-empty entry — downstream placement and counters rely on that invariant. Returns ErrBadRequest for invalid names, HomeNodes, or a zero index, ErrAlreadyExists when the name maps to an active namespace, and ErrNamespaceDeleting when the name is currently being torn down.
func (*Controller) Get ¶
func (c *Controller) Get(names ...string) []cmd.Namespace
Get returns the named namespaces. An empty Names slice returns all known namespaces; otherwise only the named ones that exist are returned (missing names are silently omitted).
func (*Controller) GetNamespace ¶
func (c *Controller) GetNamespace(name string) (ns cmd.Namespace, ok bool)
GetNamespace returns a snapshot copy of the namespace by name. ok is false when the namespace does not exist.
func (*Controller) List ¶
func (c *Controller) List() []cmd.Namespace
List returns a snapshot copy of all namespaces. Intended for callers that need to iterate without holding the lock.
func (*Controller) ListDeleting ¶
func (c *Controller) ListDeleting() []string
ListDeleting returns the names of namespaces currently in the deleting state, sorted lexicographically.
func (*Controller) RemoveEntity ¶
func (c *Controller) RemoveEntity(name string) error
RemoveEntity removes the namespace map entry. Callable only on a namespace already marked for deletion; an active namespace returns ErrInvalidState. Returns ErrNotFound when the namespace does not exist.
func (*Controller) Restore ¶
func (c *Controller) Restore(snapshot []byte) error
Restore replaces the current state with the snapshot contents. A nil, empty or "null" snapshot leaves state empty (fresh bootstrap). Unknown JSON fields are tolerated. Entries with empty State are normalized to cmd.NamespaceStateActive; entries with an unknown State return an error so a future binary's snapshot is not silently mis-classified. Entries missing the single HomeNodes entry are also rejected — there is no migration path from a pre-HomeNodes snapshot.
func (*Controller) Snapshot ¶
func (c *Controller) Snapshot() ([]byte, error)
Snapshot serializes the entire namespace map. See the Controller godoc for why the read lock is required even though Apply is single-threaded.
func (*Controller) Update ¶
func (c *Controller) Update(ns cmd.Namespace) error
Update overwrites the stored HomeNodes for an existing namespace. HomeNodes must contain exactly one non-empty entry; Name, State and StateChangeIndex are immutable here. Returns ErrBadRequest for an invalid HomeNodes, ErrNotFound when the namespace does not exist, and ErrNamespaceDeleting when the namespace is being torn down.
type Exister ¶
Exister exposes read-only access to namespace state. Rather than comparing State themselves, callers go through RequireActive or AdmitDestructiveApply, or through ShardsShouldBeOpen / RequireShardLoadable to decide about a shard.
type MockExister ¶
MockExister is an autogenerated mock type for the Exister type
func NewMockExister ¶
func NewMockExister(t interface {
mock.TestingT
Cleanup(func())
}) *MockExister
NewMockExister creates a new instance of MockExister. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. The first argument is typically a *testing.T value.
func NewMockExisterInState ¶ added in v1.38.12
func NewMockExisterInState(t *testing.T, states map[string]api.NamespaceState) *MockExister
NewMockExisterInState returns an Exister whose GetNamespace reports each named namespace in the given state and every other name as missing.
func (*MockExister) EXPECT ¶
func (_m *MockExister) EXPECT() *MockExister_Expecter
func (*MockExister) GetNamespace ¶
func (_m *MockExister) GetNamespace(name string) (api.Namespace, bool)
GetNamespace provides a mock function with given fields: name
type MockExister_Expecter ¶
type MockExister_Expecter struct {
// contains filtered or unexported fields
}
func (*MockExister_Expecter) GetNamespace ¶
func (_e *MockExister_Expecter) GetNamespace(name interface{}) *MockExister_GetNamespace_Call
GetNamespace is a helper method to define mock.On call
- name string
type MockExister_GetNamespace_Call ¶
MockExister_GetNamespace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNamespace'
func (*MockExister_GetNamespace_Call) Return ¶
func (_c *MockExister_GetNamespace_Call) Return(_a0 api.Namespace, _a1 bool) *MockExister_GetNamespace_Call
func (*MockExister_GetNamespace_Call) Run ¶
func (_c *MockExister_GetNamespace_Call) Run(run func(name string)) *MockExister_GetNamespace_Call
func (*MockExister_GetNamespace_Call) RunAndReturn ¶
func (_c *MockExister_GetNamespace_Call) RunAndReturn(run func(string) (api.Namespace, bool)) *MockExister_GetNamespace_Call
type StateChange ¶ added in v1.38.7
type StateChange struct {
// AppliedIndex is this apply's RAFT log index. A successful flip stores
// it as the namespace's new StateChangeIndex.
AppliedIndex uint64
// ExpectedIndex is the StateChangeIndex the flip requires the namespace
// to still be at. 0 skips the check.
ExpectedIndex uint64
}
StateChange carries the two RAFT indexes a state flip needs: one is written, the other is compared. Named fields rather than two uint64 parameters, which a caller could swap without the compiler noticing.