github.com/therealbill/libredis@v0.0.0-20161227004305-7d50abda5ccf/client/server.go (about)

     1  package client
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"net"
     8  	"strconv"
     9  
    10  	"github.com/therealbill/libredis/info"
    11  	"github.com/therealbill/libredis/structures"
    12  )
    13  
    14  // BgRewriteAof Instruct Redis to start an Append Only File rewrite process.
    15  // The rewrite will create a small optimized version of the current Append Only File.
    16  func (r *Redis) BgRewriteAof() error {
    17  	_, err := r.ExecuteCommand("BGREWRITEAOF")
    18  	return err
    19  }
    20  
    21  // BgSave save the DB in background.
    22  // The OK code is immediately returned.
    23  // Redis forks, the parent continues to serve the clients, the child saves the DB on disk then exits.
    24  // A client my be able to check if the operation succeeded using the LASTSAVE command.
    25  func (r *Redis) BgSave() error {
    26  	_, err := r.ExecuteCommand("BGSAVE")
    27  	return err
    28  }
    29  
    30  // ClientKill closes a given client connection identified by ip:port.
    31  // Due to the single-treaded nature of Redis,
    32  // it is not possible to kill a client connection while it is executing a command.
    33  // However, the client will notice the connection has been closed
    34  // only when the next command is sent (and results in network error).
    35  // Status code reply: OK if the connection exists and has been closed
    36  func (r *Redis) ClientKill(ip string, port int) error {
    37  	rp, err := r.ExecuteCommand("CLIENT", "KILL", net.JoinHostPort(ip, strconv.Itoa(port)))
    38  	if err != nil {
    39  		return err
    40  	}
    41  	return rp.OKValue()
    42  }
    43  
    44  // Role() returns the current role name on the server. Requires Redis >= 2.8.12
    45  func (r *Redis) Role() (sl []string, err error) {
    46  	rp, err := r.ExecuteCommand("ROLE")
    47  	if err != nil {
    48  		return sl, err
    49  	}
    50  	return rp.Multi[1].ListValue()
    51  }
    52  
    53  // RoleName() returns the current role name on the server. Requires Redis >= 2.8.12
    54  // This is a shorthand for those who only want the name of the role rather than
    55  // all the details.
    56  func (r *Redis) RoleName() (string, error) {
    57  	rp, err := r.ExecuteCommand("ROLE")
    58  	if err != nil {
    59  		return "", err
    60  	}
    61  	return rp.Multi[0].StringValue()
    62  }
    63  
    64  // ClientList returns information and statistics
    65  // about the client connections server in a mostly human readable format.
    66  // Bulk reply: a unique string, formatted as follows:
    67  // One client connection per line (separated by LF)
    68  // Each line is composed of a succession of property=value fields separated by a space character.
    69  func (r *Redis) ClientList() (string, error) {
    70  	rp, err := r.ExecuteCommand("CLIENT", "LIST")
    71  	if err != nil {
    72  		return "", err
    73  	}
    74  	return rp.StringValue()
    75  }
    76  
    77  // ClientGetName returns the name of the current connection as set by CLIENT SETNAME.
    78  // Since every new connection starts without an associated name,
    79  // if no name was assigned a null bulk reply is returned.
    80  func (r *Redis) ClientGetName() ([]byte, error) {
    81  	rp, err := r.ExecuteCommand("CLIENT", "GETNAME")
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	return rp.BytesValue()
    86  }
    87  
    88  // ClientPause stops the server processing commands from clients for some time.
    89  func (r *Redis) ClientPause(timeout uint64) error {
    90  	rp, err := r.ExecuteCommand("CLIENT", "PAUSE", timeout)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	return rp.OKValue()
    95  }
    96  
    97  // ClientSetName assigns a name to the current connection.
    98  func (r *Redis) ClientSetName(name string) error {
    99  	rp, err := r.ExecuteCommand("CLIENT", "SETNAME", name)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	return rp.OKValue()
   104  }
   105  
   106  // ConfigGet is used to read the configuration parameters of a running Redis server.
   107  // Not all the configuration parameters are supported in Redis 2.4,
   108  // while Redis 2.6 can read the whole configuration of a server using this command.
   109  // CONFIG GET takes a single argument, which is a glob-style pattern.
   110  func (r *Redis) ConfigGet(parameter string) (map[string]string, error) {
   111  	rp, err := r.ExecuteCommand("CONFIG", "GET", parameter)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	return rp.HashValue()
   116  }
   117  
   118  // ConfigRewrite rewrites the redis.conf file the server was started with,
   119  // applying the minimal changes needed to make it reflecting the configuration currently used by the server,
   120  // that may be different compared to the original one because of the use of the CONFIG SET command.
   121  // Available since 2.8.0.
   122  func (r *Redis) ConfigRewrite() error {
   123  	rp, err := r.ExecuteCommand("CONFIG", "REWRITE")
   124  	if err != nil {
   125  		return err
   126  	}
   127  	return rp.OKValue()
   128  }
   129  
   130  // ConfigSet is used in order to reconfigure the server at run time without the need to restart Redis.
   131  // You can change both trivial parameters or switch from one to another persistence option using this command.
   132  func (r *Redis) ConfigSet(parameter, value string) error {
   133  	rp, err := r.ExecuteCommand("CONFIG", "SET", parameter, value)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	return rp.OKValue()
   138  }
   139  
   140  // ConfigSetInt is a convenience wrapper for passing integers to ConfigSet
   141  func (r *Redis) ConfigSetInt(parameter string, value int) error {
   142  	sval := fmt.Sprintf("%d", value)
   143  	rp, err := r.ExecuteCommand("CONFIG", "SET", parameter, sval)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	return rp.OKValue()
   148  }
   149  
   150  // ConfigResetStat resets the statistics reported by Redis using the INFO command.
   151  // These are the counters that are reset:
   152  // Keyspace hits
   153  // Keyspace misses
   154  // Number of commands processed
   155  // Number of connections received
   156  // Number of expired keys
   157  // Number of rejected connections
   158  // Latest fork(2) time
   159  // The aof_delayed_fsync counter
   160  func (r *Redis) ConfigResetStat() error {
   161  	_, err := r.ExecuteCommand("CONFIG", "RESETSTAT")
   162  	return err
   163  }
   164  
   165  // DBSize return the number of keys in the currently-selected database.
   166  func (r *Redis) DBSize() (int64, error) {
   167  	rp, err := r.ExecuteCommand("DBSIZE")
   168  	if err != nil {
   169  		return 0, err
   170  	}
   171  	return rp.IntegerValue()
   172  }
   173  
   174  // DebugObject is a debugging command that should not be used by clients.
   175  func (r *Redis) DebugObject(key string) (string, error) {
   176  	rp, err := r.ExecuteCommand("DEBUG", "OBJECT", key)
   177  	if err != nil {
   178  		return "", err
   179  	}
   180  	return rp.StatusValue()
   181  }
   182  
   183  // FlushAll delete all the keys of all the existing databases,
   184  // not just the currently selected one.
   185  // This command never fails.
   186  func (r *Redis) FlushAll() error {
   187  	_, err := r.ExecuteCommand("FLUSHALL")
   188  	return err
   189  }
   190  
   191  // FlushDB delete all the keys of the currently selected DB.
   192  // This command never fails.
   193  func (r *Redis) FlushDB() error {
   194  	_, err := r.ExecuteCommand("FLUSHDB")
   195  	return err
   196  }
   197  
   198  // Info returns information and statistics about the server
   199  // In RedisInfoAll struct see the github.com/therealbill/libredis/info package
   200  // for details
   201  func (r *Redis) Info() (sinfo structures.RedisInfoAll, err error) {
   202  	rp, err := r.ExecuteCommand("info", "all")
   203  	if err != nil {
   204  		return
   205  	}
   206  	strval, _ := rp.StringValue()
   207  	if err != nil {
   208  		return
   209  	}
   210  	sinfo = info.GetAllInfo(strval)
   211  	return
   212  }
   213  
   214  // SentinelInfo returns information and statistics for a sentinel instance
   215  // In RedisInfoAll struct see the github.com/therealbill/libredis/info package
   216  // for details
   217  func (r *Redis) SentinelInfo() (sinfo structures.RedisInfoAll, err error) {
   218  	rp, err := r.ExecuteCommand("info")
   219  	if err != nil {
   220  		return
   221  	}
   222  	strval, _ := rp.StringValue()
   223  	if err != nil {
   224  		return
   225  	}
   226  	sinfo = info.GetAllInfo(strval)
   227  	return
   228  }
   229  
   230  // InfoString returns information and statistics about the server
   231  // in a format that is simple to parse by computers and easy to read by humans.
   232  // format document at http://redis.io/commands/info
   233  func (r *Redis) InfoString(section string) (string, error) {
   234  	args := packArgs("INFO", section)
   235  	rp, err := r.ExecuteCommand(args...)
   236  	if err != nil {
   237  		return "", err
   238  	}
   239  	return rp.StringValue()
   240  }
   241  
   242  // LastSave return the UNIX TIME of the last DB save executed with success.
   243  // A client may check if a BGSAVE command succeeded reading the LASTSAVE value,
   244  // then issuing a BGSAVE command and checking at regular intervals every N seconds if LASTSAVE changed.
   245  // Integer reply: an UNIX time stamp.
   246  func (r *Redis) LastSave() (int64, error) {
   247  	rp, err := r.ExecuteCommand("LASTSAVE")
   248  	if err != nil {
   249  		return 0, err
   250  	}
   251  	return rp.IntegerValue()
   252  }
   253  
   254  // MonitorCommand is a debugging command that streams back every command processed by the Redis server.
   255  type MonitorCommand struct {
   256  	redis *Redis
   257  	conn  *connection
   258  }
   259  
   260  // Monitor sned MONITOR command to redis server.
   261  func (r *Redis) Monitor() (*MonitorCommand, error) {
   262  	c, err := r.pool.Get()
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  	if err := c.SendCommand("MONITOR"); err != nil {
   267  		return nil, err
   268  	}
   269  	rp, err := c.RecvReply()
   270  	if err != nil {
   271  		return nil, err
   272  	}
   273  	if err := rp.OKValue(); err != nil {
   274  		return nil, err
   275  	}
   276  	return &MonitorCommand{r, c}, nil
   277  }
   278  
   279  // Receive read from redis server and return the reply.
   280  func (m *MonitorCommand) Receive() (string, error) {
   281  	rp, err := m.conn.RecvReply()
   282  	if err != nil {
   283  		return "", err
   284  	}
   285  	return rp.StatusValue()
   286  }
   287  
   288  // Close closes current monitor command.
   289  func (m *MonitorCommand) Close() error {
   290  	return m.conn.SendCommand("QUIT")
   291  }
   292  
   293  // Save performs a synchronous save of the dataset
   294  // producing a point in time snapshot of all the data inside the Redis instance,
   295  // in the form of an RDB file.
   296  // You almost never want to call SAVE in production environments
   297  // where it will block all the other clients. Instead usually BGSAVE is used.
   298  func (r *Redis) Save() error {
   299  	rp, err := r.ExecuteCommand("SAVE")
   300  	if err != nil {
   301  		return err
   302  	}
   303  	return rp.OKValue()
   304  }
   305  
   306  // Shutdown behavior is the following:
   307  // Stop all the clients.
   308  // Perform a blocking SAVE if at least one save point is configured.
   309  // Flush the Append Only File if AOF is enabled.
   310  // Quit the server.
   311  func (r *Redis) Shutdown(save bool) error {
   312  	args := packArgs("SHUTDOWN")
   313  	if save {
   314  		args = append(args, "SAVE")
   315  	} else {
   316  		args = append(args, "NOSAVE")
   317  	}
   318  	rp, err := r.ExecuteCommand(args...)
   319  	if err == io.EOF {
   320  		return nil
   321  	}
   322  	if err != nil {
   323  		return err
   324  	}
   325  	return errors.New(rp.Status)
   326  }
   327  
   328  // SlaveOf can change the replication settings of a slave on the fly.
   329  // If a Redis server is already acting as slave, the command SLAVEOF NO ONE will turn off the replication,
   330  // turning the Redis server into a MASTER.
   331  // In the proper form SLAVEOF hostname port will make the server a slave of
   332  // another server listening at the specified hostname and port.
   333  //
   334  // If a server is already a slave of some master,
   335  // SLAVEOF hostname port will stop the replication against the old server
   336  // and start the synchronization against the new one, discarding the old dataset.
   337  // The form SLAVEOF NO ONE will stop replication, turning the server into a MASTER,
   338  // but will not discard the replication.
   339  // So, if the old master stops working,
   340  // it is possible to turn the slave into a master and set the application to use this new master in read/write.
   341  // Later when the other Redis server is fixed, it can be reconfigured to work as a slave.
   342  func (r *Redis) SlaveOf(host, port string) error {
   343  	rp, err := r.ExecuteCommand("SLAVEOF", host, port)
   344  	if err != nil {
   345  		return err
   346  	}
   347  	return rp.OKValue()
   348  }
   349  
   350  // SlowLog is used in order to read and reset the Redis slow queries log.
   351  type SlowLog struct {
   352  	ID           int64
   353  	Timestamp    int64
   354  	Microseconds int64
   355  	Command      []string
   356  }
   357  
   358  // SlowLogGet returns slow logs.
   359  func (r *Redis) SlowLogGet(n int64) ([]*SlowLog, error) {
   360  	rp, err := r.ExecuteCommand("SLOWLOG", "GET", n)
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  	if rp.Type == ErrorReply {
   365  		return nil, errors.New(rp.Error)
   366  	}
   367  	if rp.Type != MultiReply {
   368  		return nil, errors.New("slowlog get protocol error")
   369  	}
   370  	var slow []*SlowLog
   371  	for _, subrp := range rp.Multi {
   372  		if subrp.Multi == nil || len(subrp.Multi) != 4 {
   373  			return nil, errors.New("slowlog get protocol error")
   374  		}
   375  		id, err := subrp.Multi[0].IntegerValue()
   376  		if err != nil {
   377  			return nil, err
   378  		}
   379  		timestamp, err := subrp.Multi[1].IntegerValue()
   380  		if err != nil {
   381  			return nil, err
   382  		}
   383  		microseconds, err := subrp.Multi[2].IntegerValue()
   384  		if err != nil {
   385  			return nil, err
   386  		}
   387  		command, err := subrp.Multi[3].ListValue()
   388  		if err != nil {
   389  			return nil, err
   390  		}
   391  		slow = append(slow, &SlowLog{id, timestamp, microseconds, command})
   392  	}
   393  	return slow, nil
   394  }
   395  
   396  // SlowLogLen Obtaining the current length of the slow log
   397  func (r *Redis) SlowLogLen() (int64, error) {
   398  	rp, err := r.ExecuteCommand("SLOWLOG", "LEN")
   399  	if err != nil {
   400  		return 0, err
   401  	}
   402  	return rp.IntegerValue()
   403  }
   404  
   405  // SlowLogReset resetting the slow log.
   406  // Once deleted the information is lost forever.
   407  func (r *Redis) SlowLogReset() error {
   408  	rp, err := r.ExecuteCommand("SLOWLOG", "RESET")
   409  	if err != nil {
   410  		return err
   411  	}
   412  	return rp.OKValue()
   413  }
   414  
   415  // Time returns a multi bulk reply containing two elements:
   416  // unix time in seconds,
   417  // microseconds.
   418  func (r *Redis) Time() ([]string, error) {
   419  	rp, err := r.ExecuteCommand("TIME")
   420  	if err != nil {
   421  		return nil, err
   422  	}
   423  	return rp.ListValue()
   424  }
   425  
   426  // Command returns the Redis command info structures
   427  func (r *Redis) Command() (comms []structures.CommandEntry, err error) {
   428  	rp, err := r.ExecuteCommand("COMMAND")
   429  	if err != nil {
   430  		return nil, err
   431  	}
   432  	for _, subrp := range rp.Multi {
   433  		name, _ := subrp.Multi[0].StringValue()
   434  		arity, _ := subrp.Multi[1].IntegerValue()
   435  		first, _ := subrp.Multi[3].IntegerValue()
   436  		last, _ := subrp.Multi[4].IntegerValue()
   437  		repeat, _ := subrp.Multi[5].IntegerValue()
   438  		ce := structures.CommandEntry{Name: name, Arity: arity, FirstKey: first, LastKey: last, RepeatCount: repeat}
   439  		flagmap := make(map[string]bool)
   440  		for _, crp := range subrp.Multi[2].Multi {
   441  			flag, _ := crp.StatusValue()
   442  			flagmap[flag] = true
   443  		}
   444  		ce.Flags = flagmap
   445  		comms = append(comms, ce)
   446  	}
   447  	return
   448  }