gh-ost/go/mysql/instance_key.go
2016-05-16 11:09:17 +02:00

116 lines
3.3 KiB
Go

/*
Copyright 2015 Shlomi Noach, courtesy Booking.com
See https://github.com/github/gh-ost/blob/master/LICENSE
*/
package mysql
import (
"fmt"
"strconv"
"strings"
)
const (
DefaultInstancePort = 3306
)
// InstanceKey is an instance indicator, identifued by hostname and port
type InstanceKey struct {
Hostname string
Port int
}
const detachHint = "//"
// ParseInstanceKey will parse an InstanceKey from a string representation such as 127.0.0.1:3306
func NewRawInstanceKey(hostPort string) (*InstanceKey, error) {
tokens := strings.SplitN(hostPort, ":", 2)
if len(tokens) != 2 {
return nil, fmt.Errorf("Cannot parse InstanceKey from %s. Expected format is host:port", hostPort)
}
instanceKey := &InstanceKey{Hostname: tokens[0]}
var err error
if instanceKey.Port, err = strconv.Atoi(tokens[1]); err != nil {
return instanceKey, fmt.Errorf("Invalid port: %s", tokens[1])
}
return instanceKey, nil
}
// ParseRawInstanceKeyLoose will parse an InstanceKey from a string representation such as 127.0.0.1:3306.
// The port part is optional; there will be no name resolve
func ParseRawInstanceKeyLoose(hostPort string) (*InstanceKey, error) {
if !strings.Contains(hostPort, ":") {
return &InstanceKey{Hostname: hostPort, Port: DefaultInstancePort}, nil
}
return NewRawInstanceKey(hostPort)
}
// Equals tests equality between this key and another key
func (this *InstanceKey) Equals(other *InstanceKey) bool {
if other == nil {
return false
}
return this.Hostname == other.Hostname && this.Port == other.Port
}
// SmallerThan returns true if this key is dictionary-smaller than another.
// This is used for consistent sorting/ordering; there's nothing magical about it.
func (this *InstanceKey) SmallerThan(other *InstanceKey) bool {
if this.Hostname < other.Hostname {
return true
}
if this.Hostname == other.Hostname && this.Port < other.Port {
return true
}
return false
}
// IsDetached returns 'true' when this hostname is logically "detached"
func (this *InstanceKey) IsDetached() bool {
return strings.HasPrefix(this.Hostname, detachHint)
}
// IsValid uses simple heuristics to see whether this key represents an actual instance
func (this *InstanceKey) IsValid() bool {
if this.Hostname == "_" {
return false
}
if this.IsDetached() {
return false
}
return len(this.Hostname) > 0 && this.Port > 0
}
// DetachedKey returns an instance key whose hostname is detahced: invalid, but recoverable
func (this *InstanceKey) DetachedKey() *InstanceKey {
if this.IsDetached() {
return this
}
return &InstanceKey{Hostname: fmt.Sprintf("%s%s", detachHint, this.Hostname), Port: this.Port}
}
// ReattachedKey returns an instance key whose hostname is detahced: invalid, but recoverable
func (this *InstanceKey) ReattachedKey() *InstanceKey {
if !this.IsDetached() {
return this
}
return &InstanceKey{Hostname: this.Hostname[len(detachHint):], Port: this.Port}
}
// StringCode returns an official string representation of this key
func (this *InstanceKey) StringCode() string {
return fmt.Sprintf("%s:%d", this.Hostname, this.Port)
}
// DisplayString returns a user-friendly string representation of this key
func (this *InstanceKey) DisplayString() string {
return this.StringCode()
}
// String returns a user-friendly string representation of this key
func (this InstanceKey) String() string {
return this.StringCode()
}