utils

package
v0.1.0-alpha.10-rc1 Latest Latest
Warning

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

Go to latest
Published: May 24, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrTopologyNameMissing indicates that a constrained level has no effective topologyName after inheritance is applied.
	ErrTopologyNameMissing = errors.New("topology constraints require an explicit or inherited topologyName")
	// ErrPackDomainMissing indicates that a topologyConstraint exists but does not specify packDomain.
	ErrPackDomainMissing = errors.New("topology constraints require packDomain")
	// ErrMultipleTopologyNamesUnsupported indicates that topology constraints within a single PCS reference different topology names.
	ErrMultipleTopologyNamesUnsupported = errors.New("multiple topology names within a single PodCliqueSet are not supported")
)

Functions

func AddEnvVarsToContainers

func AddEnvVarsToContainers(containers []corev1.Container, envVars []corev1.EnvVar)

AddEnvVarsToContainers adds the given environment variables to the Pod containers.

func ArePodGangsAvailable

func ArePodGangsAvailable(ctx context.Context, cl client.Client, namespace string, names []string) (bool, error)

ArePodGangsAvailable returns true when every named PodGang exists in the given namespace and reports PodGangConditionTypeAvailable. Returns false (with a nil error) if any PodGang is not found or has not yet reached Available. Returns an error only on unexpected API failures (anything other than NotFound).

func ComputePCLQPodTemplateHash

func ComputePCLQPodTemplateHash(pclqTemplateSpec *grovecorev1alpha1.PodCliqueTemplateSpec, priorityClassName string) string

ComputePCLQPodTemplateHash computes the pod template hash for the PCLQ pod spec.

func CountStandalonePCLQs

func CountStandalonePCLQs(pcs *grovecorev1alpha1.PodCliqueSet) int

CountStandalonePCLQs returns the number of standalone PodCliques defined in the PCS template. A standalone PodClique is one whose name does not appear in any PodCliqueScalingGroupConfig.CliqueNames.

func FilterPodGangMapEntriesByGenerationHash

func FilterPodGangMapEntriesByGenerationHash(entries []grovecorev1alpha1.PodGangEntry, hash string) []grovecorev1alpha1.PodGangEntry

FilterPodGangMapEntriesByGenerationHash returns entries that match the given PodCliqueSetGenerationHash.

func FindExplicitTopologyNameForPodCliqueSet

func FindExplicitTopologyNameForPodCliqueSet(pcs *grovecorev1alpha1.PodCliqueSet) (string, error)

FindExplicitTopologyNameForPodCliqueSet returns one explicit topologyName from the PCS. It is intended for callers operating on already-validated PCS objects where all explicit topologyName values are expected to match. Callers that need to distinguish "no topology constraints at all" from missing explicit topologyName values must first call HasAnyTopologyConstraint.

func FindPodCliqueTemplateSpecByName

func FindPodCliqueTemplateSpecByName(pcs *grovecorev1alpha1.PodCliqueSet, pclqName string) *grovecorev1alpha1.PodCliqueTemplateSpec

FindPodCliqueTemplateSpecByName retrieves the PodCliqueTemplateSpec from the PodCliqueSet by its name. If there is no matching PodCliqueTemplateSpec, it returns nil.

func FindScalingGroupConfigByName

func FindScalingGroupConfigByName(pcs *grovecorev1alpha1.PodCliqueSet, pcsgConfigName string) *grovecorev1alpha1.PodCliqueScalingGroupConfig

FindScalingGroupConfigByName retrieves the PodCliqueScalingGroupConfig from the PodCliqueSet by its name. Returns nil if no scaling group config with the given name exists in the PCS spec.

func FindScalingGroupConfigForClique

func FindScalingGroupConfigForClique(scalingGroupConfigs []grovecorev1alpha1.PodCliqueScalingGroupConfig, cliqueName string) *grovecorev1alpha1.PodCliqueScalingGroupConfig

FindScalingGroupConfigForClique searches through the scaling group configurations to find the one that contains the specified clique name in its CliqueNames list.

Returns the matching PodCliqueScalingGroupConfig and true if found, or an empty config and false if not found.

func GenerateDependencyNamesForBasePodGang

func GenerateDependencyNamesForBasePodGang(pcs *grovecorev1alpha1.PodCliqueSet, pcsReplicaIndex int, parentCliqueName string) []string

