Skip to content

Commit 310e40d

Browse files
committed
support opCodeFunction 245
1 parent eb108f4 commit 310e40d

10 files changed

Lines changed: 280 additions & 31 deletions

File tree

README.md

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,29 @@ PATH environment.
5050
use `rdb` command in terminal, you can see it's manual
5151

5252
```
53+
$ rdb
5354
This is a tool to parse Redis' RDB files
5455
Options:
5556
-c command, including: json/memory/aof/bigkey/prefix/flamegraph
56-
-o output file path, if there is no `-o` option, output to stdout
57+
-o output file path
5758
-n number of result, using in command: bigkey/prefix
5859
-port listen port for flame graph web service
5960
-sep separator for flamegraph, rdb will separate key by it, default value is ":".
60-
supporting multi separators: -sep sep1 -sep sep2
61+
supporting multi separators: -sep sep1 -sep sep2
6162
-regex using regex expression filter keys
6263
-expire filter keys by its expiration time
63-
1. '>1751731200' '>now' get keys with expiration time greater than given time
64-
2. '<1751731200' '<now' get keys with expiration time less than given time
65-
3. '1751731200~1751817600' '1751731200~now' get keys with expiration time in range
66-
4. 'noexpire' get keys without expiration time
67-
5. 'anyexpire' get all keys with expiration time
68-
-size filter keys by size; units supported: B/KB/MB/GB. Use the range expression 'min~max' (e.g., 1KB~1MB, 0~10MB, 1024~20KB); supports 'inf' to denote infinity(e.g., 1MB~inf)
64+
1. '1751731200~1751817600' get keys with expiration time in range [1751731200, 1751817600]
65+
2. '1751731200~now' 'now~1751731200' magic variable 'now' represents the current timestamp
66+
3. '1751731200~inf' 'now~inf' magic variable 'inf' represents the Infinity
67+
4. 'noexpire' get keys without expiration time
68+
5. 'anyexpire' get all keys with expiration time
69+
-size filter keys by size, supports B/KB/MB/GB/TB/PB/EB
70+
1. '1KB~1MB' get keys with size in range [1KB, 1MB]
71+
2. '10MB~inf' magic variable 'inf' represents the Infinity
72+
3. '1024~10KB' get keys with size in range [0Bytes, 10KB]
73+
-concurrent The number of concurrent json converters. 4 by default.
74+
-show-global-meta Show global meta likes redis-verion/ctime/functions
6975
-no-expired filter expired keys(deprecated, please use 'expire' option)
70-
-concurrent The number of concurrent json converters. (CpuNum -1 by default, reserve a core for decoder)
7176
7277
Examples:
7378
parameters between '[' and ']' is optional
@@ -79,7 +84,7 @@ parameters between '[' and ']' is optional
7984
rdb -c aof -o dump.aof dump.rdb
8085
4. get largest keys
8186
rdb -c bigkey [-o dump.aof] [-n 10] dump.rdb
82-
5. get number and size by prefix
87+
5. get number and memory size by prefix
8388
rdb -c prefix [-n 10] [-max-depth 3] [-o prefix-report.csv] dump.rdb
8489
6. draw flamegraph
8590
rdb -c flamegraph [-port 16379] [-sep :] dump.rdb
@@ -120,6 +125,25 @@ You can use `-concurrent` to change the number of concurrent convertes. The defa
120125
rdb -c json -o intset_16.json -concurrent 8 cases/intset_16.rdb
121126
```
122127

128+
You can use `-show-global-meta` to get metadata (redis-ver,ctime,used-mem, etc.) and functions in rdb file.
129+
130+
```bash
131+
rdb -c json -o function.json -show-global-meta cases/function.rdb
132+
```
133+
134+
Examples:
135+
136+
```json
137+
[
138+
{"db":0,"key":"redis-ver","size":0,"type":"aux","encoding":"","value":"7.2.5"},
139+
{"db":0,"key":"redis-bits","size":0,"type":"aux","encoding":"","value":"64"},
140+
{"db":0,"key":"ctime","size":0,"type":"aux","encoding":"","value":"1767107423"},
141+
{"db":0,"key":"used-mem","size":0,"type":"aux","encoding":"","value":"1269264"},
142+
{"db":0,"key":"aof-base","size":0,"type":"aux","encoding":"","value":"0"},
143+
{"db":0,"key":"functions","size":0,"type":"functions","encoding":"functions","functionsLua":"#!lua name=mylib\nredis.register_function('myfunc', function(keys, args) return 'hello' end)"}
144+
]
145+
```
146+
123147
<details>
124148
<summary>Json Fromat Detail</summary>
125149

