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 }