GenerateDependencyNamesForBasePodGang generates the FQNs of all PodCliques that would qualify as a dependency.

func GetExistingPodGangs

func GetExistingPodGangs(ctx context.Context, cl client.Client, pcsObjectMeta metav1.ObjectMeta, namespace string) ([]groveschedulerv1alpha1.PodGang, error)

GetExistingPodGangs fetches all existing PodGangs that are managed by Grove in the given namespace.

func GetExpectedPCLQNamesGroupByOwner

func GetExpectedPCLQNamesGroupByOwner(pcs *grovecorev1alpha1.PodCliqueSet) (expectedPCLQNamesForPCS []string, expectedPCLQNamesForPCSG []string)

GetExpectedPCLQNamesGroupByOwner returns the expected unqualified PodClique names which are either owned by PodCliqueSet or PodCliqueScalingGroup.

func GetExpectedPCLQPodTemplateHash

func GetExpectedPCLQPodTemplateHash(pcs *grovecorev1alpha1.PodCliqueSet, pclqObjectMeta metav1.ObjectMeta) (string, error)

GetExpectedPCLQPodTemplateHash finds the matching PodCliqueTemplateSpec from the PodCliqueSet and computes the pod template hash for the PCLQ pod spec.

func GetExpectedPCSGFQNsForPCS

func GetExpectedPCSGFQNsForPCS(pcs *grovecorev1alpha1.PodCliqueSet) []string

GetExpectedPCSGFQNsForPCS computes the FQNs for all PodCliqueScalingGroups defined in PCS for the given replica.

func GetExpectedPCSGFQNsPerPCSReplica

func GetExpectedPCSGFQNsPerPCSReplica(pcs *grovecorev1alpha1.PodCliqueSet) map[int][]string

GetExpectedPCSGFQNsPerPCSReplica computes the FQNs for all PodCliqueScalingGroups defined in PCS for each replica.

func GetExpectedStandAlonePCLQFQNsPerPCSReplica

func GetExpectedStandAlonePCLQFQNsPerPCSReplica(pcs *grovecorev1alpha1.PodCliqueSet) map[int][]string

GetExpectedStandAlonePCLQFQNsPerPCSReplica computes the FQNs for all standalone PodCliques defined in PCS for each replica.

func GetMinAvailableBreachedPCLQInfo

func GetMinAvailableBreachedPCLQInfo(pclqs []grovecorev1alpha1.PodClique, terminationDelay time.Duration, since time.Time) ([]string, time.Duration)

GetMinAvailableBreachedPCLQInfo filters PodCliques that have grovecorev1alpha1.ConditionTypeMinAvailableBreached set to true. For each such PodClique it returns the name of the PodClique a duration to wait for before terminationDelay is breached.

func GetPCLQPods

func GetPCLQPods(ctx context.Context, cl client.Client, _ string, pclq *grovecorev1alpha1.PodClique) ([]*corev1.Pod, error)

GetPCLQPods lists all Pods that belong to a PodClique. The selector uses only LabelPodClique because the PodClique name is unique across the cluster; filtering on the parent managed-by/part-of labels would add two more per-pod labels.Set.Lookup calls per match with no correctness benefit. Ownership is still validated by IsControlledBy below.

When ctx carries a cache from WithPCLQPodsCache, the first call populates the cache and subsequent calls in the same reconcile return the cached slice without hitting the informer.

func GetPCLQTemplateHashes

GetPCLQTemplateHashes generates the Pod template hash for all PCLQs in a PCSG. Returns a map of PCLQ FQN → pod-template-hash. The hash is invariant per clique, so it is computed once per clique name and reused across every PCSG replica that materializes that clique.

func GetPCLQsByOwner

func GetPCLQsByOwner(ctx context.Context, cl client.Client, ownerKind string, ownerObjectKey client.ObjectKey, selectorLabels map[string]string) ([]grovecorev1alpha1.PodClique, error)

GetPCLQsByOwner retrieves PodClique objects that are owned by the specified owner kind and object key, and match the provided selector labels.

func GetPCLQsByOwnerReplicaIndex

func GetPCLQsByOwnerReplicaIndex(ctx context.Context, cl client.Client, ownerKind string, ownerObjectKey client.ObjectKey, selectorLabels map[string]string) (map[int][]grovecorev1alpha1.PodClique, error)

