influxdb

package module
v0.9.0-rc2 Latest Latest
Warning

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

Go to latest
Published: Feb 11, 2015 License: MIT Imports: 26 Imported by: 0

README

InfluxDB Build Status

NOTE: The master branch of InfluxDB is undergoing a significant refactor for v0.9.0. If you need to build a working copy of InfluxDB, please use the 0.8.8 tag.

InfluxDB is an open source distributed time series database with no external dependencies. It's useful for recording metrics, events, and performing analytics.

It has a built-in HTTP API so you don't have to write any server side code to get up and running.

InfluxDB is designed to be scalable, simple to install and manage, and fast to get data in and out.

It aims to answer queries in real-time. That means every data point is indexed as it comes in and is immediately available in queries that should return in < 100ms.

Quickstart

Building

You don't need to build the project to use it. Pre-built binaries and instructions to install InfluxDB are here. That's the recommended way to get it running. However, if you want to contribute to the core of InfluxDB, you'll need to build. For those adventurous enough, you can follow along on our docs

Documentation

Index

Constants

View Source
const (
	// DefaultRootPassword is the password initially set for the root user.
	// It is also used when reseting the root user's password.
	DefaultRootPassword = "root"

	// DefaultRetentionPolicyName is the name of a databases's default shard space.
	DefaultRetentionPolicyName = "default"

	// DefaultSplitN represents the number of partitions a shard is split into.
	DefaultSplitN = 1

	// DefaultReplicaN represents the number of replicas data is written to.
	DefaultReplicaN = 1

	// DefaultShardDuration is the time period held by a shard.
	DefaultShardDuration = 7 * (24 * time.Hour)

	// DefaultShardRetention is the length of time before a shard is dropped.
	DefaultShardRetention = 7 * (24 * time.Hour)
)

Variables

View Source
var (
	// ErrServerOpen is returned when opening an already open server.
	ErrServerOpen = errors.New("server already open")

	// ErrServerClosed is returned when closing an already closed server.
	ErrServerClosed = errors.New("server already closed")

	// ErrPathRequired is returned when opening a server without a path.
	ErrPathRequired = errors.New("path required")

	// ErrUnableToJoin is returned when a server cannot join a cluster.
	ErrUnableToJoin = errors.New("unable to join")

	// ErrDataNodeURLRequired is returned when creating a data node without a URL.
	ErrDataNodeURLRequired = errors.New("data node url required")

	// ErrDataNodeExists is returned when creating a duplicate data node.
	ErrDataNodeExists = errors.New("data node exists")

	// ErrDataNodeNotFound is returned when dropping a non-existent data node.
	ErrDataNodeNotFound = errors.New("data node not found")

	// ErrDataNodeRequired is returned when using a blank data node id.
	ErrDataNodeRequired = errors.New("data node required")

	// ErrDatabaseNameRequired is returned when creating a database without a name.
	ErrDatabaseNameRequired = errors.New("database name required")

	// ErrDatabaseExists is returned when creating a duplicate database.
	ErrDatabaseExists = errors.New("database exists")

	// ErrDatabaseNotFound is returned when dropping a non-existent database.
	ErrDatabaseNotFound = errors.New("database not found")

	// ErrDatabaseRequired is returned when using a blank database name.
	ErrDatabaseRequired = errors.New("database required")

	// ErrClusterAdminExists is returned when creating a duplicate admin.
	ErrClusterAdminExists = errors.New("cluster admin exists")

	// ErrClusterAdminNotFound is returned when deleting a non-existent admin.
	ErrClusterAdminNotFound = errors.New("cluster admin not found")

	// ErrUserExists is returned when creating a duplicate user.
	ErrUserExists = errors.New("user exists")

	// ErrUserNotFound is returned when deleting a non-existent user.
	ErrUserNotFound = errors.New("user not found")

	// ErrUsernameRequired is returned when using a blank username.
	ErrUsernameRequired = errors.New("username required")

	// ErrInvalidUsername is returned when using a username with invalid characters.
	ErrInvalidUsername = errors.New("invalid username")

	// ErrRetentionPolicyExists is returned when creating a duplicate shard space.
	ErrRetentionPolicyExists = errors.New("retention policy exists")

	// ErrRetentionPolicyNotFound is returned when deleting a non-existent shard space.
	ErrRetentionPolicyNotFound = errors.New("retention policy not found")

	// ErrRetentionPolicyNameRequired is returned using a blank shard space name.
	ErrRetentionPolicyNameRequired = errors.New("retention policy name required")

	// ErrDefaultRetentionPolicyNotFound is returned when using the default
	// policy on a database but the default has not been set.
	ErrDefaultRetentionPolicyNotFound = errors.New("default retention policy not found")

	// ErrShardNotFound is returned writing to a non-existent shard.
	ErrShardNotFound = errors.New("shard not found")

	// ErrReadAccessDenied is returned when a user attempts to read
	// data that he or she does not have permission to read.
	ErrReadAccessDenied = errors.New("read access denied")

	// ErrReadWritePermissionsRequired is returned when required read/write permissions aren't provided.
	ErrReadWritePermissionsRequired = errors.New("read/write permissions required")

	// ErrInvalidQuery is returned when executing an unknown query type.
	ErrInvalidQuery = errors.New("invalid query")

	// ErrMeasurementNameRequired is returned when a point does not contain a name.
	ErrMeasurementNameRequired = errors.New("measurement name required")

	// ErrMeasurementNotFound is returned when a measurement does not exist.
	ErrMeasurementNotFound = errors.New("measurement not found")

	// ErrValuesRequired is returned when a point does not any values
	ErrValuesRequired = errors.New("values required")

	// ErrFieldOverflow is returned when too many fields are created on a measurement.
	ErrFieldOverflow = errors.New("field overflow")

	// ErrSeriesNotFound is returned when looking up a non-existent series by database, name and tags
	ErrSeriesNotFound = errors.New("series not found")

	// ErrSeriesExists is returned when attempting to set the id of a series by database, name and tags that already exists
	ErrSeriesExists = errors.New("series already exists")

	// ErrNotExecuted is returned when a statement is not executed in a query.
	// This can occur when a previous statement in the same query has errored.
	ErrNotExecuted = errors.New("not executed")

	// ErrInvalidGrantRevoke is returned when a statement requests an invalid
	// privilege for a user on the cluster or a database.
	ErrInvalidGrantRevoke = errors.New("invalid privilege requested")
)
View Source
var BcryptCost = 10

