Documentation
¶
Index ¶
- func ClaimFits(ctx context.Context, namespace, poolName, path string, size int64) (bool, string, error)
- func ClaimHeldByPath(ctx context.Context, c *client.T, namespace, poolName string) (map[string]int64, error)
- func ClaimLimit(namespace, poolName string) (int64, bool, error)
- func ClaimProbe(ctx context.Context, namespace, poolName, path string, size int64) (bool, string, error)
- func ConfigureVolume(ctx context.Context, p Pooler, vol Volumer, namespace, path string, size int64, ...) error
- func CopySize(p Pooler, logical int64) int64
- func DiskName(p Pooler, vol Volumer) string
- func Driver(t string) func() Pooler
- func GetMappings(ctx context.Context, p ArrayPooler, nodes []string, pathType string) (array.Mappings, error)
- func GetPaths(ctx context.Context, p ArrayPooler, nodes []string, pathType string) (san.Paths, error)
- func HasAccess(p Pooler, acs volaccess.T) bool
- func HasCapability(p Pooler, s Capability) bool
- func InitData()
- func LogicalSize(p Pooler, physical int64) int64
- func MappingsFromPaths(paths san.Paths) (array.Mappings, error)
- func MountPointFromName(name string) string
- func UsageByNode(ctx context.Context) (map[string]map[string]Usage, error)
- type ArrayPooler
- type BlkTranslater
- type By
- type Capabilities
- type Capability
- type Config
- type CopyCoster
- type Data
- type DataElement
- type Dataer
- type Disk
- type FS
- type Grant
- type Grants
- func (t *Grants) ExpiresAt(now time.Time) time.Time
- func (t *Grants) Fits(namespace, poolName, path string, to, limit int64, held map[string]int64, ...) (bool, string)
- func (t *Grants) Probe(namespace, poolName, path string, to, limit int64, held map[string]int64, ...) (bool, string)
- func (t *Grants) Seed(namespace, poolName, path string, to int64, now time.Time)
- func (t *Grants) WithFormat(format func(int64) string) *Grants
- type Lookup
- type Pooler
- type Status
- type StatusItem
- type StatusList
- type T
- func (t *T) Config() Config
- func (t *T) FSType() string
- func (t *T) GetBool(s string) bool
- func (t *T) GetInt(s string) int
- func (t *T) GetSize(s string) *int64
- func (t *T) GetString(s string) string
- func (t *T) GetStringAs(s, nodename string) string
- func (t *T) GetStrings(s string) []string
- func (t *T) Mappings() map[string]string
- func (t *T) MkblkOptions() string
- func (t *T) MkfsOptions() string
- func (t *T) MntOptions() string
- func (t T) Name() string
- func (t T) Separator() string
- func (t *T) SetConfig(c Config)
- func (t *T) SetDriver(driver string)
- func (t *T) SetName(name string)
- func (t T) Type() string
- type Translater
- type Usage
- type VolumeStatus
- type VolumeStatusList
- type Volumer
- type WeightedPools
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ClaimHeldByPath ¶
func ClaimHeldByPath(ctx context.Context, c *client.T, namespace, poolName string) (map[string]int64, error)
ClaimHeldByPath is what each volume of a namespace claims of a pool, counting the size it was created or resized with.
It counts what was asked for, not what is written: a pool hands out what it promised, and that promise is what is being rationed.
It is answered by object rather than as a sum because a claim granted a moment ago and not yet written has to be weighed against it, and weighing the two means knowing which object each is about.
func ClaimLimit ¶
ClaimLimit is the most a namespace may claim of a pool, and whether it is capped on it at all.
func ClaimProbe ¶
func ClaimProbe(ctx context.Context, namespace, poolName, path string, size int64) (bool, string, error)
ClaimFits says whether a namespace may have an object hold size bytes of a pool, and why not when it may not.
The size is what the object is to hold, not the increase: what it holds today is already counted in what the namespace holds, and is not claimed twice.
A namespace with no claim on the pool is not capped on it, and is answered from the local configuration alone, which is what most allocations are.
A capped one is brokered. The claim is asked of the daemon, which hands the question to the node speaking for the cluster: what the namespace holds is read from the configurations the cluster shares, a write reaches that reading a moment after it is made, and two claims answered from the same reading both fit where together they do not. One node answering them, counting what it has granted since, is what makes them fit one at a time.
Failing to reach the daemon leaves the claim unchecked rather than refused: a cap is something the cluster brokers, and where there is no daemon to ask there is nothing brokering. Allocating with the daemon down is an administrator acting directly, which is uncapped by design, and stopping a daemon is not something the capped user can do. ClaimProbe is ClaimFits without taking the claim: it says whether the namespace may have the object hold the size, and counts nothing as taken.
A pool lookup weighs every pool it could serve the volume from and writes to one of them. Taking the claim of each would ration the namespace on the pools it was only compared against.
func ConfigureVolume ¶
func CopySize ¶
CopySize is what one copy of a volume costs the storage behind a pool.
It is the size the volume hands out, unless the driver says otherwise.
func GetMappings ¶
func HasCapability ¶
func HasCapability(p Pooler, s Capability) bool
func LogicalSize ¶
LogicalSize is what a pool holding this many bytes can hand out to volumes.
It is the same number, unless the driver says otherwise.
func MountPointFromName ¶
func UsageByNode ¶
UsageByNode is what each node holds of the pools, as the daemon knows it.
The pool of a node is read from the node itself, and a node cannot read the pool of a peer, so this is asked of the daemon: it is where every node reports what its storage holds. Every pool is asked for rather than the one in question, because a node that reports no pool at all and a node that reports every pool but this one are not the same thing: the first has not reported yet, the second says the pool is not one of its.
Types ¶
type ArrayPooler ¶
type BlkTranslater ¶
type Capabilities ¶
type Capabilities []Capability
func (Capabilities) String ¶
func (t Capabilities) String() string
func (Capabilities) StringSlice ¶
func (t Capabilities) StringSlice() []string
type Capability ¶
type Capability string
const ( CapBlk Capability = "blk" CapFile Capability = "file" CapMove Capability = "move" CapROO Capability = "roo" CapROX Capability = "rox" CapRWO Capability = "rwo" CapRWX Capability = "rwx" CapSnap Capability = "snap" CapVolatile Capability = "volatile" )
type CopyCoster ¶
type CopyCoster interface {
// CopySize is what one copy of a volume of this size costs the
// storage behind the pool.
CopySize(logical int64) int64
// LogicalSize is what the pool can hand out to volumes, holding this
// many bytes of storage.
LogicalSize(physical int64) int64
}
CopyCoster is implemented by a pool whose storage holds a copy of a volume in something other than the size the volume hands out: an array that compresses holds less of it, one keeping a fixed overhead per volume holds more.
Both directions are asked of the driver rather than derived from one another, because a relation is not always a ratio: an overhead per volume does not divide, and a driver that rounds does not invert.
The replication is not this: a pool whose storage is not shared holds a copy of a volume on every node the volume has an instance on, which is counted where the nodes are known.
type Data ¶
Data defines a shared holder for all pool Dataer
var ( // StatusData is the package data holder for all instances statuses StatusData *Data[Status] )
func (*Data[T]) Get ¶
func (c *Data[T]) Get(name, node string) *T
Get returns a pool data or nil if data is not found
func (*Data[T]) GetAll ¶
func (c *Data[T]) GetAll() []DataElement[T]
GetAll returns all pool data as a list of DataElements
func (*Data[T]) GetByName ¶
func (c *Data[T]) GetByName(name string) []DataElement[T]
GetByName returns pool instances on a specific node as a list of DataElements
func (*Data[T]) GetByNode ¶
func (c *Data[T]) GetByNode(nodename string) []DataElement[T]
GetByNode returns pool instances on a specific node as a list of DataElements
type DataElement ¶
type FS ¶
type Grant ¶
type Grant struct {
// To is the size the object was let hold, which is what it will
// claim of the pool once its configuration is written.
To int64
// ExpiresAt is when the grant stops being counted. A claim answered
// yes is not always written: the write can fail after the answer, or
// the caller can go away between the two, and a grant nothing ever
// claims would ration the namespace for ever.
ExpiresAt time.Time
}
Grant is a claim answered yes and not yet seen in the configurations the cluster shares.
type Grants ¶
type Grants struct {
// contains filtered or unexported fields
}
Grants is what a node has let namespaces take of the pools, waiting for the configurations saying so to come back around.
A claim counts the size each volume of the namespace is configured to hold, read from the configurations the cluster shares. A write reaches that reading a moment after it is made, so a claim answered from it alone misses everything granted since: three volumes grown one after the other each read the sizes of before the first grow. Counting the grants too closes that window, and holding them here is what makes the answer and the record one step rather than two.
func (*Grants) Fits ¶
func (t *Grants) Fits(namespace, poolName, path string, to, limit int64, held map[string]int64, now time.Time) (bool, string)
Fits says whether the namespace may have an object hold to bytes of a pool, and records the grant when it may.
held is the size each volume of the namespace is configured to hold of the pool, by object path, which is the reading the grants complete.
What is weighed is what the namespace would hold once the write lands: every other object counts for the larger of what its configuration says and what it was let take, and the object asked about counts for the size asked for. So asking twice for the same size is answered the same way twice, and a grant stops adding anything as soon as the configuration it was granted for says the same thing.
func (*Grants) Probe ¶
func (t *Grants) Probe(namespace, poolName, path string, to, limit int64, held map[string]int64, now time.Time) (bool, string)
Probe says whether the namespace may have an object hold to bytes of a pool, and records nothing.
It is what a pool lookup asks of every pool it weighs: a claim is taken where a volume is written, and a pool the lookup only looked at is a pool nothing was written to. Recording there would ration the namespace on every pool it was compared against, for as long as a grant lasts.
func (*Grants) Seed ¶
Seed records a grant this node did not answer.
It is how a table lost is rebuilt. The grants of a node are in memory, so a node that has just started, or has just become the one answering claims, has none of them and answers from the configurations the cluster shares alone, which is the reading the grants exist to complete.
What was granted and written is not lost, though: it is on the node that wrote it, whose own reading of it has no lag. What was granted and never written is lost, and expiring is what would have become of it anyway.
A grant already held for the object is left alone unless the seed is larger, so rebuilding cannot lower what a namespace is counted as holding.
type Lookup ¶
type Lookup struct {
Name string
Type string
Access volaccess.T
Size int64
Namespace string
// Path is the volume the storage is looked up for, which the claim
// on the pool is granted to. It is empty where the lookup is not
// about a volume of its own, and the grant is then held until it
// expires rather than until the volume says it was claimed.
Path string
Format bool
Usage bool
Volatile bool
Nodes []string
// contains filtered or unexported fields
}
func (Lookup) ConfigureVolume ¶
type Pooler ¶
type Status ¶
type Status struct {
Usage
Capabilities Capabilities `json:"capabilities"`
Errors []string `json:"errors"`
Head string `json:"head"`
Type string `json:"type"`
UpdatedAt time.Time `json:"updated_at"`
VolumeCount int `json:"volume_count"`
}
func (*Status) HasCapability ¶
func (t *Status) HasCapability(s Capability) bool
type StatusItem ¶
type StatusList ¶
type StatusList []StatusItem
func NewStatusList ¶
func NewStatusList() StatusList
func (StatusList) Add ¶
func (t StatusList) Add(ctx context.Context, p Pooler, withUsage bool) StatusList
func (StatusList) Len ¶
func (t StatusList) Len() int
func (StatusList) Less ¶
func (t StatusList) Less(i, j int) bool
func (StatusList) Swap ¶
func (t StatusList) Swap(i, j int)
type T ¶
type T struct {
// contains filtered or unexported fields
}
func (*T) GetStringAs ¶
func (*T) GetStrings ¶
func (*T) MkblkOptions ¶
func (*T) MkfsOptions ¶
func (*T) MntOptions ¶
type Translater ¶
type Usage ¶
type Usage struct {
// Free unit is Bytes
Free int64 `json:"free"`
// Used unit is Bytes
Used int64 `json:"used"`
// Size unit is Bytes
Size int64 `json:"size"`
// LogicalFree unit is Bytes
LogicalFree int64 `json:"logical_free"`
// LogicalUsed unit is Bytes
LogicalUsed int64 `json:"logical_used"`
// LogicalSize unit is Bytes
LogicalSize int64 `json:"logical_size"`
}
Usage is what a pool holds, in the two currencies a pool is counted in.
The physical figures are what the storage behind the pool really holds. The logical ones are what the pool can hand out as volume sizes, which is the currency a volume is asked for in, a claim is written in, and a limit rations. The two differ wherever a copy of a volume costs the storage something other than the size it hands out.
type VolumeStatus ¶
type VolumeStatusList ¶
type VolumeStatusList []VolumeStatus
func (VolumeStatusList) Len ¶
func (t VolumeStatusList) Len() int
func (VolumeStatusList) Less ¶
func (t VolumeStatusList) Less(i, j int) bool
func (VolumeStatusList) Swap ¶
func (t VolumeStatusList) Swap(i, j int)
type WeightedPools ¶
type WeightedPools []Pooler