ots/vendor/github.com/xuyu/goredis/server.go
Knut Ahlers 5e3d84df9b
Vendor dependencies
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2017-08-03 20:07:30 +02:00

359 lines
11 KiB
Go

package goredis
import (
"errors"
"io"
"net"
"strconv"
)
// BgRewriteAof Instruct Redis to start an Append Only File rewrite process.
// The rewrite will create a small optimized version of the current Append Only File.
func (r *Redis) BgRewriteAof() error {
_, err := r.ExecuteCommand("BGREWRITEAOF")
return err
}
// BgSave save the DB in background.
// The OK code is immediately returned.
// Redis forks, the parent continues to serve the clients, the child saves the DB on disk then exits.
// A client my be able to check if the operation succeeded using the LASTSAVE command.
func (r *Redis) BgSave() error {
_, err := r.ExecuteCommand("BGSAVE")
return err
}
// ClientKill closes a given client connection identified by ip:port.
// Due to the single-treaded nature of Redis,
// it is not possible to kill a client connection while it is executing a command.
// However, the client will notice the connection has been closed
// only when the next command is sent (and results in network error).
// Status code reply: OK if the connection exists and has been closed
func (r *Redis) ClientKill(ip string, port int) error {
rp, err := r.ExecuteCommand("CLIENT", "KILL", net.JoinHostPort(ip, strconv.Itoa(port)))
if err != nil {
return err
}
return rp.OKValue()
}
// ClientList returns information and statistics
// about the client connections server in a mostly human readable format.
// Bulk reply: a unique string, formatted as follows:
// One client connection per line (separated by LF)
// Each line is composed of a succession of property=value fields separated by a space character.
func (r *Redis) ClientList() (string, error) {
rp, err := r.ExecuteCommand("CLIENT", "LIST")
if err != nil {
return "", err
}
return rp.StringValue()
}
// ClientGetName returns the name of the current connection as set by CLIENT SETNAME.
// Since every new connection starts without an associated name,
// if no name was assigned a null bulk reply is returned.
func (r *Redis) ClientGetName() ([]byte, error) {
rp, err := r.ExecuteCommand("CLIENT", "GETNAME")
if err != nil {
return nil, err
}
return rp.BytesValue()
}
// ClientPause stops the server processing commands from clients for some time.
func (r *Redis) ClientPause(timeout uint64) error {
rp, err := r.ExecuteCommand("CLIENT", "PAUSE", timeout)
if err != nil {
return err
}
return rp.OKValue()
}
// ClientSetName assigns a name to the current connection.
func (r *Redis) ClientSetName(name string) error {
rp, err := r.ExecuteCommand("CLIENT", "SETNAME", name)
if err != nil {
return err
}
return rp.OKValue()
}
// ConfigGet is used to read the configuration parameters of a running Redis server.
// Not all the configuration parameters are supported in Redis 2.4,
// while Redis 2.6 can read the whole configuration of a server using this command.
// CONFIG GET takes a single argument, which is a glob-style pattern.
func (r *Redis) ConfigGet(parameter string) (map[string]string, error) {
rp, err := r.ExecuteCommand("CONFIG", "GET", parameter)
if err != nil {
return nil, err
}
return rp.HashValue()
}
// ConfigRewrite rewrites the redis.conf file the server was started with,
// applying the minimal changes needed to make it reflecting the configuration currently used by the server,
// that may be different compared to the original one because of the use of the CONFIG SET command.
// Available since 2.8.0.
func (r *Redis) ConfigRewrite() error {
rp, err := r.ExecuteCommand("CONFIG", "REWRITE")
if err != nil {
return err
}
return rp.OKValue()
}
// ConfigSet is used in order to reconfigure the server at run time without the need to restart Redis.
// You can change both trivial parameters or switch from one to another persistence option using this command.
func (r *Redis) ConfigSet(parameter, value string) error {
rp, err := r.ExecuteCommand("CONFIG", "SET", parameter, value)
if err != nil {
return err
}
return rp.OKValue()
}
// ConfigResetStat resets the statistics reported by Redis using the INFO command.
// These are the counters that are reset:
// Keyspace hits
// Keyspace misses
// Number of commands processed
// Number of connections received
// Number of expired keys
// Number of rejected connections
// Latest fork(2) time
// The aof_delayed_fsync counter
func (r *Redis) ConfigResetStat() error {
_, err := r.ExecuteCommand("CONFIG", "RESETSTAT")
return err
}
// DBSize return the number of keys in the currently-selected database.
func (r *Redis) DBSize() (int64, error) {
rp, err := r.ExecuteCommand("DBSIZE")
if err != nil {
return 0, err
}
return rp.IntegerValue()
}
// DebugObject is a debugging command that should not be used by clients.
func (r *Redis) DebugObject(key string) (string, error) {
rp, err := r.ExecuteCommand("DEBUG", "OBJECT", key)
if err != nil {
return "", err
}
return rp.StatusValue()
}
// FlushAll delete all the keys of all the existing databases,
// not just the currently selected one.
// This command never fails.
func (r *Redis) FlushAll() error {
_, err := r.ExecuteCommand("FLUSHALL")
return err
}
// FlushDB delete all the keys of the currently selected DB.
// This command never fails.
func (r *Redis) FlushDB() error {
_, err := r.ExecuteCommand("FLUSHDB")
return err
}
// Info returns information and statistics about the server
// in a format that is simple to parse by computers and easy to read by humans.
// format document at http://redis.io/commands/info
func (r *Redis) Info(section string) (string, error) {
args := packArgs("INFO", section)
rp, err := r.ExecuteCommand(args...)
if err != nil {
return "", err
}
return rp.StringValue()
}
// LastSave return the UNIX TIME of the last DB save executed with success.
// A client may check if a BGSAVE command succeeded reading the LASTSAVE value,
// then issuing a BGSAVE command and checking at regular intervals every N seconds if LASTSAVE changed.
// Integer reply: an UNIX time stamp.
func (r *Redis) LastSave() (int64, error) {
rp, err := r.ExecuteCommand("LASTSAVE")
if err != nil {
return 0, err
}
return rp.IntegerValue()
}
// MonitorCommand is a debugging command that streams back every command processed by the Redis server.
type MonitorCommand struct {
redis *Redis
conn *connection
}
// Monitor sned MONITOR command to redis server.
func (r *Redis) Monitor() (*MonitorCommand, error) {
c, err := r.pool.Get()
if err != nil {
return nil, err
}
if err := c.SendCommand("MONITOR"); err != nil {
return nil, err
}
rp, err := c.RecvReply()
if err != nil {
return nil, err
}
if err := rp.OKValue(); err != nil {
return nil, err
}
return &MonitorCommand{r, c}, nil
}
// Receive read from redis server and return the reply.
func (m *MonitorCommand) Receive() (string, error) {
rp, err := m.conn.RecvReply()
if err != nil {
return "", err
}
return rp.StatusValue()
}
// Close closes current monitor command.
func (m *MonitorCommand) Close() error {
return m.conn.SendCommand("QUIT")
}
// Save performs a synchronous save of the dataset
// producing a point in time snapshot of all the data inside the Redis instance,
// in the form of an RDB file.
// You almost never want to call SAVE in production environments
// where it will block all the other clients. Instead usually BGSAVE is used.
func (r *Redis) Save() error {
rp, err := r.ExecuteCommand("SAVE")
if err != nil {
return err
}
return rp.OKValue()
}
// Shutdown behavior is the following:
// Stop all the clients.
// Perform a blocking SAVE if at least one save point is configured.
// Flush the Append Only File if AOF is enabled.
// Quit the server.
func (r *Redis) Shutdown(save, noSave bool) error {
args := packArgs("SHUTDOWN")
if save {
args = append(args, "SAVE")
} else if noSave {
args = append(args, "NOSAVE")
}
rp, err := r.ExecuteCommand(args...)
if err == io.EOF {
return nil
}
if err != nil {
return err
}
return errors.New(rp.Status)
}
// SlaveOf can change the replication settings of a slave on the fly.
// If a Redis server is already acting as slave, the command SLAVEOF NO ONE will turn off the replication,
// turning the Redis server into a MASTER.
// In the proper form SLAVEOF hostname port will make the server a slave of
// another server listening at the specified hostname and port.
//
// If a server is already a slave of some master,
// SLAVEOF hostname port will stop the replication against the old server
// and start the synchronization against the new one, discarding the old dataset.
// The form SLAVEOF NO ONE will stop replication, turning the server into a MASTER,
// but will not discard the replication.
// So, if the old master stops working,
// it is possible to turn the slave into a master and set the application to use this new master in read/write.
// Later when the other Redis server is fixed, it can be reconfigured to work as a slave.
func (r *Redis) SlaveOf(host, port string) error {
rp, err := r.ExecuteCommand("SLAVEOF", host, port)
if err != nil {
return err
}
return rp.OKValue()
}
// SlowLog is used in order to read and reset the Redis slow queries log.
type SlowLog struct {
ID int64
Timestamp int64
Microseconds int64
Command []string
}
// SlowLogGet returns slow logs.
func (r *Redis) SlowLogGet(n int) ([]*SlowLog, error) {
rp, err := r.ExecuteCommand("SLOWLOG", "GET", n)
if err != nil {
return nil, err
}
if rp.Type == ErrorReply {
return nil, errors.New(rp.Error)
}
if rp.Type != MultiReply {
return nil, errors.New("slowlog get protocol error")
}
var slow []*SlowLog
for _, subrp := range rp.Multi {
if subrp.Multi == nil || len(subrp.Multi) != 4 {
return nil, errors.New("slowlog get protocol error")
}
id, err := subrp.Multi[0].IntegerValue()
if err != nil {
return nil, err
}
timestamp, err := subrp.Multi[1].IntegerValue()
if err != nil {
return nil, err
}
microseconds, err := subrp.Multi[2].IntegerValue()
if err != nil {
return nil, err
}
command, err := subrp.Multi[3].ListValue()
if err != nil {
return nil, err
}
slow = append(slow, &SlowLog{id, timestamp, microseconds, command})
}
return slow, nil
}
// SlowLogLen Obtaining the current length of the slow log
func (r *Redis) SlowLogLen() (int64, error) {
rp, err := r.ExecuteCommand("SLOWLOG", "LEN")
if err != nil {
return 0, err
}
return rp.IntegerValue()
}
// SlowLogReset resetting the slow log.
// Once deleted the information is lost forever.
func (r *Redis) SlowLogReset() error {
rp, err := r.ExecuteCommand("SLOWLOG", "RESET")
if err != nil {
return err
}
return rp.OKValue()
}
// Time returns a multi bulk reply containing two elements:
// unix time in seconds,
// microseconds.
func (r *Redis) Time() ([]string, error) {
rp, err := r.ExecuteCommand("TIME")
if err != nil {
return nil, err
}
return rp.ListValue()
}