GetPCLQsByOwnerReplicaIndex retrieves PodClique objects per replica of the owner resource matching provided selector labels.

func GetPCLQsInPCSGPendingUpdate

func GetPCLQsInPCSGPendingUpdate(pcs *grovecorev1alpha1.PodCliqueSet, pcsg *grovecorev1alpha1.PodCliqueScalingGroup, existingPCLQs []grovecorev1alpha1.PodClique) []string

GetPCLQsInPCSGPendingUpdate collects the PodClique FQNs that are pending updates. It identifies PCLQ pending update by comparing the current PodTemplateHash label on an existing PCLQ with that of a computed PodTemplateHash from the latest PodCliqueSet resource.

func GetPCLQsMatchingLabels

func GetPCLQsMatchingLabels(ctx context.Context, cl client.Client, namespace string, selectorLabels map[string]string) ([]grovecorev1alpha1.PodClique, error)

GetPCLQsMatchingLabels gets all the PodClique's in a given namespace matching selectorLabels.

func GetPCSGMinAvailableFromPCSTemplateSpec

func GetPCSGMinAvailableFromPCSTemplateSpec(pcs *grovecorev1alpha1.PodCliqueSet) map[string]int32

GetPCSGMinAvailableFromPCSTemplateSpec returns the minAvailable replica count per PCSG from the PCS spec.

func GetPCSGReplicasFromPCSTemplateSpec

func GetPCSGReplicasFromPCSTemplateSpec(pcs *grovecorev1alpha1.PodCliqueSet) map[string]int32

GetPCSGReplicasFromPCSTemplateSpec returns the total replica count per PCSG from the PCS spec.

func GetPCSGsByPCSReplicaIndex

func GetPCSGsByPCSReplicaIndex(ctx context.Context, cl client.Client, pcsObjKey client.ObjectKey) (map[int][]grovecorev1alpha1.PodCliqueScalingGroup, error)

GetPCSGsByPCSReplicaIndex groups the PodCliqueScalingGroups per PodCliqueSet replica index and returns a map with the key being the PodCliqueSet replica index and the value being the slice of PodCliqueScalingGroup objects.

func GetPodCliqueFQNsForPCSG

func GetPodCliqueFQNsForPCSG(pcsg *grovecorev1alpha1.PodCliqueScalingGroup) []string

GetPodCliqueFQNsForPCSG generates the PodClique FQNs for all PodCliques that are owned by a PodCliqueScalingGroup.

func GetPodCliqueFQNsForPCSNotInPCSG

func GetPodCliqueFQNsForPCSNotInPCSG(pcs *grovecorev1alpha1.PodCliqueSet) []string

GetPodCliqueFQNsForPCSNotInPCSG computes the FQNs for all PodCliques for all PCS replicas which are not part of any PCSG.

func GetPodCliqueSet

func GetPodCliqueSet(ctx context.Context, cl client.Client, objectMeta metav1.ObjectMeta) (*grovecorev1alpha1.PodCliqueSet, error)

GetPodCliqueSet gets the owner PodCliqueSet object. When the context carries a cache from WithPodCliqueSetCache, the first lookup populates it and subsequent calls skip the Get. The returned pointer is the cached instance — callers must not mutate it in place.

func GetPodCliqueSetName

func GetPodCliqueSetName(objectMeta metav1.ObjectMeta) string

GetPodCliqueSetName retrieves the PodCliqueSet name from the labels of the given ObjectMeta. NOTE: It is assumed that all managed objects like PCSG, PCLQ and Pods will always have PCS name as value for grovecorev1alpha1.LabelPartOfKey label. It should be ensured that labels that are set by the operator are never removed.

func GetPodCliquesWithParentPCS

func GetPodCliquesWithParentPCS(ctx context.Context, cl client.Client, pcsObjKey client.ObjectKey) ([]grovecorev1alpha1.PodClique, error)

GetPodCliquesWithParentPCS retrieves PodClique objects that are not part of any PodCliqueScalingGroup for the given PodCliqueSet.

func GetPodGang

func GetPodGang(ctx context.Context, cl client.Client, podGangName, namespace string) (*groveschedulerv1alpha1.PodGang, error)