BcryptCost is the cost associated with generating password with Bcrypt. This setting is lowered during testing to improve test suite performance.

Functions

func HashPassword

func HashPassword(password string) ([]byte, error)

HashPassword generates a cryptographically secure hash for password. Returns an error if the password is invalid or a hash cannot be generated.

Types

type BatchPoints

type BatchPoints struct {
	Points          []client.Point    `json:"points"`
	Database        string            `json:"database"`
	RetentionPolicy string            `json:"retentionPolicy"`
	Tags            map[string]string `json:"tags"`
	Timestamp       time.Time         `json:"timestamp"`
	Precision       string            `json:"precision"`
}

BatchPoints is used to send batched data in a single write.

func (*BatchPoints) UnmarshalJSON

func (bp *BatchPoints) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes the data into the BatchPoints struct

type ContinuousQuery

type ContinuousQuery struct {
	ID    uint32
	Query string
}

ContinuousQuery represents a query that exists on the server and processes each incoming event.

type DataNode

type DataNode struct {
	ID  uint64
	URL *url.URL
}

DataNode represents a data node in the cluster.

type ErrAuthorize

type ErrAuthorize struct {
	// contains filtered or unexported fields
}

ErrAuthorize represents an authorization error.

func (ErrAuthorize) Error

func (e ErrAuthorize) Error() string

Error returns the text of the error.

type Field

type Field struct {
	ID   uint8             `json:"id,omitempty"`
	Name string            `json:"name,omitempty"`
	Type influxql.DataType `json:"type,omitempty"`
}

Field represents a series field.

type Fields

type Fields []*Field

Fields represents a list of fields.

type Matcher

type Matcher struct {
	IsRegex bool
	Name    string
}

Matcher can match either a Regex or plain string.

func (*Matcher) Matches

func (m *Matcher) Matches(name string) bool

Matches returns true of the name passed in matches this Matcher.

type Measurement

