envoy_config_filter_network_redis_proxy_v3alpha

package
v1.12.1 Latest Latest
Warning

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

Go to latest
Published: Mar 30, 2020 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var RedisProxy_ConnPoolSettings_ReadPolicy_name = map[int32]string{
	0: "MASTER",
	1: "PREFER_MASTER",
	2: "REPLICA",
	3: "PREFER_REPLICA",
	4: "ANY",
}
View Source
var RedisProxy_ConnPoolSettings_ReadPolicy_value = map[string]int32{
	"MASTER":         0,
	"PREFER_MASTER":  1,
	"REPLICA":        2,
	"PREFER_REPLICA": 3,
	"ANY":            4,
}

Functions

This section is empty.

Types

type RedisProtocolOptions

type RedisProtocolOptions struct {
	// Upstream server password as defined by the `requirepass` directive
	// <https://redis.io/topics/config>`_ in the server's configuration file.
	AuthPassword         *core.DataSource `protobuf:"bytes,1,opt,name=auth_password,json=authPassword,proto3" json:"auth_password,omitempty"`
	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
	XXX_unrecognized     []byte           `json:"-"`
	XXX_sizecache        int32            `json:"-"`
}

RedisProtocolOptions specifies Redis upstream protocol options. This object is used in :ref:`extension_protocol_options<envoy_api_field_api.v3alpha.Cluster.extension_protocol_options>`, keyed by the name `envoy.redis_proxy`.

func (*RedisProtocolOptions) Descriptor

func (*RedisProtocolOptions) Descriptor() ([]byte, []int)

func (*RedisProtocolOptions) GetAuthPassword

func (m *RedisProtocolOptions) GetAuthPassword() *core.DataSource

func (*RedisProtocolOptions) ProtoMessage

func (*RedisProtocolOptions) ProtoMessage()

func (*RedisProtocolOptions) Reset

func (m *RedisProtocolOptions) Reset()

func (*RedisProtocolOptions) String

func (m *RedisProtocolOptions) String() string

func (*RedisProtocolOptions) XXX_DiscardUnknown

func (m *RedisProtocolOptions) XXX_DiscardUnknown()

func (*RedisProtocolOptions) XXX_Marshal

func (m *RedisProtocolOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RedisProtocolOptions) XXX_Merge

func (m *RedisProtocolOptions) XXX_Merge(src proto.Message)

func (*RedisProtocolOptions) XXX_Size

func (m *RedisProtocolOptions) XXX_Size() int

func (*RedisProtocolOptions) XXX_Unmarshal

func (m *RedisProtocolOptions) XXX_Unmarshal(b []byte) error

type RedisProxy