GetPodGang fetches a PodGang by name and namespace.

func GetPodGangMap

func GetPodGangMap(ctx context.Context, cl client.Client, podGangMapName, namespace string) (*grovecorev1alpha1.PodGangMap, error)

GetPodGangMap fetches a PodGangMap by name and namespace.

func GetPodGangMapEntriesForPCLQ

func GetPodGangMapEntriesForPCLQ(entries []grovecorev1alpha1.PodGangEntry, pclqName string) []grovecorev1alpha1.PodGangEntry

GetPodGangMapEntriesForPCLQ returns all entries that reference the given standalone PodClique name.

func GetPodGangMapEntriesForPCSG

func GetPodGangMapEntriesForPCSG(entries []grovecorev1alpha1.PodGangEntry, pcsgName string) []grovecorev1alpha1.PodGangEntry

GetPodGangMapEntriesForPCSG returns all entries that reference the given PodCliqueScalingGroup name.

func GetPodGangMapForPCSReplica

func GetPodGangMapForPCSReplica(ctx context.Context, cl client.Client, pcsName, namespace string, pcsReplicaIndex int) (*grovecorev1alpha1.PodGangMap, error)

GetPodGangMapForPCSReplica fetches the PodGangMap for a given PCS replica.

func GetPodGangSelectorLabels

func GetPodGangSelectorLabels(pcsObjMeta metav1.ObjectMeta) map[string]string

GetPodGangSelectorLabels creates the label selector to list all the PodGangs for a PodCliqueSet.

func GetStandalonePCLQFQNSet

func GetStandalonePCLQFQNSet(pcs *grovecorev1alpha1.PodCliqueSet, pcsReplicaIndex int) sets.Set[string]

GetStandalonePCLQFQNSet returns a set of fully-qualified names of all standalone PodCliques for a given PCS replica. A standalone PodClique is one whose name does not appear in any PodCliqueScalingGroupConfig.CliqueNames in the PCS template.

func GetStandalonePCLQFQNs

func GetStandalonePCLQFQNs(pcs *grovecorev1alpha1.PodCliqueSet, pcsReplicaIndex int) []string

GetStandalonePCLQFQNs returns the fully-qualified names of all standalone PodCliques for a given PCS replica as a slice. See GetStandalonePCLQFQNSet for the definition of standalone.

func GetStandalonePCLQMinAvailableFromPCSTemplateSpec

func GetStandalonePCLQMinAvailableFromPCSTemplateSpec(pcs *grovecorev1alpha1.PodCliqueSet) map[string]int32

GetStandalonePCLQMinAvailableFromPCSTemplateSpec returns the minAvailable pod count per standalone PCLQ from the PCS spec.

func GetStandalonePCLQReplicasFromPCSTemplateSpec

func GetStandalonePCLQReplicasFromPCSTemplateSpec(pcs *grovecorev1alpha1.PodCliqueSet) map[string]int32

GetStandalonePCLQReplicasFromPCSTemplateSpec returns the total replica count per standalone PCLQ from the PCS spec.

func GetUniqueTopologyDomainsInPodCliqueSet

func GetUniqueTopologyDomainsInPodCliqueSet(pcs *grovecorev1alpha1.PodCliqueSet) []grovecorev1alpha1.TopologyDomain

GetUniqueTopologyDomainsInPodCliqueSet returns all unique, non-empty pack domains referenced by the PCS.

func GroupPCLQsByPCSGReplicaIndex

func GroupPCLQsByPCSGReplicaIndex(pclqs []grovecorev1alpha1.PodClique) (map[int][]grovecorev1alpha1.PodClique, error)

GroupPCLQsByPCSGReplicaIndex filters PCLQs that have a PodCliqueScalingGroupReplicaIndex label and groups them by the PCSG replica.

func GroupPCLQsByPCSReplicaIndex

func GroupPCLQsByPCSReplicaIndex(pclqs []grovecorev1alpha1.PodClique) (map[int][]grovecorev1alpha1.PodClique, error)

GroupPCLQsByPCSReplicaIndex filters PCLQs that have a PodCliqueSetReplicaIndex label and groups them by the PCS replica.

func GroupPCLQsByPodGangName

func GroupPCLQsByPodGangName(pclqs []grovecorev1alpha1.PodClique) map[string][]grovecorev1alpha1.PodClique

