Skip to content

Commit 301f2b5

Browse files
committed
feat: support more cmd and add benchmark result
1 parent 3c8c5f6 commit 301f2b5

17 files changed

+228
-17
lines changed

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@
2727

2828
## Design
2929

30-
![data transfer](./static/godis_data_transfer.png)
30+
![data transfer](./static/godis_data_transfer.png)
31+
32+
## Benchmark
33+
34+
[压测结果](benchmark/README.md)

benchmark/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Benchmark
2+
3+
- 2021/12/08 first benchmark [result](benchmark.20211208.csv).

benchmark/benchmark.20211208.csv

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"test","rps","avg_latency_ms","min_latency_ms","p50_latency_ms","p95_latency_ms","p99_latency_ms","max_latency_ms"
2+
"PING_INLINE","77519.38","0.458","0.072","0.383","0.679","1.119","18.479"
3+
"PING_MBULK","83333.34","0.459","0.080","0.335","0.735","0.919","36.287"
4+
"SET","82644.62","0.421","0.064","0.351","0.687","1.007","16.639"
5+
"GET","83333.34","0.412","0.064","0.383","0.679","0.935","2.055"
6+
"INCR","83333.34","0.452","0.080","0.367","0.743","1.103","21.295"
7+
"LPUSH","83333.34","0.396","0.136","0.375","0.583","0.847","1.655"
8+
"RPUSH","84033.61","0.447","0.064","0.343","0.735","1.007","27.631"
9+
"LPOP","84033.61","0.424","0.088","0.375","0.703","0.991","6.367"
10+
"RPOP","82644.62","0.444","0.080","0.327","0.679","0.807","35.647"
11+
"SADD","84033.61","0.441","0.080","0.383","0.711","0.871","12.967"
12+
"HSET","77519.38","0.450","0.112","0.375","0.967","1.231","1.671"
13+
"SPOP","52631.58","0.644","0.096","0.527","1.183","1.951","12.183"
14+
"ZADD","83333.34","0.447","0.072","0.367","0.791","0.967","18.207"
15+
"ZPOPMIN","87719.30","0.397","0.120","0.391","0.543","0.855","1.343"
16+
"LPUSH (needed to benchmark LRANGE)","84745.77","0.448","0.080","0.351","0.687","0.919","30.191"
17+
"LRANGE_100 (first 100 elements)","26109.66","1.014","0.128","0.967","1.319","1.735","10.623"
18+
"LRANGE_300 (first 300 elements)","11210.76","2.361","0.304","2.223","2.887","4.303","32.351"
19+
"LRANGE_500 (first 500 elements)","7309.94","3.551","0.648","3.399","4.319","5.951","39.647"
20+
"LRANGE_600 (first 600 elements)","6180.47","4.167","0.536","4.071","4.983","6.279","20.399"
21+
"MSET (10 keys)","73529.41","0.475","0.080","0.375","1.143","1.727","2.559"

datastruct/list.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ func loadAndCheckList(key string, checkLen bool) (*List, error) {
435435
}
436436

