Skip to content

Commit

Permalink
opt: optimize RESP parser performance
Browse files Browse the repository at this point in the history
  • Loading branch information
xgzlucario committed Jun 15, 2024
1 parent 018e081 commit 1777572
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 186 deletions.
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,9 @@ git clone https://github.com/xgzlucario/rotom

```
$ go run .
2024/06/05 15:26:47 cmd arguments: config=config.json, debug=false
2024/06/05 15:26:47 read config file: {
"port": 6379,
"appendonly": false,
"appendfilename": "appendonly.aof"
}
2024/06/05 15:26:47 rotom server is ready to accept.
2024-06-15 16:41:22 DBG read cmd arguments config=config.json debug=true
2024-06-15 16:41:22 DBG running on port=6379
2024-06-15 16:41:22 DBG rotom server is ready to accept.
```

**容器运行**
Expand All @@ -68,7 +64,7 @@ $ go run .

```
REPOSITORY TAG IMAGE ID CREATED SIZE
rotom latest 22f42ce9ae0e 8 seconds ago 18.4MB
rotom latest 22f42ce9ae0e 8 seconds ago 18.6MB
```

然后启动容器:
Expand Down
6 changes: 3 additions & 3 deletions aof.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (aof *Aof) Flush() error {
return aof.file.Sync()
}