GroupPCLQsByPodGangName filters PCLQs that have a PodGang label and groups them by the PodGang name.

func GroupPCSGsByPCSReplicaIndex

func GroupPCSGsByPCSReplicaIndex(pcsgs []grovecorev1alpha1.PodCliqueScalingGroup) (map[int][]grovecorev1alpha1.PodCliqueScalingGroup, error)

GroupPCSGsByPCSReplicaIndex filters PCSGs that have a PodCliqueSetReplicaIndex label and groups them by the PCS replica.

func HasAnyTopologyConstraint

func HasAnyTopologyConstraint(pcs *grovecorev1alpha1.PodCliqueSet) bool

HasAnyTopologyConstraint reports whether the PCS contains a topology constraint at any supported level.

func IsAutoUpdateStrategy

func IsAutoUpdateStrategy(pcs *grovecorev1alpha1.PodCliqueSet) bool

IsAutoUpdateStrategy returns true when PodCliqueSet update strategy is automatically orchestrated by Grove. Only the OnDelete update strategy is not an auto update strategy. Deprecated: Use IsOnDeleteStrategy, IsCoherentStrategy, or IsRollingRecreateUpdateInProgress for explicit checks.

func IsCoherentStrategy

func IsCoherentStrategy(pcs *grovecorev1alpha1.PodCliqueSet) bool

IsCoherentStrategy returns true when the PodCliqueSet update strategy is Coherent.

func IsCoherentUpdateInProgress

func IsCoherentUpdateInProgress(pcs *grovecorev1alpha1.PodCliqueSet) bool

IsCoherentUpdateInProgress returns true when a Coherent update has been initiated and not yet completed.

func IsLastPCLQUpdateCompleted

func IsLastPCLQUpdateCompleted(pclq *grovecorev1alpha1.PodClique) bool

IsLastPCLQUpdateCompleted checks if the last update of PodClique is completed. For auto update strategies, it returns if all Pods of the PodClique have been updated with the new specification. For the OnDelete strategy, it returns whether the PodClique controller has processed the update by refreshing all hash fields in the PodCliqueStatus, based on which PodCliqueStatus.UpdatedReplicas are calculated.

func IsOnDeleteStrategy

func IsOnDeleteStrategy(pcs *grovecorev1alpha1.PodCliqueSet) bool

IsOnDeleteStrategy returns true when the PodCliqueSet update strategy is OnDelete.

func IsPCLQAutoUpdateInProgress

func IsPCLQAutoUpdateInProgress(pclq *grovecorev1alpha1.PodClique) bool

IsPCLQAutoUpdateInProgress checks if PodClique is under an auto-orchestrated update.

func IsPCSGUpdateComplete

func IsPCSGUpdateComplete(pcsg *grovecorev1alpha1.PodCliqueScalingGroup, pcsGenerationHash string) bool

IsPCSGUpdateComplete returns whether the rolling update of the PodCliqueScalingGroup is complete.

func IsPCSGUpdateInProgress

func IsPCSGUpdateInProgress(pcsg *grovecorev1alpha1.PodCliqueScalingGroup) bool

IsPCSGUpdateInProgress checks if PCSG is under rolling update.

func IsRollingRecreateUpdateInProgress

func IsRollingRecreateUpdateInProgress(pcs *grovecorev1alpha1.PodCliqueSet) bool

IsRollingRecreateUpdateInProgress returns true when a RollingRecreate update has been initiated and not yet completed.

func IsStandalonePCLQ

func IsStandalonePCLQ(pclq *grovecorev1alpha1.PodClique) bool

IsStandalonePCLQ checks if the given PCLQ is a standalone PCLQ. A PCLQ is considered standalone when its owner is PCS.

func ListPCSGsForPCS

func ListPCSGsForPCS(ctx context.Context, cl client.Client, pcsObjKey client.ObjectKey) ([]grovecorev1alpha1.PodCliqueScalingGroup, error)

ListPCSGsForPCS fetches all PodCliqueScalingGroups for a PodCliqueSet.

func PCSGByName

PCSGByName builds a name-keyed map for O(1) PodCliqueScalingGroup lookups.

func PodCliqueByName

func PodCliqueByName(pclqs []grovecorev1alpha1.PodClique) map[string]grovecorev1alpha1.PodClique

