Skip to content

Commit 45df01b

Browse files
committed
Add implementation of the SETNX command
This is an optimized "SET if not exists" command, which basically does an EXISTS call before the SET.
1 parent 9f71787 commit 45df01b

File tree

5 files changed

+72
-0
lines changed

5 files changed

+72
-0
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Here's a full example of a Redis clone that accepts:
3434

3535
- SET key value
3636
- GET key
37+
- SETNX key value
3738
- DEL key
3839
- PING
3940
- QUIT
@@ -96,6 +97,22 @@ func main() {
9697
} else {
9798
conn.WriteBulk(val)
9899
}
100+
case "setnx":
101+
if len(cmd.Args) != 3 {
102+
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
103+
return
104+
}
105+
mu.RLock()
106+
_, ok := items[string(cmd.Args[1])]
107+
mu.RUnlock()
108+
if ok {
109+
conn.WriteInt(0)
110+
return
111+
}
112+
mu.Lock()
113+
items[string(cmd.Args[1])] = cmd.Args[2]
114+
mu.Unlock()
115+
conn.WriteInt(1)
99116
case "del":
100117
if len(cmd.Args) != 2 {
101118
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")

example/clone.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,22 @@ func main() {
8282
} else {
8383
conn.WriteBulk(val)
8484
}
85+
case "setnx":
86+
if len(cmd.Args) != 3 {
87+
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
88+
return
89+
}
90+
mu.RLock()
91+
_, ok := items[string(cmd.Args[1])]
92+
mu.RUnlock()
93+
if ok {
94+
conn.WriteInt(0)
95+
return
96+
}
97+
mu.Lock()
98+
items[string(cmd.Args[1])] = cmd.Args[2]
99+
mu.Unlock()
100+
conn.WriteInt(1)
85101
case "del":
86102
if len(cmd.Args) != 2 {
87103
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")

example/mux/clone.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func main() {
1919
mux.HandleFunc("quit", handler.quit)
2020
mux.HandleFunc("set", handler.set)
2121
mux.HandleFunc("get", handler.get)
22+
mux.HandleFunc("setnx", handler.setnx)
2223
mux.HandleFunc("del", handler.delete)
2324

2425
err := redcon.ListenAndServe(addr,

example/mux/handler.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,28 @@ func (h *Handler) get(conn redcon.Conn, cmd redcon.Command) {
6868
}
6969
}
7070

71+
func (h *Handler) setnx(conn redcon.Conn, cmd redcon.Command) {
72+
if len(cmd.Args) != 3 {
73+
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
74+
return
75+
}
76+
77+
h.itemsMux.RLock()
78+
_, ok := h.items[string(cmd.Args[1])]
79+
h.itemsMux.RUnlock()
80+
81+
if ok {
82+
conn.WriteInt(0)
83+
return
84+
}
85+
86+
h.itemsMux.Lock()
87+
h.items[string(cmd.Args[1])] = cmd.Args[2]
88+
h.itemsMux.Unlock()
89+
90+
conn.WriteInt(1)
91+
}
92+
7193
func (h *Handler) delete(conn redcon.Conn, cmd redcon.Command) {
7294
if len(cmd.Args) != 2 {
7395
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")

example/tls/clone.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,22 @@ func main() {
8888
} else {
8989
conn.WriteBulk(val)
9090
}
91+
case "setnx":
92+
if len(cmd.Args) != 3 {
93+
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")
94+
return
95+
}
96+
mu.RLock()
97+
_, ok := items[string(cmd.Args[1])]
98+
mu.RUnlock()
99+
if ok {
100+
conn.WriteInt(0)
101+
return
102+
}
103+
mu.Lock()
104+
items[string(cmd.Args[1])] = cmd.Args[2]
105+
mu.Unlock()
106+
conn.WriteInt(1)
91107
case "del":
92108
if len(cmd.Args) != 2 {
93109
conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")

0 commit comments

Comments
 (0)