redis TCP concurrency
This commit is contained in:
parent
d9437be5a2
commit
72c34f3568
@ -10,6 +10,17 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RedisCmd struct {
|
||||||
|
cmd string
|
||||||
|
key string
|
||||||
|
val string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandExec struct {
|
||||||
|
*RedisCmd
|
||||||
|
Result chan string
|
||||||
|
}
|
||||||
|
|
||||||
func getCommand(reader io.Reader) (string, error) {
|
func getCommand(reader io.Reader) (string, error) {
|
||||||
scanner := bufio.NewScanner(reader)
|
scanner := bufio.NewScanner(reader)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
@ -32,8 +43,8 @@ func isCommand(str string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseCmd(line string) (string, string, string, error) {
|
func parseCmd(line string) (*RedisCmd, error) {
|
||||||
cmd, key, val := "", "", ""
|
redisCmd := new(RedisCmd)
|
||||||
var err error
|
var err error
|
||||||
parts := strings.Split(line, " ")
|
parts := strings.Split(line, " ")
|
||||||
if len(parts) != 2 && len(parts) != 3 {
|
if len(parts) != 2 && len(parts) != 3 {
|
||||||
@ -43,23 +54,23 @@ func parseCmd(line string) (string, string, string, error) {
|
|||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
if isCommand(part) {
|
if isCommand(part) {
|
||||||
cmd = part
|
redisCmd.cmd = part
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("Unknown command")
|
err = errors.New("Unknown command")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
key = part
|
redisCmd.key = part
|
||||||
case 2:
|
case 2:
|
||||||
if cmd == "SET" {
|
if redisCmd.cmd == "SET" {
|
||||||
val = part
|
redisCmd.val = part
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("Invalid number of arguments")
|
err = errors.New("Invalid number of arguments")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cmd, key, val, err
|
return redisCmd, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func respond(writer io.Writer, ret string) {
|
func respond(writer io.Writer, ret string) {
|
||||||
@ -78,39 +89,68 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer ln.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
|
commands := make(chan CommandExec)
|
||||||
|
go func() {
|
||||||
|
for exec := range commands {
|
||||||
|
switch exec.cmd {
|
||||||
|
case "DEL":
|
||||||
|
log.Println("Deleting", exec.key)
|
||||||
|
delete(db, exec.key)
|
||||||
|
close(exec.Result)
|
||||||
|
case "GET":
|
||||||
|
log.Println("Getting", exec.key)
|
||||||
|
ret, ok := db[exec.key]
|
||||||
|
if ok {
|
||||||
|
log.Println("Value found", ret)
|
||||||
|
go func() {
|
||||||
|
exec.Result <- ret
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
log.Println("Unknown key", exec.key)
|
||||||
|
close(exec.Result)
|
||||||
|
}
|
||||||
|
case "SET":
|
||||||
|
log.Println("Setting", exec.key)
|
||||||
|
db[exec.key] = exec.val
|
||||||
|
close(exec.Result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
conn, err := ln.Accept()
|
conn, err := ln.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
results := make(chan string)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
line, err := getCommand(conn)
|
ret, ok := <-results
|
||||||
if err != nil {
|
|
||||||
respond(conn, fmt.Sprint(err))
|
|
||||||
}
|
|
||||||
cmd, key, val, err := parseCmd(line)
|
|
||||||
if err != nil {
|
|
||||||
respond(conn, fmt.Sprint(err))
|
|
||||||
}
|
|
||||||
switch cmd {
|
|
||||||
case "DEL":
|
|
||||||
log.Println("Deleting", key)
|
|
||||||
delete(db, key)
|
|
||||||
case "GET":
|
|
||||||
log.Println("Getting", key)
|
|
||||||
ret, ok := db[key]
|
|
||||||
if ok {
|
if ok {
|
||||||
log.Println("Value found", ret)
|
|
||||||
respond(conn, ret)
|
respond(conn, ret)
|
||||||
} else {
|
|
||||||
log.Println("Unknown key", key)
|
|
||||||
}
|
|
||||||
case "SET":
|
|
||||||
log.Println("Setting", key)
|
|
||||||
db[key] = val
|
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
exec := new(CommandExec)
|
||||||
|
exec.Result = results
|
||||||
|
|
||||||
|
line, err := getCommand(conn)
|
||||||
|
if err != nil {
|
||||||
|
go func() {
|
||||||
|
exec.Result <- fmt.Sprint(err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
cmd, err := parseCmd(line)
|
||||||
|
if err != nil {
|
||||||
|
go func() {
|
||||||
|
exec.Result <- fmt.Sprint(err)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
exec.RedisCmd = cmd
|
||||||
|
commands <- *exec
|
||||||
|
}()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,20 +47,18 @@ func TestRespond(t *testing.T) {
|
|||||||
type ParseCmdTest struct {
|
type ParseCmdTest struct {
|
||||||
line string
|
line string
|
||||||
fails bool
|
fails bool
|
||||||
cmd string
|
RedisCmd
|
||||||
key string
|
|
||||||
val string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseCommand(t *testing.T) {
|
func TestParseCommand(t *testing.T) {
|
||||||
tests := []ParseCmdTest{
|
tests := []ParseCmdTest{
|
||||||
{"test", true, "", "", ""},
|
{"test", true, RedisCmd{"", "", ""}},
|
||||||
{"test test", true, "", "", ""},
|
{"test test", true, RedisCmd{"", "", ""}},
|
||||||
{"SET 1 2 3", true, "", "", ""},
|
{"SET 1 2 3", true, RedisCmd{"", "", ""}},
|
||||||
{"GET 1 2", true, "", "", ""},
|
{"GET 1 2", true, RedisCmd{"", "", ""}},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
c, k, v, e := parseCmd(test.line)
|
c, e := parseCmd(test.line)
|
||||||
if test.fails {
|
if test.fails {
|
||||||
if e == nil {
|
if e == nil {
|
||||||
t.Log("should fail (" + test.line + ")")
|
t.Log("should fail (" + test.line + ")")
|
||||||
@ -71,16 +69,16 @@ func TestParseCommand(t *testing.T) {
|
|||||||
t.Log("should no fail", e)
|
t.Log("should no fail", e)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
if c != test.cmd {
|
if c.cmd != test.cmd {
|
||||||
t.Log("Error command", c, test.cmd)
|
t.Log("Error command", c.cmd, test.cmd)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
if k != test.key {
|
if c.key != test.key {
|
||||||
t.Log("Error key", k, test.key)
|
t.Log("Error key", c.key, test.key)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
if v != test.val {
|
if c.val != test.val {
|
||||||
t.Log("Error value", v, test.val)
|
t.Log("Error value", c.val, test.val)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user