@@ -270,6 +294,66 @@ rdb -c json -o intset_16.json -concurrent 8 cases/intset_16.rdb
270294
}
271295
```
272296

297+
## aux
298+
299+
```json
300+
[
301+
{
302+
"db": 0,
303+
"key": "redis-ver",
304+
"size": 0,
305+
"type": "aux",
306+
"encoding": "",
307+
"value": "7.2.5"
308+
},
309+
{
310+
"db": 0,
311+
"key": "redis-bits",
312+
"size": 0,
313+
"type": "aux",
314+
"encoding": "",
315+
"value": "64"
316+
},
317+
{
318+
"db": 0,
319+
"key": "ctime",
320+
"size": 0,
321+
"type": "aux",
322+
"encoding": "",
323+
"value": "1767107423"
324+
},
325+
{
326+
"db": 0,
327+
"key": "used-mem",
328+
"size": 0,
329+
"type": "aux",
330+
"encoding": "",
331+
"value": "1269264"
332+
},
333+
{
334+
"db": 0,
335+
"key": "aof-base",
336+
"size": 0,
337+
"type": "aux",
338+
"encoding": "",
339+
"value": "0"
340+
}
341+
]
342+
```
343+
344+
## functions
345+
346+
```json
347+
{
348+
"db": 0,
349+
"key": "functions",
350+
"size": 0,
351+
"type": "functions",
352+
"encoding": "functions",
353+
"functionsLua": "#!lua name=mylib\nredis.register_function('myfunc', function(keys, args) return 'hello' end)"
354+
}
355+
```
356+
273357
</details>
274358

275359
# Generate Memory Report

README_CN.md

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,26 @@ go install github.com/hdt3213/rdb@latest
3939
$ rdb
4040
This is a tool to parse Redis' RDB files
4141
Options:
42-
-c command, including: json/memory/aof/bigkey/flamegraph
42+
-c command, including: json/memory/aof/bigkey/prefix/flamegraph
4343
-o output file path
44-
-n number of result, using in
44+
-n number of result, using in command: bigkey/prefix
4545
-port listen port for flame graph web service
4646
-sep separator for flamegraph, rdb will separate key by it, default value is ":".
47-
supporting multi separators: -sep sep1 -sep sep2
47+
supporting multi separators: -sep sep1 -sep sep2
4848
-regex using regex expression filter keys
4949
-expire filter keys by its expiration time
50-
1. '>1751731200' '>now' get keys with expiration time greater than given time
51-
2. '<1751731200' '<now' get keys with expiration time less than given time
52-
3. '1751731200~1751817600' '1751731200~now' get keys with expiration time in range
53-
4. 'noexpire' get keys without expiration time
54-
5. 'anyexpire' get all keys with expiration time
55-
-size 根据大小过滤键值对;单位支持 B/KB/MB/GB/TB。范围表达式格式为“最小值~最大值”(例如 1KB~1MB, 0~10MB, 1024~20KB),支持使用“inf”表示无穷大(例如 1MB~inf)。
50+
1. '1751731200~1751817600' get keys with expiration time in range [1751731200, 1751817600]
51+
2. '1751731200~now' 'now~1751731200' magic variable 'now' represents the current timestamp
52+
3. '1751731200~inf' 'now~inf' magic variable 'inf' represents the Infinity
53+
4. 'noexpire' get keys without expiration time
54+
5. 'anyexpire' get all keys with expiration time
55+
-size filter keys by size, supports B/KB/MB/GB/TB/PB/EB
56+
1. '1KB~1MB' get keys with size in range [1KB, 1MB]
57+
2. '10MB~inf' magic variable 'inf' represents the Infinity
58+
3. '1024~10KB' get keys with size in range [0Bytes, 10KB]
59+
-concurrent The number of concurrent json converters. 4 by default.
60+
-show-global-meta Show global meta likes redis-verion/ctime/functions
5661
-no-expired filter expired keys(deprecated, please use 'expire' option)
57-
-concurrent The number of concurrent json converters. (Cpu number by default)
5862
5963
Examples:
6064
parameters between '[' and ']' is optional
@@ -66,7 +70,9 @@ parameters between '[' and ']' is optional
6670
rdb -c aof -o dump.aof dump.rdb
6771
4. get largest keys
6872
rdb -c bigkey [-o dump.aof] [-n 10] dump.rdb
69-
5. draw flamegraph
73+
5. get number and memory size by prefix
74+
rdb -c prefix [-n 10] [-max-depth 3] [-o prefix-report.csv] dump.rdb
75+
6. draw flamegraph
7076
rdb -c flamegraph [-port 16379] [-sep :] dump.rdb
7177
```
7278

