diff --git a/cmd/ledis-cli/const.go b/cmd/ledis-cli/const.go index 790a77b..5586f1a 100644 --- a/cmd/ledis-cli/const.go +++ b/cmd/ledis-cli/const.go @@ -1,4 +1,4 @@ -//This file was generated by .tools/generate_commands.py on Mon Oct 20 2014 22:35:33 +0800 +//This file was generated by .tools/generate_commands.py on Sun Oct 26 2014 15:14:39 +0800 package main var helpCommands = [][]string{ @@ -86,6 +86,7 @@ var helpCommands = [][]string{ {"SDIFFSTORE", "destination key [key ...]", "Set"}, {"SELECT", "index", "Server"}, {"SET", "key value", "KV"}, + {"SETEX", "key seconds value", "KV"}, {"SETNX", "key value", "KV"}, {"SEXPIRE", "key seconds", "Set"}, {"SEXPIREAT", "key timestamp", "Set"}, diff --git a/doc/commands.json b/doc/commands.json index b03e7f9..d435bc3 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -310,6 +310,11 @@ "group": "KV", "readonly": false }, + "SETEX": { + "arguments": "key seconds value", + "group": "KV", + "readonly": false + }, "SLAVEOF": { "arguments": "host port [RESTART] [READONLY]", "group": "Replication", diff --git a/doc/commands.md b/doc/commands.md index 9dcdca6..a5c0527 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -22,6 +22,7 @@ Table of Contents - [MSET key value [key value ...]](#mset-key-value-key-value-) - [SET key value](#set-key-value) - [SETNX key value](#setnx-key-value) + - [SETEX key seconds value](#setex-key-seconds-value) - [EXPIRE key seconds](#expire-key-seconds) - [EXPIREAT key timestamp](#expireat-key-timestamp) - [TTL key](#ttl-key) @@ -389,6 +390,30 @@ ledis> GET mykey "hello" ``` +### SETEX key seconds value +Set key to hold the string value and set key to timeout after a given number of seconds. This command is equivalent to executing the following commands: + +``` +SET mykey value +EXPIRE mykey seconds +``` + +**Return value** + +Simple string reply + +**Examples** + +``` +ledis> SETEX mykey 10 "Hello" +OK +ledis> TTL mykey +(integer) 10 +ledis> GET mykey +"Hello" +ledis> +``` + ### EXPIRE key seconds Set a timeout on key. After the timeout has expired, the key will be deleted. diff --git a/ledis/t_kv.go b/ledis/t_kv.go index 497dcf2..2a55425 100644 --- a/ledis/t_kv.go +++ b/ledis/t_kv.go @@ -300,6 +300,32 @@ func (db *DB) SetNX(key []byte, value []byte) (int64, error) { return n, err } +func (db *DB) SetEX(key []byte, duration int64, value []byte) error { + if err := checkKeySize(key); err != nil { + return err + } else if err := checkValueSize(value); err != nil { + return err + } else if duration <= 0 { + return errExpireValue + } + + ek := db.encodeKVKey(key) + + t := db.kvBatch + + t.Lock() + defer t.Unlock() + + t.Put(ek, value) + db.expireAt(t, KVType, key, time.Now().Unix()+duration) + + if err := t.Commit(); err != nil { + return err + } + + return nil +} + func (db *DB) flush() (drop int64, err error) { t := db.kvBatch t.Lock() diff --git a/ledis/t_kv_test.go b/ledis/t_kv_test.go index b0f3437..77ce706 100644 --- a/ledis/t_kv_test.go +++ b/ledis/t_kv_test.go @@ -116,3 +116,32 @@ func TestKVFlush(t *testing.T) { } } } + +func TestKVSetEX(t *testing.T) { + db := getTestDB() + db.FlushAll() + + key := []byte("testdb_kv_c") + + if err := db.SetEX(key, 10, []byte("hello world")); err != nil { + t.Fatal(err) + } + + v, err := db.Get(key) + if err != nil { + t.Fatal(err) + } else if string(v) == "" { + t.Fatal("v is nil") + } + + if n, err := db.TTL(key); err != nil { + t.Fatal(err) + } else if n != 10 { + t.Fatal(n) + } + + if v, _ := db.Get(key); string(v) != "hello world" { + t.Fatal(string(v)) + } + +} diff --git a/server/cmd_kv.go b/server/cmd_kv.go index c62cc18..0d2dc25 100644 --- a/server/cmd_kv.go +++ b/server/cmd_kv.go @@ -66,6 +66,26 @@ func setnxCommand(c *client) error { return nil } +func setexCommand(c *client) error { + args := c.args + if len(args) != 3 { + return ErrCmdParams + } + + sec, err := ledis.StrInt64(args[1], nil) + if err != nil { + return ErrValue + } + + if err := c.db.SetEX(args[0], sec, args[2]); err != nil { + return err + } else { + c.resp.writeStatus(OK) + } + + return nil +} + func existsCommand(c *client) error { args := c.args if len(args) != 1 { @@ -365,6 +385,7 @@ func init() { register("mset", msetCommand) register("set", setCommand) register("setnx", setnxCommand) + register("setex", setexCommand) register("expire", expireCommand) register("expireat", expireAtCommand) register("ttl", ttlCommand) diff --git a/server/cmd_kv_test.go b/server/cmd_kv_test.go index d24fd25..d3b0fe4 100644 --- a/server/cmd_kv_test.go +++ b/server/cmd_kv_test.go @@ -27,6 +27,12 @@ func TestKV(t *testing.T) { t.Fatal(n) } + if ok, err := ledis.String(c.Do("setex", "xx", 10, "hello world")); err != nil { + t.Fatal(err) + } else if ok != OK { + t.Fatal(ok) + } + if v, err := ledis.String(c.Do("get", "a")); err != nil { t.Fatal(err) } else if v != "1234" { @@ -214,4 +220,8 @@ func TestKVErrorParams(t *testing.T) { t.Fatal("invalid err of %v", err) } + if _, err := c.Do("setex", "a", "blah", "hello world"); err == nil { + t.Fatalf("invalid err %v", err) + } + }