PodCliqueByName builds a name-keyed map for O(1) PodClique lookups.

func PodGangByName

PodGangByName builds a name-keyed map for O(1) PodGang lookups.

func PodsToObjectNames

func PodsToObjectNames(pods []*corev1.Pod) []string

PodsToObjectNames converts a slice of Pods to a slice of string representations in "namespace/name" format.

func ResolveEffectiveTopologyNameForConstraint

func ResolveEffectiveTopologyNameForConstraint(explicitTopologyName, inheritedTopologyName string) (string, error)

ResolveEffectiveTopologyNameForConstraint resolves the topologyName for a single constrained level.

func ResolveEffectiveTopologyNameForPodCliqueSet

func ResolveEffectiveTopologyNameForPodCliqueSet(pcs *grovecorev1alpha1.PodCliqueSet) (string, error)

ResolveEffectiveTopologyNameForPodCliqueSet resolves the single effective topologyName for the PCS after inheritance is applied. Callers that need to distinguish "no topology constraints at all" from invalid topology constraints must first call HasAnyTopologyConstraint.

func WithPCLQPodsCache

func WithPCLQPodsCache(ctx context.Context) context.Context

WithPCLQPodsCache returns a context that memoizes GetPCLQPods results for the lifetime of one reconcile. Call this once at the top of Reconcile and propagate the returned context.

func WithPodCliqueSetCache

func WithPodCliqueSetCache(ctx context.Context) context.Context

WithPodCliqueSetCache returns a context that memoizes GetPodCliqueSet results for the lifetime of one reconcile. Call this once at the top of Reconcile and propagate the ctx.

Types

type MVUTemplate

type MVUTemplate struct {
	// StandalonePCLQs maps standalone PodClique name to the minAvailable pod count.
	StandalonePCLQs map[string]int32
	// PCSGs maps PodCliqueScalingGroup name to the minAvailable replica count.
	PCSGs map[string]int32
}

MVUTemplate describes the composition of one Minimum Viable Unit (MVU) PodGang. It specifies the minimum number of pods per standalone PodClique and the minimum number of replicas per PodCliqueScalingGroup that must be gang-scheduled together.

func ComputeMVUTemplateFromPCSTemplateSpec

func ComputeMVUTemplateFromPCSTemplateSpec(pcs *grovecorev1alpha1.PodCliqueSet) MVUTemplate

ComputeMVUTemplateFromPCSTemplateSpec computes the MVU template for a PCS from its spec.

type PodGangEntryBuilder

type PodGangEntryBuilder func(standalonePCLQReplicas map[string]int32, pcsgReplicaIndices map[string][]int32, dependsOn []string) grovecorev1alpha1.PodGangEntry

PodGangEntryBuilder is a function that creates a PodGangEntry given standalone PCLQ pod counts and PCSG replica indices for the PodGang, and the names of PodGangs this entry depends on.

func NewPodGangEntryBuilder

func NewPodGangEntryBuilder(pcsName string, pcsReplicaIndex int32, pcsGenerationHash string, podGangIndex *int32) PodGangEntryBuilder

NewPodGangEntryBuilder returns a closure that creates PodGangEntry values with sequentially-numbered names. The counter is incremented on each call.

type Set

type Set[T comparable] map[T]struct{}

Set represents unique values with O(1) membership checks. Use it where callers only need to test whether an element is present; use a plain map[K]V (built via lo.SliceToMap) where callers also need to retrieve the value associated with the key.

func NewSet

func NewSet[T comparable](values []T) Set[T]

NewSet converts a slice into a set for O(1) membership checks.

func NewSetBy

func NewSetBy[T any, K comparable](values []T, keyFunc func(T) K) Set[K]

NewSetBy converts a slice into a set using keyFunc to derive the key.

func PodCliqueNameSet

func PodCliqueNameSet(pclqs []grovecorev1alpha1.PodClique) Set[string]

PodCliqueNameSet builds a set of PodClique names for O(1) membership checks.

func (Set[T]) Has

func (s Set[T]) Has(value T) bool

Has returns true if the set contains value. The Set type uses a sentinel struct{} value, so callers cannot use the comma-ok idiom directly; this method gives them an equivalent.

Jump to

Keyboard shortcuts

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