type RedisProxy struct {
	// The prefix to use when emitting :ref:`statistics <config_network_filters_redis_proxy_stats>`.
	StatPrefix string `protobuf:"bytes,1,opt,name=stat_prefix,json=statPrefix,proto3" json:"stat_prefix,omitempty"`
	// Network settings for the connection pool to the upstream clusters.
	Settings *RedisProxy_ConnPoolSettings `protobuf:"bytes,3,opt,name=settings,proto3" json:"settings,omitempty"`
	// Indicates that latency stat should be computed in microseconds. By default it is computed in
	// milliseconds.
	LatencyInMicros bool `protobuf:"varint,4,opt,name=latency_in_micros,json=latencyInMicros,proto3" json:"latency_in_micros,omitempty"`
	// List of **unique** prefixes used to separate keys from different workloads to different
	// clusters. Envoy will always favor the longest match first in case of overlap. A catch-all
	// cluster can be used to forward commands when there is no match. Time complexity of the
	// lookups are in O(min(longest key prefix, key length)).
	//
	// Example:
	//
	// .. code-block:: yaml
	//
	//    prefix_routes:
	//      routes:
	//        - prefix: "ab"
	//          cluster: "cluster_a"
	//        - prefix: "abc"
	//          cluster: "cluster_b"
	//
	// When using the above routes, the following prefixes would be sent to:
	//
	// * 'get abc:users' would retrieve the key 'abc:users' from cluster_b.
	// * 'get ab:users' would retrieve the key 'ab:users' from cluster_a.
	// * 'get z:users' would return a NoUpstreamHost error. A :ref:`catch-all
	//   route<envoy_api_field_config.filter.network.redis_proxy.v3alpha.RedisProxy.PrefixRoutes.catch_all_route>`
	//   would have retrieved the key from that cluster instead.
	//
	// See the :ref:`configuration section
	// <arch_overview_redis_configuration>` of the architecture overview for recommendations on
	// configuring the backing clusters.
	PrefixRoutes *RedisProxy_PrefixRoutes `protobuf:"bytes,5,opt,name=prefix_routes,json=prefixRoutes,proto3" json:"prefix_routes,omitempty"`
	// Authenticate Redis client connections locally by forcing downstream clients to issue a `Redis
	// AUTH command <https://redis.io/commands/auth>`_ with this password before enabling any other
	// command. If an AUTH command's password matches this password, an "OK" response will be returned
	// to the client. If the AUTH command password does not match this password, then an "ERR invalid
	// password" error will be returned. If any other command is received before AUTH when this
	// password is set, then a "NOAUTH Authentication required." error response will be sent to the
	// client. If an AUTH command is received when the password is not set, then an "ERR Client sent
	// AUTH, but no password is set" error will be returned.
	DownstreamAuthPassword *core.DataSource `` /* 129-byte string literal not displayed */
	XXX_NoUnkeyedLiteral   struct{}         `json:"-"`
	XXX_unrecognized       []byte           `json:"-"`
	XXX_sizecache          int32            `json:"-"`
}