type Measurement struct {
	Name   string   `json:"name,omitempty"`
	Fields []*Field `json:"fields,omitempty"`
	// contains filtered or unexported fields
}

Measurement represents a collection of time series in a database. It also contains in memory structures for indexing tags. These structures are accessed through private methods on the Measurement object. Generally these methods are only accessed from Index, which is responsible for ensuring go routine safe access.

func NewMeasurement

func NewMeasurement(name string) *Measurement

NewMeasurement allocates and initializes a new Measurement.

func (*Measurement) Field

func (m *Measurement) Field(id uint8) *Field

Field returns a field by id.

func (*Measurement) FieldByName

func (m *Measurement) FieldByName(name string) *Field

FieldByName returns a field by name.

type Measurements

type Measurements []*Measurement

Measurements represents a list of *Measurement.

func (Measurements) Len

func (a Measurements) Len() int

func (Measurements) Less

func (a Measurements) Less(i, j int) bool

func (Measurements) Swap

func (a Measurements) Swap(i, j int)

type MessagingClient

type MessagingClient interface {
	// Publishes a message to the broker.
	Publish(m *messaging.Message) (index uint64, err error)

	// Creates a new replica with a given ID on the broker.
	CreateReplica(replicaID uint64) error

	// Deletes an existing replica with a given ID from the broker.
	DeleteReplica(replicaID uint64) error

	// Creates a subscription for a replica to a topic.
	Subscribe(replicaID, topicID uint64) error

	// Removes a subscription from the replica for a topic.
	Unsubscribe(replicaID, topicID uint64) error

	// The streaming channel for all subscribed messages.
	C() <-chan *messaging.Message
}

MessagingClient represents the client used to receive messages from brokers.

type Point

type Point struct {
	Name      string
	Tags      map[string]string
	Timestamp time.Time
	Values    map[string]interface{}
}

Point defines the values that will be written to the database

func NormalizeBatchPoints

func NormalizeBatchPoints(bp BatchPoints) ([]Point, error)

NormalizeBatchPoints returns a slice of Points, created by populating individual points within the batch, which do not have timestamps or tags, with the top-level values.

type Result

type Result struct {
	Rows []*influxql.Row
	Err  error
}

Result represents a resultset returned from a single statement.

func (*Result) MarshalJSON

func (r *Result) MarshalJSON() ([]byte, error)

MarshalJSON encodes the result into JSON.

func (*Result) UnmarshalJSON

func (r *Result) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes the data into the Result struct

type Results

type Results struct {
	Results []*Result
	Err     error
}

Results represents a list of statement results.

func (*Results) Error

func (r *Results) Error() error

Error returns the first error from any statement. Returns nil if no errors occurred on any statements.

func (Results) MarshalJSON

func (r Results) MarshalJSON() ([]byte, error)

MarshalJSON encodes a Results stuct into JSON.

func (*Results) UnmarshalJSON

func (r *Results) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes the data into the Results struct

type RetentionPolicy

type RetentionPolicy struct {
	// Unique name within database. Required.
	Name string `json:"name"`

	// Length of time to keep data around
	Duration time.Duration `json:"duration"`

	// The number of copies to make of each shard.
	ReplicaN uint32 `json:"replicaN"`
	// contains filtered or unexported fields
}

RetentionPolicy represents a policy for creating new shards in a database and how long they're kept around for.

func NewRetentionPolicy

func NewRetentionPolicy(name string) *RetentionPolicy

NewRetentionPolicy returns a new instance of RetentionPolicy with defaults set.

func (*RetentionPolicy) MarshalJSON

func (rp *RetentionPolicy) MarshalJSON() ([]byte, error)

MarshalJSON encodes a retention policy to a JSON-encoded byte slice.

func (*RetentionPolicy) UnmarshalJSON

func (rp *RetentionPolicy) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a JSON-encoded byte slice to a retention policy.

type RetentionPolicyUpdate

type RetentionPolicyUpdate struct {
	Name     *string        `json:"name,omitempty"`
	Duration *time.Duration `json:"duration,omitempty"`
	ReplicaN *uint32        `json:"replicaN,omitempty"`
}

RetentionPolicyUpdate represents retention policy fields that need to be updated.

type Series

type Series struct {
	ID   uint32
	Tags map[string]string
	// contains filtered or unexported fields
}

