From 45df01b385dd1b6f4a93516f343245869233d818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Sun, 19 Feb 2023 13:23:40 +0100 Subject: [PATCH] Add implementation of the SETNX command This is an optimized "SET if not exists" command, which basically does an EXISTS call before the SET. --- README.md | 17 +++++++++++++++++ example/clone.go | 16 ++++++++++++++++ example/mux/clone.go | 1 + example/mux/handler.go | 22 ++++++++++++++++++++++ example/tls/clone.go | 16 ++++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/README.md b/README.md index 89c836d..1b12a38 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Here's a full example of a Redis clone that accepts: - SET key value - GET key +- SETNX key value - DEL key - PING - QUIT @@ -96,6 +97,22 @@ func main() { } else { conn.WriteBulk(val) } + case "setnx": + if len(cmd.Args) != 3 { + conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") + return + } + mu.RLock() + _, ok := items[string(cmd.Args[1])] + mu.RUnlock() + if ok { + conn.WriteInt(0) + return + } + mu.Lock() + items[string(cmd.Args[1])] = cmd.Args[2] + mu.Unlock() + conn.WriteInt(1) case "del": if len(cmd.Args) != 2 { conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") diff --git a/example/clone.go b/example/clone.go index f7615d7..d99914f 100644 --- a/example/clone.go +++ b/example/clone.go @@ -82,6 +82,22 @@ func main() { } else { conn.WriteBulk(val) } + case "setnx": + if len(cmd.Args) != 3 { + conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") + return + } + mu.RLock() + _, ok := items[string(cmd.Args[1])] + mu.RUnlock() + if ok { + conn.WriteInt(0) + return + } + mu.Lock() + items[string(cmd.Args[1])] = cmd.Args[2] + mu.Unlock() + conn.WriteInt(1) case "del": if len(cmd.Args) != 2 { conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") diff --git a/example/mux/clone.go b/example/mux/clone.go index bc47d65..6e626af 100644 --- a/example/mux/clone.go +++ b/example/mux/clone.go @@ -19,6 +19,7 @@ func main() { mux.HandleFunc("quit", handler.quit) mux.HandleFunc("set", handler.set) mux.HandleFunc("get", handler.get) + mux.HandleFunc("setnx", handler.setnx) mux.HandleFunc("del", handler.delete) err := redcon.ListenAndServe(addr, diff --git a/example/mux/handler.go b/example/mux/handler.go index dd5e616..2eea590 100644 --- a/example/mux/handler.go +++ b/example/mux/handler.go @@ -68,6 +68,28 @@ func (h *Handler) get(conn redcon.Conn, cmd redcon.Command) { } } +func (h *Handler) setnx(conn redcon.Conn, cmd redcon.Command) { + if len(cmd.Args) != 3 { + conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") + return + } + + h.itemsMux.RLock() + _, ok := h.items[string(cmd.Args[1])] + h.itemsMux.RUnlock() + + if ok { + conn.WriteInt(0) + return + } + + h.itemsMux.Lock() + h.items[string(cmd.Args[1])] = cmd.Args[2] + h.itemsMux.Unlock() + + conn.WriteInt(1) +} + func (h *Handler) delete(conn redcon.Conn, cmd redcon.Command) { if len(cmd.Args) != 2 { conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") diff --git a/example/tls/clone.go b/example/tls/clone.go index 8d1b67c..43cd2f0 100644 --- a/example/tls/clone.go +++ b/example/tls/clone.go @@ -88,6 +88,22 @@ func main() { } else { conn.WriteBulk(val) } + case "setnx": + if len(cmd.Args) != 3 { + conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command") + return + } + mu.RLock() + _, ok := items[string(cmd.Args[1])] + mu.RUnlock() + if ok { + conn.WriteInt(0) + return + } + mu.Lock() + items[string(cmd.Args[1])] = cmd.Args[2] + mu.Unlock() + conn.WriteInt(1) case "del": if len(cmd.Args) != 2 { conn.WriteError("ERR wrong number of arguments for '" + string(cmd.Args[0]) + "' command")