[#next-free-field: 7]

func (*RedisProxy) Descriptor

func (*RedisProxy) Descriptor() ([]byte, []int)

func (*RedisProxy) GetDownstreamAuthPassword

func (m *RedisProxy) GetDownstreamAuthPassword() *core.DataSource

func (*RedisProxy) GetLatencyInMicros

func (m *RedisProxy) GetLatencyInMicros() bool

func (*RedisProxy) GetPrefixRoutes

func (m *RedisProxy) GetPrefixRoutes() *RedisProxy_PrefixRoutes

func (*RedisProxy) GetSettings

func (m *RedisProxy) GetSettings() *RedisProxy_ConnPoolSettings

func (*RedisProxy) GetStatPrefix

func (m *RedisProxy) GetStatPrefix() string

func (*RedisProxy) ProtoMessage

func (*RedisProxy) ProtoMessage()

func (*RedisProxy) Reset

func (m *RedisProxy) Reset()

func (*RedisProxy) String

func (m *RedisProxy) String() string

func (*RedisProxy) XXX_DiscardUnknown

func (m *RedisProxy) XXX_DiscardUnknown()

func (*RedisProxy) XXX_Marshal

func (m *RedisProxy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RedisProxy) XXX_Merge

func (m *RedisProxy) XXX_Merge(src proto.Message)

func (*RedisProxy) XXX_Size

func (m *RedisProxy) XXX_Size() int

func (*RedisProxy) XXX_Unmarshal

func (m *RedisProxy) XXX_Unmarshal(b []byte) error

type RedisProxy_ConnPoolSettings

type RedisProxy_ConnPoolSettings struct {
	// Per-operation timeout in milliseconds. The timer starts when the first
	// command of a pipeline is written to the backend connection. Each response received from Redis
	// resets the timer since it signifies that the next command is being processed by the backend.
	// The only exception to this behavior is when a connection to a backend is not yet established.
	// In that case, the connect timeout on the cluster will govern the timeout until the connection
	// is ready.
	OpTimeout *types.Duration `protobuf:"bytes,1,opt,name=op_timeout,json=opTimeout,proto3" json:"op_timeout,omitempty"`
	// Use hash tagging on every redis key to guarantee that keys with the same hash tag will be
	// forwarded to the same upstream. The hash key used for determining the upstream in a
	// consistent hash ring configuration will be computed from the hash tagged key instead of the
	// whole key. The algorithm used to compute the hash tag is identical to the `redis-cluster
	// implementation <https://redis.io/topics/cluster-spec#keys-hash-tags>`_.
	//
	// Examples:
	//
	// * '{user1000}.following' and '{user1000}.followers' **will** be sent to the same upstream
	// * '{user1000}.following' and '{user1001}.following' **might** be sent to the same upstream
	EnableHashtagging bool `protobuf:"varint,2,opt,name=enable_hashtagging,json=enableHashtagging,proto3" json:"enable_hashtagging,omitempty"`
	// Accept `moved and ask redirection
	// <https://redis.io/topics/cluster-spec#redirection-and-resharding>`_ errors from upstream
	// redis servers, and retry commands to the specified target server. The target server does not
	// need to be known to the cluster manager. If the command cannot be redirected, then the
	// original error is passed downstream unchanged. By default, this support is not enabled.
	EnableRedirection bool `protobuf:"varint,3,opt,name=enable_redirection,json=enableRedirection,proto3" json:"enable_redirection,omitempty"`
	// Maximum size of encoded request buffer before flush is triggered and encoded requests
	// are sent upstream. If this is unset, the buffer flushes whenever it receives data
	// and performs no batching.
	// This feature makes it possible for multiple clients to send requests to Envoy and have
	// them batched- for example if one is running several worker processes, each with its own
	// Redis connection. There is no benefit to using this with a single downstream process.
	// Recommended size (if enabled) is 1024 bytes.
	MaxBufferSizeBeforeFlush uint32 `` /* 140-byte string literal not displayed */
	// The encoded request buffer is flushed N milliseconds after the first request has been
	// encoded, unless the buffer size has already exceeded `max_buffer_size_before_flush`.
	// If `max_buffer_size_before_flush` is not set, this flush timer is not used. Otherwise,
	// the timer should be set according to the number of clients, overall request rate and
	// desired maximum latency for a single command. For example, if there are many requests
	// being batched together at a high rate, the buffer will likely be filled before the timer
	// fires. Alternatively, if the request rate is lower the buffer will not be filled as often
	// before the timer fires.
	// If `max_buffer_size_before_flush` is set, but `buffer_flush_timeout` is not, the latter
	// defaults to 3ms.
	BufferFlushTimeout *types.Duration `protobuf:"bytes,5,opt,name=buffer_flush_timeout,json=bufferFlushTimeout,proto3" json:"buffer_flush_timeout,omitempty"`
	// `max_upstream_unknown_connections` controls how many upstream connections to unknown hosts
	// can be created at any given time by any given worker thread (see `enable_redirection` for
	// more details). If the host is unknown and a connection cannot be created due to enforcing
	// this limit, then redirection will fail and the original redirection error will be passed
	// downstream unchanged. This limit defaults to 100.
	MaxUpstreamUnknownConnections *types.UInt32Value `` /* 152-byte string literal not displayed */
	// Enable per-command statistics per upstream cluster, in addition to the filter level aggregate
	// count.
	EnableCommandStats bool `protobuf:"varint,8,opt,name=enable_command_stats,json=enableCommandStats,proto3" json:"enable_command_stats,omitempty"`
	// Read policy. The default is to read from the master.
	ReadPolicy           RedisProxy_ConnPoolSettings_ReadPolicy `` /* 184-byte string literal not displayed */
	XXX_NoUnkeyedLiteral struct{}                               `json:"-"`
	XXX_unrecognized     []byte                                 `json:"-"`
	XXX_sizecache        int32                                  `json:"-"`
}

Redis connection pool settings. [#next-free-field: 9]

func (*RedisProxy_ConnPoolSettings) Descriptor

func (*RedisProxy_ConnPoolSettings) Descriptor() ([]byte, []int)

func (*RedisProxy_ConnPoolSettings) GetBufferFlushTimeout

func (m *RedisProxy_ConnPoolSettings) GetBufferFlushTimeout() *types.Duration

func (*RedisProxy_ConnPoolSettings) GetEnableCommandStats

func (m *RedisProxy_ConnPoolSettings) GetEnableCommandStats() bool

func (*RedisProxy_ConnPoolSettings) GetEnableHashtagging

func (m *RedisProxy_ConnPoolSettings) GetEnableHashtagging() bool

func (*RedisProxy_ConnPoolSettings) GetEnableRedirection

func (m *RedisProxy_ConnPoolSettings) GetEnableRedirection() bool

func (*RedisProxy_ConnPoolSettings) GetMaxBufferSizeBeforeFlush

func (m *RedisProxy_ConnPoolSettings) GetMaxBufferSizeBeforeFlush() uint32

func (*RedisProxy_ConnPoolSettings) GetMaxUpstreamUnknownConnections

func (m *RedisProxy_ConnPoolSettings) GetMaxUpstreamUnknownConnections() *types.UInt32Value

func (*RedisProxy_ConnPoolSettings) GetOpTimeout

func (m *RedisProxy_ConnPoolSettings) GetOpTimeout() *types.Duration

func (*RedisProxy_ConnPoolSettings) GetReadPolicy

func (*RedisProxy_ConnPoolSettings) ProtoMessage

func (*RedisProxy_ConnPoolSettings) ProtoMessage()

func (*RedisProxy_ConnPoolSettings) Reset

func (m *RedisProxy_ConnPoolSettings) Reset()

func (*RedisProxy_ConnPoolSettings) String

func (m *RedisProxy_ConnPoolSettings) String() string

func (*RedisProxy_ConnPoolSettings) XXX_DiscardUnknown

func (m *RedisProxy_ConnPoolSettings) XXX_DiscardUnknown()

func (*RedisProxy_ConnPoolSettings) XXX_Marshal

func (m *RedisProxy_ConnPoolSettings) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RedisProxy_ConnPoolSettings) XXX_Merge

func (m *RedisProxy_ConnPoolSettings) XXX_Merge(src proto.Message)

func (*RedisProxy_ConnPoolSettings) XXX_Size

func (m *RedisProxy_ConnPoolSettings) XXX_Size() int

func (*RedisProxy_ConnPoolSettings) XXX_Unmarshal

func (m *RedisProxy_ConnPoolSettings) XXX_Unmarshal(b []byte) error

type RedisProxy_ConnPoolSettings_ReadPolicy

type RedisProxy_ConnPoolSettings_ReadPolicy int32

ReadPolicy controls how Envoy routes read commands to Redis nodes. This is currently supported for Redis Cluster. All ReadPolicy settings except MASTER may return stale data because replication is asynchronous and requires some delay. You need to ensure that your application can tolerate stale data.

const (
	// Default mode. Read from the current master node.
	RedisProxy_ConnPoolSettings_MASTER RedisProxy_ConnPoolSettings_ReadPolicy = 0
	// Read from the master, but if it is unavailable, read from replica nodes.
	RedisProxy_ConnPoolSettings_PREFER_MASTER RedisProxy_ConnPoolSettings_ReadPolicy = 1
	// Read from replica nodes. If multiple replica nodes are present within a shard, a random
	// node is selected. Healthy nodes have precedent over unhealthy nodes.
	RedisProxy_ConnPoolSettings_REPLICA RedisProxy_ConnPoolSettings_ReadPolicy = 2
	// Read from the replica nodes (similar to REPLICA), but if all replicas are unavailable (not
	// present or unhealthy), read from the master.
	RedisProxy_ConnPoolSettings_PREFER_REPLICA RedisProxy_ConnPoolSettings_ReadPolicy = 3
	// Read from any node of the cluster. A random node is selected among the master and replicas,
	// healthy nodes have precedent over unhealthy nodes.
	RedisProxy_ConnPoolSettings_ANY RedisProxy_ConnPoolSettings_ReadPolicy = 4
)

func (RedisProxy_ConnPoolSettings_ReadPolicy) EnumDescriptor

func (RedisProxy_ConnPoolSettings_ReadPolicy) EnumDescriptor() ([]byte, []int)

func (RedisProxy_ConnPoolSettings_ReadPolicy) String

type RedisProxy_PrefixRoutes

type RedisProxy_PrefixRoutes struct {
	// List of prefix routes.
	Routes []*RedisProxy_PrefixRoutes_Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"`
	// Indicates that prefix matching should be case insensitive.
	CaseInsensitive bool `protobuf:"varint,2,opt,name=case_insensitive,json=caseInsensitive,proto3" json:"case_insensitive,omitempty"`
	// Optional catch-all route to forward commands that doesn't match any of the routes. The
	// catch-all route becomes required when no routes are specified.
	CatchAllRoute        *RedisProxy_PrefixRoutes_Route `protobuf:"bytes,4,opt,name=catch_all_route,json=catchAllRoute,proto3" json:"catch_all_route,omitempty"`
	XXX_NoUnkeyedLiteral struct{}                       `json:"-"`
	XXX_unrecognized     []byte                         `json:"-"`
	XXX_sizecache        int32                          `json:"-"`
}

func (*RedisProxy_PrefixRoutes) Descriptor

func (*RedisProxy_PrefixRoutes) Descriptor() ([]byte, []int)

func (*RedisProxy_PrefixRoutes) GetCaseInsensitive

func (m *RedisProxy_PrefixRoutes) GetCaseInsensitive() bool

func (*RedisProxy_PrefixRoutes) GetCatchAllRoute

func (*RedisProxy_PrefixRoutes) GetRoutes

func (*RedisProxy_PrefixRoutes) ProtoMessage

func (*RedisProxy_PrefixRoutes) ProtoMessage()

func (*RedisProxy_PrefixRoutes) Reset

func (m *RedisProxy_PrefixRoutes) Reset()

func (*RedisProxy_PrefixRoutes) String

func (m *RedisProxy_PrefixRoutes) String() string

func (*RedisProxy_PrefixRoutes) XXX_DiscardUnknown

func (m *RedisProxy_PrefixRoutes) XXX_DiscardUnknown()

func (*RedisProxy_PrefixRoutes) XXX_Marshal

func (m *RedisProxy_PrefixRoutes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RedisProxy_PrefixRoutes) XXX_Merge

func (m *RedisProxy_PrefixRoutes) XXX_Merge(src proto.Message)

func (*RedisProxy_PrefixRoutes) XXX_Size

func (m *RedisProxy_PrefixRoutes) XXX_Size() int

func (*RedisProxy_PrefixRoutes) XXX_Unmarshal

func (m *RedisProxy_PrefixRoutes) XXX_Unmarshal(b []byte) error

type RedisProxy_PrefixRoutes_Route

type RedisProxy_PrefixRoutes_Route struct {
	// String prefix that must match the beginning of the keys. Envoy will always favor the
	// longest match.
	Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"`
	// Indicates if the prefix needs to be removed from the key when forwarded.
	RemovePrefix bool `protobuf:"varint,2,opt,name=remove_prefix,json=removePrefix,proto3" json:"remove_prefix,omitempty"`
	// Upstream cluster to forward the command to.
	Cluster string `protobuf:"bytes,3,opt,name=cluster,proto3" json:"cluster,omitempty"`
	// Indicates that the route has a request mirroring policy.
	RequestMirrorPolicy  []*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy `protobuf:"bytes,4,rep,name=request_mirror_policy,json=requestMirrorPolicy,proto3" json:"request_mirror_policy,omitempty"`
	XXX_NoUnkeyedLiteral struct{}                                             `json:"-"`
	XXX_unrecognized     []byte                                               `json:"-"`
	XXX_sizecache        int32                                                `json:"-"`
}

func (*RedisProxy_PrefixRoutes_Route) Descriptor

func (*RedisProxy_PrefixRoutes_Route) Descriptor() ([]byte, []int)

func (*RedisProxy_PrefixRoutes_Route) GetCluster

func (m *RedisProxy_PrefixRoutes_Route) GetCluster() string

func (*RedisProxy_PrefixRoutes_Route) GetPrefix

func (m *RedisProxy_PrefixRoutes_Route) GetPrefix() string

func (*RedisProxy_PrefixRoutes_Route) GetRemovePrefix

func (m *RedisProxy_PrefixRoutes_Route) GetRemovePrefix() bool

func (*RedisProxy_PrefixRoutes_Route) GetRequestMirrorPolicy

func (*RedisProxy_PrefixRoutes_Route) ProtoMessage

func (*RedisProxy_PrefixRoutes_Route) ProtoMessage()

func (*RedisProxy_PrefixRoutes_Route) Reset

func (m *RedisProxy_PrefixRoutes_Route) Reset()

func (*RedisProxy_PrefixRoutes_Route) String

func (*RedisProxy_PrefixRoutes_Route) XXX_DiscardUnknown

func (m *RedisProxy_PrefixRoutes_Route) XXX_DiscardUnknown()

func (*RedisProxy_PrefixRoutes_Route) XXX_Marshal

func (m *RedisProxy_PrefixRoutes_Route) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RedisProxy_PrefixRoutes_Route) XXX_Merge