@@ -105,6 +111,24 @@ rdb -c json -o intset_16.json cases/intset_16.rdb
105111
rdb -c json -o intset_16.json -concurrent 8 cases/intset_16.rdb
106112
```
107113

114+
`-show-global-meta` 选项可以解析 RDB 文件中的元信息 (redis-ver、ctime、used-mem 等) 以及函数定义。
115+
116+
```bash
117+
rdb -c json -o function.json -show-global-meta cases/function.rdb
118+
```
119+
120+
示例:
121+
```json
122+
[
123+
{"db":0,"key":"redis-ver","size":0,"type":"aux","encoding":"","value":"7.2.5"},
124+
{"db":0,"key":"redis-bits","size":0,"type":"aux","encoding":"","value":"64"},
125+
{"db":0,"key":"ctime","size":0,"type":"aux","encoding":"","value":"1767107423"},
126+
{"db":0,"key":"used-mem","size":0,"type":"aux","encoding":"","value":"1269264"},
127+
{"db":0,"key":"aof-base","size":0,"type":"aux","encoding":"","value":"0"},
128+
{"db":0,"key":"functions","size":0,"type":"functions","encoding":"functions","functionsLua":"#!lua name=mylib\nredis.register_function('myfunc', function(keys, args) return 'hello' end)"}
129+
]
130+
```
131+
108132
<details>
109133
<summary>Json 格式</summary>
110134

cases/function.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{"db":0,"key":"redis-ver","size":0,"type":"aux","encoding":"","value":"7.2.5"},
3+
{"db":0,"key":"redis-bits","size":0,"type":"aux","encoding":"","value":"64"},
4+
{"db":0,"key":"ctime","size":0,"type":"aux","encoding":"","value":"1767107423"},
5+
{"db":0,"key":"used-mem","size":0,"type":"aux","encoding":"","value":"1269264"},
6+
{"db":0,"key":"aof-base","size":0,"type":"aux","encoding":"","value":"0"},
7+
{"db":0,"key":"functions","size":0,"type":"functions","encoding":"functions","functionsLua":"#!lua name=mylib\nredis.register_function('myfunc', function(keys, args) return 'hello' end)"}
8+
]

cases/function.rdb

182 Bytes
Binary file not shown.

cmd.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@ Options:
1717
-n number of result, using in command: bigkey/prefix
1818
-port listen port for flame graph web service
1919
-sep separator for flamegraph, rdb will separate key by it, default value is ":".
20-
supporting multi separators: -sep sep1 -sep sep2
20+
supporting multi separators: -sep sep1 -sep sep2
2121
-regex using regex expression filter keys
2222
-expire filter keys by its expiration time
23-
1. '1751731200~1751817600' get keys with expiration time in range [1751731200, 1751817600]
24-
2. '1751731200~now' 'now~1751731200' magic variable 'now' represents the current timestamp
25-
3. '1751731200~inf' 'now~inf' magic variable 'inf' represents the Infinity
26-
4. 'noexpire' get keys without expiration time
27-
5. 'anyexpire' get all keys with expiration time
23+
1. '1751731200~1751817600' get keys with expiration time in range [1751731200, 1751817600]
24+
2. '1751731200~now' 'now~1751731200' magic variable 'now' represents the current timestamp
25+
3. '1751731200~inf' 'now~inf' magic variable 'inf' represents the Infinity
26+
4. 'noexpire' get keys without expiration time
27+
5. 'anyexpire' get all keys with expiration time
2828
-size filter keys by size, supports B/KB/MB/GB/TB/PB/EB
29-
1. '1KB~1MB' get keys with size in range [1KB, 1MB]
30-
2. '10MB~inf' magic variable 'inf' represents the Infinity
31-
3. '1024~10KB' get keys with size in range [0Bytes, 10KB]
32-
-no-expired filter expired keys(deprecated, please use 'expire' option)
29+
1. '1KB~1MB' get keys with size in range [1KB, 1MB]
30+
2. '10MB~inf' magic variable 'inf' represents the Infinity
31+
3. '1024~10KB' get keys with size in range [0Bytes, 10KB]
3332
-concurrent The number of concurrent json converters. 4 by default.
33+
-show-global-meta Show global meta likes redis-verion/ctime/functions
34+
-no-expired filter expired keys(deprecated, please use 'expire' option)
3435
3536
Examples:
3637
parameters between '[' and ']' is optional
@@ -72,6 +73,7 @@ func main() {
7273
var sizeExpr string
7374
var maxDepth int
7475
var concurrent int
76+
var showGlobalMeta bool
7577
var err error
7678
flagSet.StringVar(&cmd, "c", "", "command for rdb: json")
7779
flagSet.StringVar(&output, "o", "", "output file path")
@@ -84,6 +86,7 @@ func main() {
8486
flagSet.StringVar(&expirationExpr, "expire", "", "expiration filter expression")
8587
flagSet.StringVar(&sizeExpr, "size", "", "size filter expression")
8688
flagSet.BoolVar(&noExpired, "no-expired", false, "filter expired keys(deprecated, please use expire)")
89+
flagSet.BoolVar(&showGlobalMeta, "show-global-meta", false, "Show global meta likes redis-verion/ctime/functions")
8790
_ = flagSet.Parse(os.Args[1:]) // ExitOnError
8891
src := flagSet.Arg(0)
8992

@@ -112,6 +115,9 @@ func main() {
112115
if sizeExpr != "" {
113116
options = append(options, helper.WithSizeOption(sizeExpr))
114117
}
118+
if showGlobalMeta {
119+
options = append(options, helper.WithGlobalMeta())
120+
}
115121

116122
var outputFile *os.File
117123
if output == "" {

core/decoder.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const (
5454
)
5555

5656
const (
57+
opCodeFunction = 245
5758
opCodeModuleAux = 247 /* Module auxiliary data. */
5859
opCodeIdle = 248 /* LRU idle time. */
5960
opCodeFreq = 249 /* LFU frequency. */
@@ -419,6 +420,7 @@ func (dec *Decoder) parse(cb func(object model.RedisObject) bool) error {
419420
obj := &model.AuxObject{
420421
BaseObject: &model.BaseObject{},
421422
}
423+
obj.Type = model.AuxType
422424
obj.Key = unsafeBytes2Str(key)
423425
obj.Value = unsafeBytes2Str(value)
424426
tbc := cb(obj)
@@ -445,6 +447,25 @@ func (dec *Decoder) parse(cb func(object model.RedisObject) bool) error {
445447
return err
446448
}
447449
continue
450+
} else if b == opCodeFunction {
451+
functionsLua, err := dec.readString()
452+
if err != nil {
453+
return err
454+
}
455+
if dec.withSpecialOpCode {
456+
obj := &model.FunctionsObject{
457+
BaseObject: &model.BaseObject{},
458+
}
459+
obj.Key = "functions"
460+
obj.Type = model.FunctionsType
461+
obj.Encoding = "functions"
462+
obj.FunctionsLua = unsafeBytes2Str(functionsLua)
463+
tbc := cb(obj)
464+
if !tbc {
465+
break
466+
}
467+
}
468+
continue
448469
}
449470
key, err := dec.readString()
450471
if err != nil {

core/functions_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package core
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/hdt3213/rdb/model"
8+
)
9+
10+
11+
12+
func TestParseFunctions(t *testing.T) {
13+
rdbFile, err := os.Open("../cases/function.rdb")
14+
if err != nil {
15+
panic(err)
16+
}
17+
defer func() {
18+
_ = rdbFile.Close()
19+
}()
20+
21+
dec := NewDecoder(rdbFile).WithSpecialOpCode()
22+
var functionLua string
23+
dec.Parse(func(object model.RedisObject) bool {
24+
if object.GetType() == model.FunctionsType {
25+
functionObj := object.(*model.FunctionsObject)
26+
functionLua = functionObj.FunctionsLua
27+
return false
28+
}
29+
return true
30+
})
31+
expect := "#!lua name=mylib\nredis.register_function('myfunc', function(keys, args) return 'hello' end)"
32+
if functionLua != expect {
33+
t.Error("function lua is not equals")
34+
}
35+
}

0 commit comments

Comments
 (0)