func (aof *Aof) Read(fn func(value Value)) error {
func (aof *Aof) Read(fn func(args []Arg)) error {
// Read file data by mmap.
data, err := mmap.Open(aof.filePath, false)
if len(data) == 0 {
Expand All @@ -61,14 +61,14 @@ func (aof *Aof) Read(fn func(value Value)) error {
// Iterate over the records in the file, applying the function to each.
reader := NewResp(data)
for {
value, err := reader.Read()
values, err := reader.ReadNextCommand(nil)
if err != nil {
if err == io.EOF {
break
}
return err
}
fn(value)
fn(values)
}

return nil
Expand Down
8 changes: 4 additions & 4 deletions aof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ func TestAof(t *testing.T) {
assert.Nil(err)
defer aof.Close()

aof.Read(func(value Value) {
assert.Equal(value.Append(nil), setCommand)
})
// aof.Read(func(value []Value) {
// assert.Equal(value.Append(nil), setCommand)
// })
})

t.Run("read-error", func(t *testing.T) {
aof, _ := NewAof("not-exist.aof")
defer aof.Close()

aof.Read(func(value Value) {
aof.Read(func(args []Arg) {
panic("should not call")
})
})
Expand Down
4 changes: 2 additions & 2 deletions bench.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
docker stop rotom
docker run --rm -d --name rotom rotom
sleep 3
docker exec rotom redis-benchmark -t set,get,hset,rpush -P 10 > output_rotom
docker exec rotom redis-benchmark -t set,get,hset,rpush > output_rotom
) &

wait
Expand All @@ -14,7 +14,7 @@ wait
docker stop redis
docker run --rm -d --name redis redis
sleep 3
docker exec redis redis-benchmark -t set,get,hset,rpush -P 10 > output_redis
docker exec redis redis-benchmark -t set,get,hset,rpush > output_redis
) &

wait
Expand Down
51 changes: 31 additions & 20 deletions command.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package main

import (
"strings"

"github.com/xgzlucario/rotom/structx"
)

Expand All @@ -12,7 +10,7 @@ type Command struct {
name string

// handler is this command real database handler function.
handler func([]Value) Value
handler func([]Arg) Value

// arity represents the minimal number of arguments that command accepts.
arity int
Expand All @@ -39,34 +37,47 @@ var cmdTable []*Command = []*Command{
}

func lookupCommand(command string) *Command {
cmdStr := strings.ToLower(command)
for _, c := range cmdTable {
if c.name == cmdStr {
if equalCommand(command, c.name) {
return c
}
}
return nil
}

func (cmd *Command) processCommand(args []Value) Value {
func equalCommand(str, lowerText string) bool {
if len(str) != len(lowerText) {
return false
}
const s = 'a' - 'A'
for i, lo := range lowerText {
delta := lo - rune(str[i])
if delta != 0 && delta != s {
return false
}
}
return true
}

func (cmd *Command) processCommand(args []Arg) Value {
if len(args) < cmd.arity {
return newErrValue(ErrWrongNumberArgs(cmd.name))
}
return cmd.handler(args)
}

func pingCommand(_ []Value) Value {
func pingCommand(_ []Arg) Value {
return Value{typ: STRING, raw: []byte("PONG")}
}

func setCommand(args []Value) Value {
func setCommand(args []Arg) Value {
key := args[0].ToString()
value := args[1].ToBytes()
db.strs.Set(key, value)
return ValueOK
}

func getCommand(args []Value) Value {
func getCommand(args []Arg) Value {
key := args[0].ToStringUnsafe()

value, _, ok := db.strs.Get(key)
Expand All @@ -81,7 +92,7 @@ func getCommand(args []Value) Value {
return ValueNull
}

func hsetCommand(args []Value) Value {
func hsetCommand(args []Arg) Value {
hash := args[0].ToString()
args = args[1:]

Expand All @@ -106,7 +117,7 @@ func hsetCommand(args []Value) Value {
return newIntegerValue(newFields)
}

func hgetCommand(args []Value) Value {
func hgetCommand(args []Arg) Value {
hash := args[0].ToStringUnsafe()
key := args[1].ToStringUnsafe()

Expand All @@ -121,7 +132,7 @@ func hgetCommand(args []Value) Value {
return newBulkValue(value)
}

func hdelCommand(args []Value) Value {
func hdelCommand(args []Arg) Value {
hash := args[0].ToString()
keys := args[1:]

Expand All @@ -138,7 +149,7 @@ func hdelCommand(args []Value) Value {
return newIntegerValue(success)
}

func hgetallCommand(args []Value) Value {
func hgetallCommand(args []Arg) Value {
hash := args[0].ToString()

hmap, err := fetchMap(hash)
Expand All @@ -154,15 +165,15 @@ func hgetallCommand(args []Value) Value {
return newArrayValue(res)
}

func lpushCommand(args []Value) Value {
func lpushCommand(args []Arg) Value {
return pushInternal(args, true)
}

func rpushCommand(args []Value) Value {
func rpushCommand(args []Arg) Value {
return pushInternal(args, false)
}

func pushInternal(args []Value, isDirectLeft bool) Value {
func pushInternal(args []Arg, isDirectLeft bool) Value {
key := args[0].ToString()

ls, err := fetchList(key, true)
Expand All @@ -181,15 +192,15 @@ func pushInternal(args []Value, isDirectLeft bool) Value {
return newIntegerValue(ls.Size())
}

func lpopCommand(args []Value) Value {
func lpopCommand(args []Arg) Value {
return popInternal(args, true)
}

func rpopCommand(args []Value) Value {
func rpopCommand(args []Arg) Value {
return popInternal(args, false)
}

func popInternal(args []Value, isDirectLeft bool) Value {
func popInternal(args []Arg, isDirectLeft bool) Value {
key := args[0].ToString()

ls, err := fetchList(key)
Expand All @@ -210,7 +221,7 @@ func popInternal(args []Value, isDirectLeft bool) Value {
return newBulkValue(nil)
}

func lrangeCommand(args []Value) Value {
func lrangeCommand(args []Arg) Value {
key := args[0].ToString()
start, err := args[1].ToInt()
if err != nil {
Expand Down
8 changes: 5 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,25 @@ require (
github.com/sakeven/RbTree v1.1.1
github.com/stretchr/testify v1.9.0
github.com/tidwall/mmap v0.3.0
github.com/xgzlucario/GigaCache v0.0.0-20240612154219-55320030c9ec
github.com/xgzlucario/GigaCache v0.0.0-20240614161308-886947cfb989
github.com/xgzlucario/quicklist v0.0.0-20240530174658-6f1a884f579b
golang.org/x/sys v0.21.0
)

require (
github.com/bits-and-blooms/bitset v1.13.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cockroachdb/swiss v0.0.0-20240605133600-232b93a2b829 // indirect
github.com/cockroachdb/swiss v0.0.0-20240612210725-f4de07ae6964 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
19 changes: 13 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cockroachdb/swiss v0.0.0-20240605133600-232b93a2b829 h1:sU50KSd7d+GRu+5r5K3WPXRqmmSGerLZ6p3kFosYpFA=
github.com/cockroachdb/swiss v0.0.0-20240605133600-232b93a2b829/go.mod h1:yBRu/cnL4ks9bgy4vAASdjIW+/xMlFwuHKqtmh3GZQg=
github.com/cockroachdb/swiss v0.0.0-20240612210725-f4de07ae6964 h1:Ew0znI2JatzKy52N1iS5muUsHkf2UJuhocH7uFW7jjs=
github.com/cockroachdb/swiss v0.0.0-20240612210725-f4de07ae6964/go.mod h1:yBRu/cnL4ks9bgy4vAASdjIW+/xMlFwuHKqtmh3GZQg=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -25,6 +25,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand Down Expand Up @@ -55,14 +57,19 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/mmap v0.3.0 h1:XXt1YsiXCF5/UAu3pLbu6g7iulJ9jsbs6vt7UpiV0sY=
github.com/tidwall/mmap v0.3.0/go.mod h1:2/dNzF5zA+te/JVHfrqNLcRkb8LjdH3c80vYHFQEZRk=
github.com/xgzlucario/GigaCache v0.0.0-20240612154219-55320030c9ec h1:zqja/H/phFV0Z56sntDByz8E52tmepFM4k9b4S9xCHw=
github.com/xgzlucario/GigaCache v0.0.0-20240612154219-55320030c9ec/go.mod h1:aD6u4clIF+hGKyw+QgLzc1jhk9zQ/CygCbGhAv9QmsQ=
github.com/xgzlucario/GigaCache v0.0.0-20240614161308-886947cfb989 h1:oBY9eL6HxLYH7bATgeXwBrebPSKrz0IC+VTBNtINn/k=
github.com/xgzlucario/GigaCache v0.0.0-20240614161308-886947cfb989/go.mod h1:ChL9yLENqn4jVon23LCNQ6fPPEdA9u8vgvnpDIDlVEs=
github.com/xgzlucario/quicklist v0.0.0-20240530174658-6f1a884f579b h1:C/+nN/kFJ6yrmEhIu+5Ra2jx/W8w+Ayu8pTiZfuU5Xc=
github.com/xgzlucario/quicklist v0.0.0-20240530174658-6f1a884f579b/go.mod h1:1ZgyZNk91XIllYdOPpwP+9L2RCw6QGSy6alTYF+Z0iU=
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8 h1:LoYXNGAShUG3m/ehNk4iFctuhGX/+R1ZpfJ4/ia80JM=
golang.org/x/exp v0.0.0-20240604190554-fc45aab8b7f8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
Expand Down
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ func main() {
runDebug()
}

logger.Debug().Int("port", config.Port).Msg("running on")
logger.Debug().Msg("rotom server is ready to accept.")

// register main aeLoop event
server.aeLoop.AddFileEvent(server.fd, AE_READABLE, AcceptHandler, nil)
server.aeLoop.AddTimeEvent(AE_NORMAL, 100, ServerCronEvict, nil)
if server.config.AppendOnly {
server.aeLoop.AddTimeEvent(AE_NORMAL, 1000, ServerCronFlush, nil)
}
logger.Debug().Int("port", config.Port).Msg("running on")
logger.Debug().Msg("rotom server is ready to accept.")
server.aeLoop.AeMain()
}
Loading

0 comments on commit 1777572

Please sign in to comment.