func (m *RedisProxy_PrefixRoutes_Route) XXX_Merge(src proto.Message)

func (*RedisProxy_PrefixRoutes_Route) XXX_Size

func (m *RedisProxy_PrefixRoutes_Route) XXX_Size() int

func (*RedisProxy_PrefixRoutes_Route) XXX_Unmarshal

func (m *RedisProxy_PrefixRoutes_Route) XXX_Unmarshal(b []byte) error

type RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy

type RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy struct {
	// Specifies the cluster that requests will be mirrored to. The cluster must
	// exist in the cluster manager configuration.
	Cluster string `protobuf:"bytes,1,opt,name=cluster,proto3" json:"cluster,omitempty"`
	// If not specified or the runtime key is not present, all requests to the target cluster
	// will be mirrored.
	//
	// If specified, Envoy will lookup the runtime key to get the percentage of requests to the
	// mirror.
	RuntimeFraction *core.RuntimeFractionalPercent `protobuf:"bytes,2,opt,name=runtime_fraction,json=runtimeFraction,proto3" json:"runtime_fraction,omitempty"`
	// Set this to TRUE to only mirror write commands, this is effectively replicating the
	// writes in a "fire and forget" manner.
	ExcludeReadCommands  bool     `protobuf:"varint,3,opt,name=exclude_read_commands,json=excludeReadCommands,proto3" json:"exclude_read_commands,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

The router is capable of shadowing traffic from one cluster to another. The current implementation is "fire and forget," meaning Envoy will not wait for the shadow cluster to respond before returning the response from the primary cluster. All normal statistics are collected for the shadow cluster making this feature useful for testing.

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) Descriptor

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) GetCluster

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) GetExcludeReadCommands

func (m *RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) GetExcludeReadCommands() bool

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) GetRuntimeFraction

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) ProtoMessage

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) Reset

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) String

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) XXX_DiscardUnknown

func (m *RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) XXX_DiscardUnknown()

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) XXX_Marshal

func (m *RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) XXX_Merge

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) XXX_Size

func (*RedisProxy_PrefixRoutes_Route_RequestMirrorPolicy) XXX_Unmarshal

Jump to

Keyboard shortcuts

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