Series belong to a Measurement and represent unique time series in a database

type SeriesIDs

type SeriesIDs []uint32

SeriesIDs is a convenience type for sorting, checking equality, and doing union and intersection of collections of series ids.

func (SeriesIDs) Equals

func (a SeriesIDs) Equals(seriesIDs SeriesIDs) bool

Equals assumes that both are sorted. This is by design, no touchy!

func (SeriesIDs) Intersect

func (a SeriesIDs) Intersect(seriesIDs SeriesIDs) SeriesIDs

Intersect returns a new collection of series ids in sorted order that is the intersection of the two. The two collections must already be sorted.

func (SeriesIDs) Len

func (a SeriesIDs) Len() int

func (SeriesIDs) Less

func (a SeriesIDs) Less(i, j int) bool

func (SeriesIDs) Reject

func (a SeriesIDs) Reject(other SeriesIDs) SeriesIDs

Reject returns a new collection of series ids in sorted order with the passed in set removed from the original. This is useful for the NOT operator. The two collections must already be sorted.

func (SeriesIDs) Swap

func (a SeriesIDs) Swap(i, j int)

func (SeriesIDs) Union

func (a SeriesIDs) Union(other SeriesIDs) SeriesIDs

Union returns a new collection of series ids in sorted order that is the union of the two. The two collections must already be sorted.

type Server

type Server struct {
	Logger *log.Logger
	// contains filtered or unexported fields
}

Server represents a collection of metadata and raw metric data.

func NewServer

func NewServer() *Server

NewServer returns a new instance of Server.

func (*Server) AdminUserExists

func (s *Server) AdminUserExists() bool

AdminUserExists returns whether at least 1 admin-level user exists.

func (*Server) Authenticate

func (s *Server) Authenticate(username, password string) (*User, error)

Authenticate returns an authenticated user by username. If any error occurs, or the authentication credentials are invalid, an error is returned.

func (*Server) Authorize

func (s *Server) Authorize(u *User, q *influxql.Query, database string) error

Authorize user u to execute query q on database. database can be "" for queries that do not require a database. If u is nil, this means authorization is disabled.

func (*Server) Begin

func (s *Server) Begin() (influxql.Tx, error)

Begin returns an unopened transaction associated with the server.

func (*Server) Client

func (s *Server) Client() MessagingClient

Client retrieves the current messaging client.

func (*Server) Close

func (s *Server) Close() error

Close shuts down the server.

func (*Server) CopyMetastore

func (s *Server) CopyMetastore(w io.Writer) error

CopyMetastore writes the underlying metastore data file to a writer.

func (*Server) CreateDataNode

func (s *Server) CreateDataNode(u *url.URL) error

CreateDataNode creates a new data node with a given URL.

func (*Server) CreateDatabase

func (s *Server) CreateDatabase(name string) error

CreateDatabase creates a new database.

func (*Server) CreateRetentionPolicy

func (s *Server) CreateRetentionPolicy(database string, rp *RetentionPolicy) error

CreateRetentionPolicy creates a retention policy for a database.

func (*Server) CreateShardGroupIfNotExists

func (s *Server) CreateShardGroupIfNotExists(database, policy string, timestamp time.Time) error

CreateShardGroupIfNotExists creates the shard group for a retention policy for the interval a timestamp falls into.

func (*Server) CreateUser

func (s *Server) CreateUser(username, password string, admin bool) error

CreateUser creates a user on the server.

func (*Server) DataNode

func (s *Server) DataNode(id uint64) *DataNode

DataNode returns a data node by id.

func (*Server) DataNodeByURL

func (s *Server) DataNodeByURL(u *url.URL) *DataNode

DataNodeByURL returns a data node by url.

func (*Server) DataNodes

func (s *Server) DataNodes() (a []*DataNode)

DataNodes returns a list of data nodes.

func (*Server) DatabaseExists

func (s *Server) DatabaseExists(name string) bool

DatabaseExists returns true if a database exists.

func (*Server) Databases

func (s *Server) Databases() (a []string)

Databases returns a sorted list of all database names.

func (*Server) DefaultRetentionPolicy

func (s *Server) DefaultRetentionPolicy(database string) (*RetentionPolicy, error)