437437
func LPush(key string, values ...string) (ln int, err error) {
438-
info, err := loadKeyInfo(key, KeyTypeList)
438+
list, err := loadAndCheckList(key, false)
439439
if err == ErrNil {
440440
list := newListByLPush(values...)
441441
defaultCache.keys.Set(key, &KeyInfo{
@@ -450,7 +450,6 @@ func LPush(key string, values ...string) (ln int, err error) {
450450
return 0, err
451451
}
452452

453-
list := info.Value.(*List)
454453
for _, value := range values {
455454
list.LPush(value)
456455
}
@@ -459,12 +458,11 @@ func LPush(key string, values ...string) (ln int, err error) {
459458
}
460459

461460
func LPop(key string, count int) (values []string, err error) {
462-
info, err := loadKeyInfo(key, KeyTypeList)
461+
list, err := loadAndCheckList(key, true)
463462
if err != nil {
464463
return nil, err
465464
}
466465

467-
list := info.Value.(*List)
468466
for count > 0 && list.length > 0 {
469467
value, ok := list.LPop()
470468
if !ok {
@@ -479,9 +477,9 @@ func LPop(key string, count int) (values []string, err error) {
479477
}
480478

481479
func RPush(key string, values ...string) (ln int, err error) {
482-
info, err := loadKeyInfo(key, KeyTypeList)
480+
list, err := loadAndCheckList(key, false)
483481
if err == ErrNil {
484-
list := newListByRPush(values...)
482+
list = newListByRPush(values...)
485483
defaultCache.keys.Set(key, &KeyInfo{
486484
Type: KeyTypeList,
487485
Value: list,
@@ -494,7 +492,6 @@ func RPush(key string, values ...string) (ln int, err error) {
494492
return 0, err
495493
}
496494

497-
list := info.Value.(*List)
498495
for _, value := range values {
499496
list.RPush(value)
500497
}

datastruct/set.go

+24-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ func (s *set) sRem(key string) int {
4444
return 0
4545
}
4646

47+
func (s *set) sPop(cnt int) []string {
48+
var (
49+
result []string
50+
ch = s.m.IterBuffered()
51+
)
52+
for i := 0; i < cnt; i++ {
53+
item := <-ch
54+
s.sRem(item.Key)
55+
result = append(result, item.Key)
56+
}
57+
58+
return result
59+
}
60+
4761
func sDiff(s1, s2 *set) *set {
4862
var result = newSet()
4963
s1.m.IterCb(func(key string, _ interface{}) {
@@ -82,7 +96,7 @@ func sUnion(sets ...*set) *set {
8296
*/
8397

8498
func loadAndCheckSet(key string, check bool) (*set, error) {
85-
info, err := loadKeyInfo(key, KeyTypeSortedSet)
99+
info, err := loadKeyInfo(key, KeyTypeSet)
86100
if err != nil {
87101
return nil, err
88102
}
@@ -343,6 +357,15 @@ func SUnionStore(storeKey string, keys ...string) (int, error) {
343357
return result.length, nil
344358
}
345359

360+
func SPop(key string, cnt int) ([]string, error) {
361+
s, err := loadAndCheckSet(key, true)
362+
if err != nil {
363+
return nil, err
364+
}
365+
366+
return s.sPop(cnt), nil
367+
}
368+
346369
/*
347370
* compare with sync map
348371
* just for compare, not using in any data struct

datastruct/sorted_set.go

+44
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,50 @@ func ZRevRange(key, minStr, maxStr string, flag int) ([]string, error) {
786786
return zs.zsl.zRevRange(start, stop, withScores), nil
787787
}
788788

789+
func ZPopMin(key string, cnt int) ([]string, error) {
790+
zs, err := loadAndCheckZSet(key, true)
791+
if err != nil {
792+
return nil, err
793+
}
794+
795+
var result []string
796+
for i := 0; i < cnt; i++ {
797+
node := zs.zsl.findElementByRank(1)
798+
if node == nil {
799+
return result, nil
800+
}
801+
802+
zs.zsl.delete(node.score, node.value, nil)
803+
result = append(result,
804+
node.value,
805+
strconv.FormatFloat(node.score, 'g', -1, 64))
806+
}
807+
808+
return result, nil
809+
}
810+
811+
func ZPopMax(key string, cnt int) ([]string, error) {
812+
zs, err := loadAndCheckZSet(key, true)
813+
if err != nil {
814+
return nil, err
815+
}
816+
817+
var result []string
818+
for i := 0; i < cnt; i++ {
819+
node := zs.zsl.findElementByRank(uint(zs.zsl.length))
820+
if node == nil {
821+
return result, nil
822+
}
823+
824+
zs.zsl.delete(node.score, node.value, nil)
825+
result = append(result,
826+
node.value,
827+
strconv.FormatFloat(node.score, 'g', -1, 64))
828+
}
829+
830+
return result, nil
831+
}
832+
789833
// parse score input and return value and true if is open interval
790834
// example '(5' => 5, true, '3' => 3, false '-inf' => math.Inf(-1), false
791835
func handleFloatScoreStr(str string) (float64, bool, error) {

datastruct/string.go

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ func Set(key string, value string, options ...string) {
1313
defaultCache.keys.Set(key, &KeyInfo{Type: KeyTypeString, Value: value})
1414
}
1515

16+
func MSet(kvs ...string) {
17+
for i := 0; i < len(kvs)-1; i += 2 {
18+
Set(kvs[i], kvs[i+1])
19+
}
20+
}
21+
1622
func Append(key, value string) (ln int, err error) {
1723
v, ok := defaultCache.keys.Get(key)
1824
if !ok {

protocol/decode.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func ReceiveDataAsync(r Reader) *AsyncReceive {
5757
if errors.Is(err, io.EOF) || errors.Is(err, net.ErrClosed) {
5858
return
5959
}
60+
log.Println(err)
6061
continue
6162
}
6263

@@ -71,7 +72,7 @@ func DecodeFromReader(r Reader) (rec Receive, err error) {
7172
rec = make([]string, 0)
7273
b, err := r.ReadBytes('\n')
7374
if err != nil {
74-
log.Println("readBytes err:", err)
75+
//log.Println("readBytes err:", err)
7576
return nil, err
7677
}
7778

@@ -121,6 +122,9 @@ func decodeSingleLine(line []byte) (str string, length int, desc byte, err error
121122
case DescriptionSimpleStrings, DescriptionErrors, DescriptionIntegers:
122123
str = string(line[1 : len(line)-CRLFLen])
123124
default:
125+
if string(line) == "PING\r\n" {
126+
return "PING", 0, DescriptionSimpleStrings, nil
127+
}
124128
return "", 0, 0, fmt.Errorf("unsupport protocol: %s", string(line))
125129
}
126130

redis/command.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ func NewCommandFromReceive(rec protocol.Receive) *Command {
3434
c.Values = append(c.Values, e)
3535
}
3636

37-
log.Println("command: ", c.Command)
3837
return c
3938
}
4039

@@ -54,15 +53,21 @@ func (c *Command) ExecuteWithContext(ctx context.Context) chan *protocol.Respons
5453
}
5554

5655
go func() {
57-
defer close(rspChan)
56+
defer func() {
57+
if recover() != nil {
58+
log.Println(c.Command, c.Values)
59+
}
60+
}()
5861
f, ok := implementedCommands[c.Command]
5962
if !ok {
63+
log.Println(c.Command, c.Values)
6064
c.putRspToChan(rspChan, protocol.NewResponseWithError(ErrUnknownCommand))
6165
return
6266
}
6367

6468
rsp, err := f(c)
6569
if err != nil {
70+
log.Println(c.Command)
6671
c.putRspToChan(rspChan, protocol.NewResponseWithError(err))
6772
return
6873
}

redis/keys.go

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package redis
22

33
import (
4-
"time"
5-
64
"github.com/yusank/godis/datastruct"
75
"github.com/yusank/godis/protocol"
86
)
@@ -59,7 +57,6 @@ func keyType(c *Command) (*protocol.Response, error) {
5957
}
6058

6159
func ping(c *Command) (*protocol.Response, error) {
62-
time.Sleep(2 * time.Second)
6360
return protocol.NewResponseWithSimpleString(RespPong), nil
6461
}
6562

redis/set.cmd.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

redis/set.go

+32
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package redis
22

33
import (
4+
"strconv"
5+
46
"github.com/yusank/godis/datastruct"
57
"github.com/yusank/godis/protocol"
68
)
@@ -215,3 +217,33 @@ func sRem(c *Command) (*protocol.Response, error) {
215217

216218
return protocol.NewResponseWithInteger(int64(cnt)), nil
217219
}
220+
221+
// SPop .
222+
func SPop(c *Command) (*protocol.Response, error) {
223+
if len(c.Values) < 1 {
224+
return nil, ErrCommandArgsNotEnough
225+
}
226+
227+
var (
228+
key = c.Values[0]
229+
cnt int
230+
err error
231+
)
232+
233+
if len(c.Values) > 1 {
234+
cnt, err = strconv.Atoi(c.Values[1])
235+
if err != nil {
236+
return nil, datastruct.ErrNotInteger
237+
}
238+
}
239+
240+
values, err := datastruct.SPop(key, cnt)
241+
if err == datastruct.ErrNil {
242+
return protocol.NewResponseWithEmptyArray(), nil
243+
}
244+
if err != nil {
245+
return nil, err
246+
}
247+
248+
return protocol.NewResponse(true).AppendBulkStrings(values...), nil
249+
}

redis/sorted_set.cmd.go

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

redis/sorted_set.go

+61
Original file line numberDiff line numberDiff line change
@@ -249,5 +249,66 @@ func zRevRange(c *Command) (*protocol.Response, error) {
249249
}
250250

251251
return protocol.NewResponse(true).AppendBulkStrings(values...), nil
252+
}
253+
254+
// zPopMin .
255+
func zPopMin(c *Command) (*protocol.Response, error) {
256+
if len(c.Values) < 1 {
257+
return nil, ErrCommandArgsNotEnough
258+
}
252259

260+
var (
261+
key = c.Values[0]
262+
cnt = 1
263+
err error
264+
)
265+
266+
if len(c.Values) > 1 {
267+
cnt, err = strconv.Atoi(c.Values[1])
268+
if err != nil {
269+
return nil, datastruct.ErrNotInteger
270+
}
271+
}
272+
273+
values, err := datastruct.ZPopMin(key, cnt)
274+
if err == datastruct.ErrNil || len(values) == 0 {
275+
return protocol.NewResponseWithEmptyArray(), nil
276+
}
277+
278+
if err != nil {
279+
return nil, err
280+
}
281+
282+
return protocol.NewResponse(true).AppendBulkStrings(values...), nil
283+
}
284+
285+
// zPopMax .
286+
func zPopMix(c *Command) (*protocol.Response, error) {
287+
if len(c.Values) < 1 {
288+
return nil, ErrCommandArgsNotEnough
289+
}
290+
291+
var (
292+
key = c.Values[0]
293+
cnt = 1
294+
err error
295+
)
296+
297+
if len(c.Values) > 1 {
298+
cnt, err = strconv.Atoi(c.Values[1])
299+
if err != nil {
300+
return nil, datastruct.ErrNotInteger
301+
}
302+
}
303+
304+
values, err := datastruct.ZPopMax(key, cnt)
305+
if err == datastruct.ErrNil || len(values) == 0 {
306+
return protocol.NewResponseWithEmptyArray(), nil
307+
}
308+
309+
if err != nil {
310+
return nil, err
311+
}
312+
313+
return protocol.NewResponse(true).AppendBulkStrings(values...), nil
253314
}

0 commit comments

Comments
 (0)