diff --git a/tool/kratos-gen-mc/README.md b/tool/kratos-gen-mc/README.md index f912f7198..0bc8c89ff 100644 --- a/tool/kratos-gen-mc/README.md +++ b/tool/kratos-gen-mc/README.md @@ -40,5 +40,6 @@ mc Add方法需要用注解 -type=only_add单独指定 | batch | | get(限多key模板) | 批量获取数据 每组大小 | - | 100 | | max_group | | get(限多key模板) | 批量获取数据 最大组数量 | - | 10 | | batch_err | break | get(限多key模板) | 批量获取数据回源错误的时候 降级继续请求(continue)还是直接返回(break) | break 或 continue | continue | -| struct_name | Dao | 全部 | 用户自定义Dao结构体名称 | | MemcacheDao | - +| struct_name | dao | 全部 | 用户自定义Dao结构体名称 | | MemcacheDao | +|check_null_code||add/set|(和null_expire配套使用)判断是否是空缓存的代码 用于为空缓存独立设定过期时间||$.ID==-1 或者 $=="-1"等| +|null_expire|300(5分钟)|add/set|(和check_null_code配套使用)空缓存的过期时间||d.nullExpire| \ No newline at end of file diff --git a/tool/kratos-gen-mc/header_template.go b/tool/kratos-gen-mc/header_template.go index 86a1699fc..ad53e8a17 100644 --- a/tool/kratos-gen-mc/header_template.go +++ b/tool/kratos-gen-mc/header_template.go @@ -25,7 +25,5 @@ NEWLINE {{.ImportPackage}} ) -var ( - _ _mc -) +var _ _mc ` diff --git a/tool/kratos-gen-mc/main.go b/tool/kratos-gen-mc/main.go index 86759cd0a..c740d516c 100644 --- a/tool/kratos-gen-mc/main.go +++ b/tool/kratos-gen-mc/main.go @@ -9,26 +9,29 @@ import ( "os" "path/filepath" "regexp" + "runtime" "strconv" "strings" "text/template" - "github.com/bilibili/kratos/tool/pkg" + common "github.com/bilibili/kratos/tool/pkg" ) var ( - encode = flag.String("encode", "", "encode type: json/pb/raw/gob/gzip") - mcType = flag.String("type", "", "type: get/set/del/replace/only_add") - key = flag.String("key", "", "key name method") - expire = flag.String("expire", "", "expire time code") - structName = flag.String("struct_name", "Dao", "struct name") - batchSize = flag.Int("batch", 0, "batch size") - batchErr = flag.String("batch_err", "break", "batch err to contine or break") - maxGroup = flag.Int("max_group", 0, "max group size") + encode = flag.String("encode", "", "encode type: json/pb/raw/gob/gzip") + mcType = flag.String("type", "", "type: get/set/del/replace/only_add") + key = flag.String("key", "", "key name method") + expire = flag.String("expire", "", "expire time code") + structName = flag.String("struct_name", "dao", "struct name") + batchSize = flag.Int("batch", 0, "batch size") + batchErr = flag.String("batch_err", "break", "batch err to contine or break") + maxGroup = flag.Int("max_group", 0, "max group size") + checkNullCode = flag.String("check_null_code", "", "check null code") + nullExpire = flag.String("null_expire", "", "null cache expire time code") mcValidTypes = []string{"set", "replace", "del", "get", "only_add"} mcValidPrefix = []string{"set", "replace", "del", "get", "cache", "add"} - optionNamesMap = map[string]bool{"batch": true, "max_group": true, "encode": true, "type": true, "key": true, "expire": true, "batch_err": true, "struct_name": true} + optionNamesMap = map[string]bool{"batch": true, "max_group": true, "encode": true, "type": true, "key": true, "expire": true, "batch_err": true, "struct_name": true, "check_null_code": true, "null_expire": true} simpleTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "bool", "string", "[]byte"} lenTypes = []string{"[]", "map"} ) @@ -51,6 +54,9 @@ func resetFlag() { *batchSize = 0 *maxGroup = 0 *batchErr = "break" + *checkNullCode = "" + *nullExpire = "" + *structName = "dao" } // options options @@ -88,17 +94,20 @@ type options struct { LenType bool PointType bool StructName string + CheckNullCode string + ExpireNullCode string + EnableNullCode bool } func getOptions(opt *options, comment string) { os.Args = []string{os.Args[0]} if regexp.MustCompile(`\s+//\s*mc:.+`).Match([]byte(comment)) { - args := strings.Split(pkg.RegexpReplace(`//\s*mc:(?P.+)`, comment, "$arg"), " ") + args := strings.Split(common.RegexpReplace(`//\s*mc:(?P.+)`, comment, "$arg"), " ") for _, arg := range args { arg = strings.TrimSpace(arg) if arg != "" { // validate option name - argName := pkg.RegexpReplace(`-(?P[\w_-]+)=.+`, arg, "$name") + argName := common.RegexpReplace(`-(?P[\w_-]+)=.+`, arg, "$name") if !optionNamesMap[argName] { log.Fatalf("选项:%s 不存在 请检查拼写\n", argName) } @@ -122,9 +131,16 @@ func getOptions(opt *options, comment string) { opt.GroupSize = *batchSize opt.MaxGroup = *maxGroup opt.StructName = *structName + opt.CheckNullCode = *checkNullCode + if *nullExpire != "" { + opt.ExpireNullCode = *nullExpire + } + if opt.CheckNullCode != "" { + opt.EnableNullCode = true + } } -func getTypeFromPrefix(opt *options, params []*ast.Field, s *pkg.Source) { +func getTypeFromPrefix(opt *options, params []*ast.Field, s *common.Source) { if opt.MCType == "" { for _, t := range mcValidPrefix { if strings.HasPrefix(strings.ToLower(opt.name), t) { @@ -160,7 +176,7 @@ func getTypeFromPrefix(opt *options, params []*ast.Field, s *pkg.Source) { } } -func processList(s *pkg.Source, list *ast.Field) (opt options) { +func processList(s *common.Source, list *ast.Field) (opt options) { src := s.Src fset := s.Fset lines := strings.Split(src, "\n") @@ -168,11 +184,12 @@ func processList(s *pkg.Source, list *ast.Field) (opt options) { opt.name = list.Names[0].Name opt.KeyMethod = "key" + opt.name opt.ExpireCode = "d.mc" + opt.name + "Expire" + opt.ExpireNullCode = "300" // 默认5分钟 // get comment line := fset.Position(list.Pos()).Line - 3 if len(lines)-1 >= line { comment := lines[line] - opt.Comment = pkg.RegexpReplace(`\s+//(?P.+)`, comment, "$name") + opt.Comment = common.RegexpReplace(`\s+//(?P.+)`, comment, "$name") opt.Comment = strings.TrimSpace(opt.Comment) } // get options @@ -235,7 +252,7 @@ func processList(s *pkg.Source, list *ast.Field) (opt options) { return } -func getKeyValueType(opt *options, params, results []*ast.Field, s *pkg.Source) { +func getKeyValueType(opt *options, params, results []*ast.Field, s *common.Source) { // check if s.ExprString(results[len(results)-1].Type) != "error" { log.Fatalln("最后返回值参数需为error") @@ -352,7 +369,7 @@ func getKeyValueType(opt *options, params, results []*ast.Field, s *pkg.Source) } } -func parse(s *pkg.Source) (opts []*options) { +func parse(s *common.Source) (opts []*options) { c := s.F.Scope.Lookup(_interfaceName) if (c == nil) || (c.Kind != ast.Typ) { log.Fatalln("无法找到缓存声明") @@ -476,6 +493,9 @@ func genBody(opts []*options) (res string) { src = strings.Replace(src, "VALUE", option.ValueType, -1) src = strings.Replace(src, "GROUPSIZE", strconv.Itoa(option.GroupSize), -1) src = strings.Replace(src, "MAXGROUP", strconv.Itoa(option.MaxGroup), -1) + if option.EnableNullCode { + option.CheckNullCode = strings.Replace(option.CheckNullCode, "$", "val", -1) + } t := template.Must(template.New("cache").Parse(src)) var buffer bytes.Buffer err := t.Execute(&buffer, option) @@ -494,13 +514,15 @@ func main() { log.SetFlags(0) defer func() { if err := recover(); err != nil { - log.Fatalf("程序解析失败, err: %+v", err) + buf := make([]byte, 64*1024) + buf = buf[:runtime.Stack(buf, false)] + log.Fatalf("程序解析失败, err: %+v stack: %s 请企业微信联系 @wangxu01", err, buf) } }() - options := parse(pkg.NewSource(pkg.SourceText())) + options := parse(common.NewSource(common.SourceText())) header := genHeader(options) body := genBody(options) - code := pkg.FormatCode(header + "\n" + body) + code := common.FormatCode(header + "\n" + body) // Write to file. dir := filepath.Dir(".") outputName := filepath.Join(dir, "mc.cache.go") diff --git a/tool/kratos-gen-mc/multi_template.go b/tool/kratos-gen-mc/multi_template.go index 214adad76..db02358cc 100644 --- a/tool/kratos-gen-mc/multi_template.go +++ b/tool/kratos-gen-mc/multi_template.go @@ -167,6 +167,11 @@ func (d *{{.StructName}}) NAME(c context.Context, values map[KEY]VALUE {{.ExtraA {{else}} item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}} {{end}} + {{if .EnableNullCode}} + if {{.CheckNullCode}} { + item.Expiration = {{.ExpireNullCode}} + } + {{end}} if err = d.mc.Set(c, item); err != nil { log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key)) return diff --git a/tool/kratos-gen-mc/none_template.go b/tool/kratos-gen-mc/none_template.go index fb7a28353..65ec1de63 100644 --- a/tool/kratos-gen-mc/none_template.go +++ b/tool/kratos-gen-mc/none_template.go @@ -72,6 +72,11 @@ func (d *{{.StructName}}) NAME(c context.Context, val VALUE) (err error) { {{else}} item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}} {{end}} + {{if .EnableNullCode}} + if {{.CheckNullCode}} { + item.Expiration = {{.ExpireNullCode}} + } + {{end}} if err = d.mc.Set(c, item); err != nil { log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key)) return diff --git a/tool/kratos-gen-mc/single_template.go b/tool/kratos-gen-mc/single_template.go index b7a111cc4..850a4ba12 100644 --- a/tool/kratos-gen-mc/single_template.go +++ b/tool/kratos-gen-mc/single_template.go @@ -71,6 +71,11 @@ func (d *{{.StructName}}) NAME(c context.Context, id KEY, val VALUE {{.ExtraArgs {{else}} item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}} {{end}} + {{if .EnableNullCode}} + if {{.CheckNullCode}} { + item.Expiration = {{.ExpireNullCode}} + } + {{end}} if err = d.mc.Set(c, item); err != nil { log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key)) return