DefaultRetentionPolicy returns the default retention policy for a database. Returns an error if the database doesn't exist.

func (*Server) DeleteDataNode

func (s *Server) DeleteDataNode(id uint64) error

DeleteDataNode deletes an existing data node.

func (*Server) DeleteDatabase

func (s *Server) DeleteDatabase(name string) error

DeleteDatabase deletes an existing database.

func (*Server) DeleteRetentionPolicy

func (s *Server) DeleteRetentionPolicy(database, name string) error

DeleteRetentionPolicy removes a retention policy from a database.

func (*Server) DeleteUser

func (s *Server) DeleteUser(username string) error

DeleteUser removes a user from the server.

func (*Server) ExecuteQuery

func (s *Server) ExecuteQuery(q *influxql.Query, database string, user *User) Results

ExecuteQuery executes an InfluxQL query against the server. Returns a resultset for each statement in the query. Stops on first execution error that occurs.

func (*Server) ID

func (s *Server) ID() uint64

ID returns the data node id for the server. Returns zero if the server is closed or the server has not joined a cluster.

func (*Server) Index

func (s *Server) Index() uint64

Index returns the index for the server.

func (*Server) Initialize

func (s *Server) Initialize(u *url.URL) error

Initialize creates a new data node and initializes the server's id to 1.

func (*Server) Join

func (s *Server) Join(u *url.URL, joinURL *url.URL) error

Join creates a new data node in an existing cluster, copies the metastore, and initializes the ID.

func (*Server) MeasurementNames

func (s *Server) MeasurementNames(database string) []string

MeasurementNames returns a list of all measurements for the specified database.

func (*Server) NormalizeMeasurement

func (s *Server) NormalizeMeasurement(name string, defaultDatabase string) (string, error)

NormalizeMeasurement inserts the default database or policy into all measurement names.

func (*Server) NormalizeStatement

func (s *Server) NormalizeStatement(stmt influxql.Statement, defaultDatabase string) (err error)

NormalizeStatement adds a default database and policy to the measurements in statement.

func (*Server) Open

func (s *Server) Open(path string) error

Open initializes the server from a given path.

func (*Server) Path

func (s *Server) Path() string

Path returns the path used when opening the server. Returns an empty string when the server is closed.

func (*Server) ReadSeries

func (s *Server) ReadSeries(database, retentionPolicy, name string, tags map[string]string, timestamp time.Time) (map[string]interface{}, error)

ReadSeries reads a single point from a series in the database.

func (*Server) RetentionPolicies

func (s *Server) RetentionPolicies(database string) ([]*RetentionPolicy, error)

RetentionPolicies returns a list of retention polocies for a database. Returns an error if the database doesn't exist.

func (*Server) RetentionPolicy

func (s *Server) RetentionPolicy(database, name string) (*RetentionPolicy, error)

RetentionPolicy returns a retention policy by name. Returns an error if the database doesn't exist.

func (*Server) SetAuthenticationEnabled

func (s *Server) SetAuthenticationEnabled(enabled bool)

SetAuthenticationEnabled turns on or off server authentication

func (*Server) SetClient

func (s *Server) SetClient(client MessagingClient) error

SetClient sets the messaging client on the server.

func (*Server) SetDefaultRetentionPolicy

func (s *Server) SetDefaultRetentionPolicy(database, name string) error

SetDefaultRetentionPolicy sets the default policy to write data into and query from on a database.

func (*Server) SetLogOutput

func (s *Server) SetLogOutput(w io.Writer)

SetLogOutput sets writer for all Server log output.

func (*Server) SetPrivilege

func (s *Server) SetPrivilege(p influxql.Privilege, username string, dbname string) error

SetPrivilege grants / revokes a privilege to a user.

func (*Server) Shard

func (s *Server) Shard(id uint64) *Shard

Shard returns a shard by ID.

func (*Server) ShardGroups

func (s *Server) ShardGroups(database string) ([]*ShardGroup, error)

ShardGroups returns a list of all shard groups for a database. Returns an error if the database doesn't exist.

func (*Server) Sync

func (s *Server) Sync(index uint64) error

Sync blocks until a given index (or a higher index) has been applied. Returns any error associated with the command.

func (*Server) UpdateRetentionPolicy

func (s *Server) UpdateRetentionPolicy(database, name string, rpu *RetentionPolicyUpdate) error

UpdateRetentionPolicy updates an existing retention policy on a database.

func (*Server) UpdateUser

func (s *Server) UpdateUser(username, password string) error

UpdateUser updates an existing user on the server.

func (*Server) User

func (s *Server) User(name string) *User

User returns a user by username Returns nil if the user does not exist.

func (*Server) UserCount

func (s *Server) UserCount() int

UserCount returns the number of users.

func (*Server) Users

func (s *Server) Users() (a []*User)

Users returns a list of all users, sorted by name.

func (*Server) WriteSeries

func (s *Server) WriteSeries(database, retentionPolicy string, points []Point) (uint64, error)

WriteSeries writes series data to the database. Returns the messaging index the data was written to.

type Shard

type Shard struct {
	ID          uint64   `json:"id,omitempty"`
	DataNodeIDs []uint64 `json:"nodeIDs,omitempty"` // owners
	// contains filtered or unexported fields
}

Shard represents the logical storage for a given time range. The instance on a local server may contain the raw data in "store" if the shard is assigned to the server's data node id.

func (*Shard) HasDataNodeID

func (s *Shard) HasDataNodeID(id uint64) bool

HasDataNodeID return true if the data node owns the shard.

type ShardGroup

type ShardGroup struct {
	ID        uint64    `json:"id,omitempty"`
	StartTime time.Time `json:"startTime,omitempty"`
	EndTime   time.Time `json:"endTime,omitempty"`
	Shards    []*Shard  `json:"shards,omitempty"`
}

ShardGroup represents a group of shards created for a single time range.

func (*ShardGroup) Duration

func (g *ShardGroup) Duration() time.Duration

Duration returns the duration between the shard group's start and end time.

func (*ShardGroup) ShardBySeriesID

func (g *ShardGroup) ShardBySeriesID(seriesID uint32) *Shard

ShardBySeriesID returns the shard that a series is assigned to in the group.

type Shards

type Shards []*Shard

Shards represents a list of shards.

type TagFilter

type TagFilter struct {
	Not   bool
	Key   string
	Value string
	Regex *regexp.Regexp
}

TagFilter represents a tag filter when looking up other tags or measurements.

type TimePrecision

type TimePrecision int

TimePrecision represents a level of time precision.

const (
	// MicrosecondPrecision is 1/1,000,000 th of a second.
	MicrosecondPrecision TimePrecision = iota
	// MillisecondPrecision is 1/1,000 th of a second.
	MillisecondPrecision
	// SecondPrecision is 1 second precision.
	SecondPrecision
)

type UDPServer

type UDPServer struct {

	// The UDP address to listen on.
	Addr *net.UDPAddr

	// The name of the database to insert data into.
	Database string

	// The user authorized to insert the data.
	User *User
	// contains filtered or unexported fields
}

UDPServer represents a UDP transport for InfluxDB.

func NewUDPServer

func NewUDPServer(server *Server) *UDPServer

NewUDPServer returns an instance of UDPServer attached to a Server.

func (*UDPServer) ListenAndServe

func (s *UDPServer) ListenAndServe() error

ListenAndServe opens a UDP socket to listen for messages.

type User

type User struct {
	Name       string                        `json:"name"`
	Hash       string                        `json:"hash"`
	Privileges map[string]influxql.Privilege `json:"privileges"` // db name to privilege
	Admin      bool                          `json:"admin,omitempty"`
}

User represents a user account on the system. It can be given read/write permissions to individual databases.

func (*User) Authenticate

func (u *User) Authenticate(password string) error

Authenticate returns nil if the password matches the user's password. Returns an error if the password was incorrect.

func (*User) Authorize

func (u *User) Authorize(privilege influxql.Privilege, database string) bool

Authorize returns true if the user is authorized and false if not.

Directories

Path Synopsis
cmd
Package influxql implements a parser for the InfluxDB query language.
Package influxql implements a parser for the InfluxDB query language.
Package messaging implements a distributed, raft-backed messaging system.
Package messaging implements a distributed, raft-backed messaging system.
Package raft implements a streaming version of the Raft protocol.
Package raft implements a streaming version of the Raft protocol.

Jump to

Keyboard shortcuts

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