Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

45
app/tool/cache/memcached/BUILD vendored Normal file
View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "memcached",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"header_template.go",
"main.go",
"multi_template.go",
"none_template.go",
"single_template.go",
],
importpath = "go-common/app/tool/cache/memcached",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//app/tool/cache/common:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/tool/cache/memcached/testdata:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

11
app/tool/cache/memcached/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,11 @@
### tools/cache/memcached
##### Version 1.1.1
1. 修复返回值为string []byte无法正常生成的问题
##### Version 1.1.0
1. 支持分批获取
##### Version 1.0.0
1. 添加基础模块与测试

24
app/tool/cache/memcached/README.md vendored Normal file
View File

@@ -0,0 +1,24 @@
#### tools/cache/mc
> mc缓存代码生成
##### 项目简介
自动生成memcached缓存代码 和缓存回源工具配合使用 体验更佳
支持以下功能:
- 常用mc命令(get/set/add/replace/delete)
- 多种数据存储格式(json/pb/raw/gob/gzip)
- 常用值类型自动转换(int/bool/float...)
- 自定义缓存名称和过期时间
- 记录pkg/error错误栈
- 记录日志trace id
- prometheus错误监控
- 自定义参数个数
- 自定义注释
##### 使用方式:
代码生成: 使用go generate方式生成 具体参数见[文档](http://info.bilibili.co/pages/viewpage.action?pageId=8471941)

View File

@@ -0,0 +1,30 @@
package main
var _headerTemplate = `
// Code generated by $GOPATH/src/go-common/app/tool/cache/mc. DO NOT EDIT.
NEWLINE
/*
Package {{.PkgName}} is a generated mc cache package.
It is generated from:
ARGS
*/
NEWLINE
package {{.PkgName}}
import (
"context"
"fmt"
{{if .UseStrConv}}"strconv"{{end}}
{{if .EnableBatch }}"sync"{{end}}
NEWLINE
"go-common/library/stat/prom"
{{if .UseMemcached }}"go-common/library/cache/memcache"{{end}}
{{if .EnableBatch }}"go-common/library/sync/errgroup"{{end}}
"go-common/library/log"
{{.ImportPackage}}
)
var _ _mc
`

517
app/tool/cache/memcached/main.go vendored Normal file
View File

@@ -0,0 +1,517 @@
package main
import (
"bytes"
"flag"
"go/ast"
"io/ioutil"
"log"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"text/template"
"go-common/app/tool/cache/common"
)
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")
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")
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}
simpleTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "bool", "string", "[]byte"}
lenTypes = []string{"[]", "map"}
)
const (
_interfaceName = "_mc"
_multiTpl = 1
_singleTpl = 2
_noneTpl = 3
_typeGet = "get"
_typeSet = "set"
_typeDel = "del"
_typeReplace = "replace"
_typeAdd = "only_add"
)
func resetFlag() {
*encode = ""
*mcType = ""
*batchSize = 0
*maxGroup = 0
*batchErr = "break"
}
// options options
type options struct {
name string
keyType string
ValueType string
template int
SimpleValue bool
// int float 类型
GetSimpleValue bool
// string, []byte类型
GetDirectValue bool
ConvertValue2Bytes string
ConvertBytes2Value string
GoValue bool
ImportPackage string
importPackages []string
Args string
PkgName string
ExtraArgsType string
ExtraArgs string
MCType string
KeyMethod string
ExpireCode string
Encode string
UseMemcached bool
InitValue bool
OriginValueType string
UseStrConv bool
Comment string
GroupSize int
MaxGroup int
EnableBatch bool
BatchErrBreak bool
LenType bool
PointType bool
}
func parse(s *common.Source) (opts []*options) {
f := s.F
fset := s.Fset
src := s.Src
c := f.Scope.Lookup(_interfaceName)
if (c == nil) || (c.Kind != ast.Typ) {
log.Fatalln("无法找到缓存声明")
}
lines := strings.Split(src, "\n")
lists := c.Decl.(*ast.TypeSpec).Type.(*ast.InterfaceType).Methods.List
for _, list := range lists {
opt := options{Args: s.GetDef(_interfaceName), UseMemcached: true, importPackages: s.Packages(list)}
opt.name = list.Names[0].Name
opt.KeyMethod = "key" + opt.name
opt.ExpireCode = "d.mc" + opt.name + "Expire"
// get comment
line := fset.Position(list.Pos()).Line - 3
if len(lines)-1 >= line {
comment := lines[line]
opt.Comment = common.RegexpReplace(`\s+//(?P<name>.+)`, comment, "$name")
opt.Comment = strings.TrimSpace(opt.Comment)
}
// get options
line = fset.Position(list.Pos()).Line - 2
comment := lines[line]
os.Args = []string{os.Args[0]}
if regexp.MustCompile(`\s+//\s*mc:.+`).Match([]byte(comment)) {
args := strings.Split(common.RegexpReplace(`//\s*mc:(?P<arg>.+)`, comment, "$arg"), " ")
for _, arg := range args {
arg = strings.TrimSpace(arg)
if arg != "" {
// validate option name
argName := common.RegexpReplace(`-(?P<name>[\w_-]+)=.+`, arg, "$name")
if !optionNamesMap[argName] {
log.Fatalf("选项:%s 不存在 请检查拼写\n", argName)
}
os.Args = append(os.Args, arg)
}
}
}
resetFlag()
flag.Parse()
if *mcType != "" {
opt.MCType = *mcType
}
if *key != "" {
opt.KeyMethod = *key
}
if *expire != "" {
opt.ExpireCode = *expire
}
opt.EnableBatch = (*batchSize != 0) && (*maxGroup != 0)
opt.BatchErrBreak = *batchErr == "break"
opt.GroupSize = *batchSize
opt.MaxGroup = *maxGroup
// get type from prefix
if opt.MCType == "" {
for _, t := range mcValidPrefix {
if strings.HasPrefix(strings.ToLower(opt.name), t) {
if t == "add" {
t = _typeSet
}
opt.MCType = t
break
}
}
if opt.MCType == "" {
log.Fatalln(opt.name + "请指定方法类型(type=get/set/del...)")
}
}
if opt.MCType == "cache" {
opt.MCType = _typeGet
}
params := list.Type.(*ast.FuncType).Params.List
if len(params) == 0 {
log.Fatalln(opt.name + "参数不足")
}
if s.ExprString(params[0].Type) != "context.Context" {
log.Fatalln(opt.name + "第一个参数必须为context")
}
for _, param := range params {
if len(param.Names) > 1 {
log.Fatalln(opt.name + "不支持省略类型")
}
}
// get template
if len(params) == 1 {
opt.template = _noneTpl
} else if (len(params) == 2) && (opt.MCType == _typeSet || opt.MCType == _typeAdd || opt.MCType == _typeReplace) {
if _, ok := params[1].Type.(*ast.MapType); ok {
opt.template = _multiTpl
} else {
opt.template = _noneTpl
}
} else {
if _, ok := params[1].Type.(*ast.ArrayType); ok {
opt.template = _multiTpl
} else {
opt.template = _singleTpl
}
}
// extra args
if len(params) > 2 {
args := []string{""}
allArgs := []string{""}
var pos = 2
if (opt.MCType == _typeAdd) || (opt.MCType == _typeSet) || (opt.MCType == _typeReplace) {
pos = 3
}
for _, pa := range params[pos:] {
paType := s.ExprString(pa.Type)
if len(pa.Names) == 0 {
args = append(args, paType)
allArgs = append(allArgs, paType)
continue
}
var names []string
for _, name := range pa.Names {
names = append(names, name.Name)
}
allArgs = append(allArgs, strings.Join(names, ",")+" "+paType)
args = append(args, strings.Join(names, ","))
}
if len(args) > 1 {
opt.ExtraArgs = strings.Join(args, ",")
opt.ExtraArgsType = strings.Join(allArgs, ",")
}
}
// get k v from results
results := list.Type.(*ast.FuncType).Results.List
if s.ExprString(results[len(results)-1].Type) != "error" {
log.Fatalln("最后返回值参数需为error")
}
for _, res := range results {
if len(res.Names) > 1 {
log.Fatalln(opt.name + "返回值不支持省略类型")
}
}
if opt.MCType == _typeGet {
if len(results) != 2 {
log.Fatalln("参数个数不对")
}
}
// get key type and value type
if (opt.MCType == _typeAdd) || (opt.MCType == _typeSet) || (opt.MCType == _typeReplace) {
if opt.template == _multiTpl {
p, ok := params[1].Type.(*ast.MapType)
if !ok {
log.Fatalf("%s: 参数类型错误 批量设置数据时类型需为map类型\n", opt.name)
}
opt.keyType = s.ExprString(p.Key)
opt.ValueType = s.ExprString(p.Value)
} else if opt.template == _singleTpl {
opt.keyType = s.ExprString(params[1].Type)
opt.ValueType = s.ExprString(params[2].Type)
} else {
opt.ValueType = s.ExprString(params[1].Type)
}
}
if opt.MCType == _typeGet {
if opt.template == _multiTpl {
if p, ok := results[0].Type.(*ast.MapType); ok {
opt.keyType = s.ExprString(p.Key)
opt.ValueType = s.ExprString(p.Value)
} else {
log.Fatalf("%s: 返回值类型错误 批量获取数据时返回值需为map类型\n", opt.name)
}
} else if opt.template == _singleTpl {
opt.keyType = s.ExprString(params[1].Type)
opt.ValueType = s.ExprString(results[0].Type)
} else {
opt.ValueType = s.ExprString(results[0].Type)
}
}
if opt.MCType == _typeDel {
if opt.template == _multiTpl {
p, ok := params[1].Type.(*ast.ArrayType)
if !ok {
log.Fatalf("%s: 类型错误 参数需为[]类型\n", opt.name)
}
opt.keyType = s.ExprString(p.Elt)
} else if opt.template == _singleTpl {
opt.keyType = s.ExprString(params[1].Type)
}
}
for _, t := range simpleTypes {
if t == opt.ValueType {
opt.SimpleValue = true
opt.GetSimpleValue = true
opt.ConvertValue2Bytes = convertValue2Bytes(t)
opt.ConvertBytes2Value = convertBytes2Value(t)
break
}
}
if opt.ValueType == "string" {
opt.LenType = true
} else {
for _, t := range lenTypes {
if strings.HasPrefix(opt.ValueType, t) {
opt.LenType = true
break
}
}
}
if opt.SimpleValue && (opt.ValueType == "[]byte" || opt.ValueType == "string") {
opt.GetSimpleValue = false
opt.GetDirectValue = true
}
if opt.MCType == _typeGet && opt.template == _multiTpl {
opt.UseMemcached = false
}
if strings.HasPrefix(opt.ValueType, "*") {
opt.InitValue = true
opt.PointType = true
opt.OriginValueType = strings.Replace(opt.ValueType, "*", "", 1)
} else {
opt.OriginValueType = opt.ValueType
}
if *encode != "" {
var flags []string
for _, f := range strings.Split(*encode, "|") {
switch f {
case "gob":
flags = append(flags, "memcache.FlagGOB")
case "json":
flags = append(flags, "memcache.FlagJSON")
case "raw":
flags = append(flags, "memcache.FlagRAW")
case "pb":
flags = append(flags, "memcache.FlagProtobuf")
case "gzip":
flags = append(flags, "memcache.FlagGzip")
default:
log.Fatalf("%s: encode类型无效\n", opt.name)
}
}
opt.Encode = strings.Join(flags, " | ")
} else {
if opt.SimpleValue {
opt.Encode = "memcache.FlagRAW"
} else {
opt.Encode = "memcache.FlagJSON"
}
}
opt.Check()
opts = append(opts, &opt)
}
return
}
func (option *options) Check() {
var valid bool
for _, x := range mcValidTypes {
if x == option.MCType {
valid = true
break
}
}
if !valid {
log.Fatalf("%s: 类型错误 不支持%s类型\n", option.name, option.MCType)
}
if (option.MCType != _typeDel) && !option.SimpleValue && !strings.Contains(option.ValueType, "*") && !strings.Contains(option.ValueType, "[]") && !strings.Contains(option.ValueType, "map") {
log.Fatalf("%s: 值类型只能为基本类型/slice/map/指针类型\n", option.name)
}
}
func genHeader(opts []*options) (src string) {
option := options{PkgName: os.Getenv("GOPACKAGE"), UseMemcached: false}
var packages []string
packagesMap := map[string]bool{`"context"`: true}
for _, opt := range opts {
if len(opt.importPackages) > 0 {
for _, pkg := range opt.importPackages {
if !packagesMap[pkg] {
packages = append(packages, pkg)
packagesMap[pkg] = true
}
}
}
if opt.Args != "" {
option.Args = opt.Args
}
if opt.UseMemcached {
option.UseMemcached = true
}
if opt.SimpleValue && !opt.GetDirectValue {
option.UseStrConv = true
}
if opt.EnableBatch {
option.EnableBatch = true
}
}
option.ImportPackage = strings.Join(packages, "\n")
src = _headerTemplate
t := template.Must(template.New("header").Parse(src))
var buffer bytes.Buffer
err := t.Execute(&buffer, option)
if err != nil {
log.Fatalf("execute template: %s", err)
}
// Format the output.
src = strings.Replace(buffer.String(), "\t", "", -1)
src = regexp.MustCompile("\n+").ReplaceAllString(src, "\n")
src = strings.Replace(src, "NEWLINE", "", -1)
src = strings.Replace(src, "ARGS", option.Args, -1)
return
}
func genBody(opts []*options) (res string) {
for _, option := range opts {
var src string
if option.template == _multiTpl {
switch option.MCType {
case _typeGet:
src = _multiGetTemplate
case _typeSet:
src = _multiSetTemplate
case _typeReplace:
src = _multiReplaceTemplate
case _typeDel:
src = _multiDelTemplate
case _typeAdd:
src = _multiAddTemplate
}
} else if option.template == _singleTpl {
switch option.MCType {
case _typeGet:
src = _singleGetTemplate
case _typeSet:
src = _singleSetTemplate
case _typeReplace:
src = _singleReplaceTemplate
case _typeDel:
src = _singleDelTemplate
case _typeAdd:
src = _singleAddTemplate
}
} else {
switch option.MCType {
case _typeGet:
src = _noneGetTemplate
case _typeSet:
src = _noneSetTemplate
case _typeReplace:
src = _noneReplaceTemplate
case _typeDel:
src = _noneDelTemplate
case _typeAdd:
src = _noneAddTemplate
}
}
src = strings.Replace(src, "KEY", option.keyType, -1)
src = strings.Replace(src, "NAME", option.name, -1)
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)
t := template.Must(template.New("cache").Parse(src))
var buffer bytes.Buffer
err := t.Execute(&buffer, option)
if err != nil {
log.Fatalf("execute template: %s", err)
}
// Format the output.
src = strings.Replace(buffer.String(), "\t", "", -1)
src = regexp.MustCompile("\n+").ReplaceAllString(src, "\n")
res = res + "\n" + src
}
return
}
func main() {
log.SetFlags(0)
defer func() {
if err := recover(); err != nil {
log.Fatalf("程序解析失败, err: %+v 请企业微信联系 @wangxu01", err)
}
}()
options := parse(common.NewSource(common.SourceText()))
header := genHeader(options)
body := genBody(options)
code := common.FormatCode(header + "\n" + body)
// Write to file.
dir := filepath.Dir(".")
outputName := filepath.Join(dir, "mc.cache.go")
err := ioutil.WriteFile(outputName, []byte(code), 0644)
if err != nil {
log.Fatalf("写入文件失败: %s", err)
}
log.Println("mc.cache.go: 生成成功")
}
func convertValue2Bytes(t string) string {
switch t {
case "int", "int8", "int16", "int32", "int64":
return "[]byte(strconv.FormatInt(int64(val), 10))"
case "uint", "uint8", "uint16", "uint32", "uint64":
return "[]byte(strconv.FormatUInt(val, 10))"
case "bool":
return "[]byte(strconv.FormatBool(val))"
case "float32":
return "[]byte(strconv.FormatFloat(val, 'E', -1, 32))"
case "float64":
return "[]byte(strconv.FormatFloat(val, 'E', -1, 64))"
case "string":
return "[]byte(val)"
case "[]byte":
return "val"
}
return ""
}
func convertBytes2Value(t string) string {
switch t {
case "int", "int8", "int16", "int32", "int64":
return "strconv.ParseInt(v, 10, 64)"
case "uint", "uint8", "uint16", "uint32", "uint64":
return "strconv.ParseUInt(v, 10, 64)"
case "bool":
return "strconv.ParseBool(v)"
case "float32":
return "float32(strconv.ParseFloat(v, 32))"
case "float64":
return "strconv.ParseFloat(v, 64)"
}
return ""
}

View File

@@ -0,0 +1,217 @@
package main
import (
"strings"
)
var _multiGetTemplate = `
// NAME {{or .Comment "get data from mc"}}
func (d *Dao) NAME(c context.Context, ids []KEY {{.ExtraArgsType}}) (res map[KEY]VALUE, err error) {
l := len(ids)
if l == 0 {
return
}
{{if .EnableBatch}}
mutex := sync.Mutex{}
for i:=0;i < l; i+= GROUPSIZE * MAXGROUP {
var subKeys []KEY
{{if .BatchErrBreak}}
group, ctx := errgroup.WithContext(c)
{{else}}
group := &errgroup.Group{}
ctx := c
{{end}}
if (i + GROUPSIZE * MAXGROUP) > l {
subKeys = ids[i:]
} else {
subKeys = ids[i : i+GROUPSIZE * MAXGROUP]
}
subLen := len(subKeys)
for j:=0; j< subLen; j += GROUPSIZE {
var ks []KEY
if (j+GROUPSIZE) > subLen {
ks = subKeys[j:]
} else {
ks = subKeys[j:j+GROUPSIZE]
}
group.Go(func() (err error) {
keysMap := make(map[string]KEY, len(ks))
keys := make([]string, 0, len(ks))
for _, id := range ks {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
keysMap[key] = id
keys = append(keys, key)
}
conn := d.mc.Get(ctx)
defer conn.Close()
replies, err := conn.GetMulti(keys)
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(ctx, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("keys", keys))
return
}
for key, reply := range replies {
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
var v VALUE
{{if .GetDirectValue}}
err = conn.Scan(reply, &v)
{{else}}
{{if .InitValue}}
v = &{{.OriginValueType}}{}
err = conn.Scan(reply, res)
{{else}}
v = {{.OriginValueType}}{}
err = conn.Scan(reply, &res)
{{end}}
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(ctx, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(ctx, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return res, err
}
mutex.Lock()
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = {{.ValueType}}(r)
mutex.Unlock()
{{else}}
mutex.Lock()
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = v
mutex.Unlock()
{{end}}
}
return
})
}
err1 := group.Wait()
if err1 != nil {
err = err1
{{if .BatchErrBreak}}
break
{{end}}
}
}
{{else}}
keysMap := make(map[string]KEY, l)
keys := make([]string, 0, l)
for _, id := range ids {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
keysMap[key] = id
keys = append(keys, key)
}
conn := d.mc.Get(c)
defer conn.Close()
replies, err := conn.GetMulti(keys)
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("keys", keys))
return
}
for key, reply := range replies {
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
var v VALUE
{{if .InitValue}}
v = &{{.OriginValueType}}{}
err = conn.Scan(reply, v)
{{else}}
v = {{.OriginValueType}}{}
err = conn.Scan(reply, &v)
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return res, err
}
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = {{.ValueType}}(r)
{{else}}
if res == nil {
res = make(map[KEY]VALUE, len(keys))
}
res[keysMap[key]] = v
{{end}}
}
{{end}}
return
}
`
var _multiSetTemplate = `
// NAME {{or .Comment "Set data to mc"}}
func (d *Dao) NAME(c context.Context, values map[KEY]VALUE {{.ExtraArgsType}}) (err error) {
if len(values) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for id, val := range values {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
{{if .SimpleValue}}
bs := {{.ConvertValue2Bytes}}
item := &memcache.Item{Key: key, Value: bs, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{else}}
item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{end}}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
`
var _multiAddTemplate = strings.Replace(_multiSetTemplate, "Set", "Add", -1)
var _multiReplaceTemplate = strings.Replace(_multiSetTemplate, "Set", "Replace", -1)
var _multiDelTemplate = `
// NAME {{or .Comment "delete data from mc"}}
func (d *Dao) NAME(c context.Context, ids []KEY {{.ExtraArgsType}}) (err error) {
if len(ids) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for _, id := range ids {
key := {{.KeyMethod}}(id{{.ExtraArgs}})
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
continue
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
`

View File

@@ -0,0 +1,107 @@
package main
import (
"strings"
)
var _noneGetTemplate = `
// NAME {{or .Comment "get data from mc"}}
func (d *Dao) NAME(c context.Context) (res VALUE, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}()
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
{{if .GetDirectValue}}
err = conn.Scan(reply, &res)
{{else}}
{{if .InitValue}}
res = &{{.OriginValueType}}{}
err = conn.Scan(reply, res)
{{else}}
res = {{.OriginValueType}}{}
err = conn.Scan(reply, &res)
{{end}}
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = {{.ValueType}}(r)
{{end}}
return
}
`
var _noneSetTemplate = `
// NAME {{or .Comment "Set data to mc"}}
func (d *Dao) NAME(c context.Context, val VALUE) (err error) {
{{if .PointType}}
if val == nil {
return
}
{{end}}
{{if .LenType}}
if len(val) == 0 {
return
}
{{end}}
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}()
{{if .SimpleValue}}
bs := {{.ConvertValue2Bytes}}
item := &memcache.Item{Key: key, Value: bs, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{else}}
item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{end}}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`
var _noneAddTemplate = strings.Replace(_noneSetTemplate, "Set", "Add", -1)
var _noneReplaceTemplate = strings.Replace(_noneSetTemplate, "Set", "Replace", -1)
var _noneDelTemplate = `
// NAME {{or .Comment "delete data from mc"}}
func (d *Dao) NAME(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`

View File

@@ -0,0 +1,107 @@
package main
import (
"strings"
)
var _singleGetTemplate = `
// NAME {{or .Comment "get data from mc"}}
func (d *Dao) NAME(c context.Context, id KEY {{.ExtraArgsType}}) (res VALUE, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}(id{{.ExtraArgs}})
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
var v string
err = conn.Scan(reply, &v)
{{else}}
{{if .GetDirectValue}}
err = conn.Scan(reply, &res)
{{else}}
{{if .InitValue}}
res = &{{.OriginValueType}}{}
err = conn.Scan(reply, res)
{{else}}
res = {{.OriginValueType}}{}
err = conn.Scan(reply, &res)
{{end}}
{{end}}
{{end}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
{{if .GetSimpleValue}}
r, err := {{.ConvertBytes2Value}}
if err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = {{.ValueType}}(r)
{{end}}
return
}
`
var _singleSetTemplate = `
// NAME {{or .Comment "Set data to mc"}}
func (d *Dao) NAME(c context.Context, id KEY, val VALUE {{.ExtraArgsType}}) (err error) {
{{if .PointType}}
if val == nil {
return
}
{{end}}
{{if .LenType}}
if len(val) == 0 {
return
}
{{end}}
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}(id{{.ExtraArgs}})
{{if .SimpleValue}}
bs := {{.ConvertValue2Bytes}}
item := &memcache.Item{Key: key, Value: bs, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{else}}
item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}}
{{end}}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`
var _singleAddTemplate = strings.Replace(_singleSetTemplate, "Set", "Add", -1)
var _singleReplaceTemplate = strings.Replace(_singleSetTemplate, "Set", "Replace", -1)
var _singleDelTemplate = `
// NAME {{or .Comment "delete data from mc"}}
func (d *Dao) NAME(c context.Context, id KEY {{.ExtraArgsType}}) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := {{.KeyMethod}}(id{{.ExtraArgs}})
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:NAME")
log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
`

71
app/tool/cache/memcached/testdata/BUILD vendored Normal file
View File

@@ -0,0 +1,71 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
proto_library(
name = "model_proto",
srcs = ["model.proto"],
tags = ["automanaged"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/tool/cache/memcached/testdata",
proto = ":model_proto",
tags = ["automanaged"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mc.cache.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/tool/cache/memcached/testdata",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/container/pool:go_default_library",
"//library/log:go_default_library",
"//library/stat/prom:go_default_library",
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,87 @@
package testdata
import (
"context"
"fmt"
"time"
"go-common/library/cache/memcache"
"go-common/library/container/pool"
xtime "go-common/library/time"
)
// Dao .
type Dao struct {
mc *memcache.Pool
articleExpire int32
}
// New new dao
func New() (d *Dao) {
cfg := &memcache.Config{
Config: &pool.Config{
Active: 10,
Idle: 5,
IdleTimeout: xtime.Duration(time.Second),
},
Name: "test",
Proto: "tcp",
// Addr: "172.16.33.54:11214",
Addr: "127.0.0.1:11211",
DialTimeout: xtime.Duration(time.Second),
ReadTimeout: xtime.Duration(time.Second),
WriteTimeout: xtime.Duration(time.Second),
}
d = &Dao{
mc: memcache.NewPool(cfg),
articleExpire: int32(5),
}
return
}
//go:generate $GOPATH/src/go-common/app/tool/cache/mc
type _mc interface {
// mc: -key=articleKey
CacheArticles(c context.Context, keys []int64) (map[int64]*Article, error)
// mc: -key=articleKey
CacheArticle(c context.Context, key int64) (*Article, error)
// mc: -key=keyMid
CacheArticle1(c context.Context, key int64, mid int64) (*Article, error)
// mc: -key=noneKey
CacheNone(c context.Context) (*Article, error)
// mc: -key=articleKey
CacheString(c context.Context, key int64) (string, error)
// mc: -key=articleKey -expire=d.articleExpire -encode=json
AddCacheArticles(c context.Context, values map[int64]*Article) error
// 这里也支持自定义注释 会替换默认的注释
// mc: -key=articleKey -expire=d.articleExpire -encode=json|gzip
AddCacheArticle(c context.Context, key int64, value *Article) error
// mc: -key=keyMid -expire=d.articleExpire -encode=gob
AddCacheArticle1(c context.Context, key int64, value *Article, mid int64) error
// mc: -key=noneKey
AddCacheNone(c context.Context, value *Article) error
// mc: -key=articleKey -expire=d.articleExpire
AddCacheString(c context.Context, key int64, value string) error
// mc: -key=articleKey
DelCacheArticles(c context.Context, keys []int64) error
// mc: -key=articleKey
DelCacheArticle(c context.Context, key int64) error
// mc: -key=keyMid
DelCacheArticle1(c context.Context, key int64, mid int64) error
// mc: -key=noneKey
DelCacheNone(c context.Context) error
}
func articleKey(id int64) string {
return fmt.Sprintf("art_%d", id)
}
func keyMid(id, mid int64) string {
return fmt.Sprintf("art_%d_%d", id, mid)
}
func noneKey() string {
return "none"
}

View File

@@ -0,0 +1,116 @@
package testdata
import (
"context"
"testing"
)
func TestArticle(t *testing.T) {
d := New()
c := context.TODO()
art := &Article{ID: 1, Title: "title"}
err := d.AddCacheArticle(c, art.ID, art)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err := d.CacheArticle(c, art.ID)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if (art1.ID != art.ID) || (art.Title != art1.Title) {
t.Error("art not equal")
t.FailNow()
}
err = d.DelCacheArticle(c, art.ID)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err = d.CacheArticle(c, art.ID)
if (art1 != nil) || (err != nil) {
t.Errorf("art %v, err: %v", art1, err)
t.FailNow()
}
}
func TestNone(t *testing.T) {
d := New()
c := context.TODO()
art := &Article{ID: 1, Title: "title"}
err := d.AddCacheNone(c, art)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err := d.CacheNone(c)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if (art1.ID != art.ID) || (art.Title != art1.Title) {
t.Error("art not equal")
t.FailNow()
}
err = d.DelCacheNone(c)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
art1, err = d.CacheNone(c)
if (art1 != nil) || (err != nil) {
t.Errorf("art %v, err: %v", art1, err)
t.FailNow()
}
}
func TestArticles(t *testing.T) {
d := New()
c := context.TODO()
art1 := &Article{ID: 1, Title: "title"}
art2 := &Article{ID: 2, Title: "title"}
err := d.AddCacheArticles(c, map[int64]*Article{1: art1, 2: art2})
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
arts, err := d.CacheArticles(c, []int64{art1.ID, art2.ID})
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if (arts[1].Title != art1.Title) || (arts[2].Title != art2.Title) {
t.Error("art not equal")
t.FailNow()
}
err = d.DelCacheArticles(c, []int64{art1.ID, art2.ID})
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
arts, err = d.CacheArticles(c, []int64{art1.ID, art2.ID})
if (arts != nil) || (err != nil) {
t.Errorf("art %v, err: %v", art1, err)
t.FailNow()
}
}
func TestString(t *testing.T) {
d := New()
c := context.TODO()
err := d.AddCacheString(c, 1, "abc")
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
res, err := d.CacheString(c, 1)
if err != nil {
t.Errorf("err should be nil, get: %v", err)
t.FailNow()
}
if res != "abc" {
t.Error("res wrong")
t.FailNow()
}
}

View File

@@ -0,0 +1,350 @@
// Code generated by $GOPATH/src/go-common/app/tool/cache/mc. DO NOT EDIT.
/*
Package testdata is a generated mc cache package.
It is generated from:
type _mc interface {
// mc: -key=articleKey
CacheArticles(c context.Context, keys []int64) (map[int64]*Article, error)
// mc: -key=articleKey
CacheArticle(c context.Context, key int64) (*Article, error)
// mc: -key=keyMid
CacheArticle1(c context.Context, key int64, mid int64) (*Article, error)
// mc: -key=noneKey
CacheNone(c context.Context) (*Article, error)
// mc: -key=articleKey
CacheString(c context.Context, key int64) (string, error)
// mc: -key=articleKey -expire=d.articleExpire -encode=json
AddCacheArticles(c context.Context, values map[int64]*Article) error
// 这里也支持自定义注释 会替换默认的注释
// mc: -key=articleKey -expire=d.articleExpire -encode=json|gzip
AddCacheArticle(c context.Context, key int64, value *Article) error
// mc: -key=keyMid -expire=d.articleExpire -encode=gob
AddCacheArticle1(c context.Context, key int64, value *Article, mid int64) error
// mc: -key=noneKey
AddCacheNone(c context.Context, value *Article) error
// mc: -key=articleKey -expire=d.articleExpire
AddCacheString(c context.Context, key int64, value string) error
// mc: -key=articleKey
DelCacheArticles(c context.Context, keys []int64) error
// mc: -key=articleKey
DelCacheArticle(c context.Context, key int64) error
// mc: -key=keyMid
DelCacheArticle1(c context.Context, key int64, mid int64) error
// mc: -key=noneKey
DelCacheNone(c context.Context) error
}
*/
package testdata
import (
"context"
"fmt"
"go-common/library/cache/memcache"
"go-common/library/log"
"go-common/library/stat/prom"
)
var _ _mc
// CacheArticles get data from mc
func (d *Dao) CacheArticles(c context.Context, ids []int64) (res map[int64]*Article, err error) {
l := len(ids)
if l == 0 {
return
}
keysMap := make(map[string]int64, l)
keys := make([]string, 0, l)
for _, id := range ids {
key := articleKey(id)
keysMap[key] = id
keys = append(keys, key)
}
conn := d.mc.Get(c)
defer conn.Close()
replies, err := conn.GetMulti(keys)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticles")
log.Errorv(c, log.KV("CacheArticles", fmt.Sprintf("%+v", err)), log.KV("keys", keys))
return
}
for key, reply := range replies {
var v *Article
v = &Article{}
err = conn.Scan(reply, v)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticles")
log.Errorv(c, log.KV("CacheArticles", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
if res == nil {
res = make(map[int64]*Article, len(keys))
}
res[keysMap[key]] = v
}
return
}
// CacheArticle get data from mc
func (d *Dao) CacheArticle(c context.Context, id int64) (res *Article, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheArticle")
log.Errorv(c, log.KV("CacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &Article{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticle")
log.Errorv(c, log.KV("CacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheArticle1 get data from mc
func (d *Dao) CacheArticle1(c context.Context, id int64, mid int64) (res *Article, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := keyMid(id, mid)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheArticle1")
log.Errorv(c, log.KV("CacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &Article{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheArticle1")
log.Errorv(c, log.KV("CacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheNone get data from mc
func (d *Dao) CacheNone(c context.Context) (res *Article, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := noneKey()
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheNone")
log.Errorv(c, log.KV("CacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
res = &Article{}
err = conn.Scan(reply, res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheNone")
log.Errorv(c, log.KV("CacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// CacheString get data from mc
func (d *Dao) CacheString(c context.Context, id int64) (res string, err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
reply, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:CacheString")
log.Errorv(c, log.KV("CacheString", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
err = conn.Scan(reply, &res)
if err != nil {
prom.BusinessErrCount.Incr("mc:CacheString")
log.Errorv(c, log.KV("CacheString", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheArticles Set data to mc
func (d *Dao) AddCacheArticles(c context.Context, values map[int64]*Article) (err error) {
if len(values) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for id, val := range values {
key := articleKey(id)
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheArticles")
log.Errorv(c, log.KV("AddCacheArticles", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
// AddCacheArticle 这里也支持自定义注释 会替换默认的注释
func (d *Dao) AddCacheArticle(c context.Context, id int64, val *Article) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagJSON | memcache.FlagGzip}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheArticle")
log.Errorv(c, log.KV("AddCacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheArticle1 Set data to mc
func (d *Dao) AddCacheArticle1(c context.Context, id int64, val *Article, mid int64) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := keyMid(id, mid)
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagGOB}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheArticle1")
log.Errorv(c, log.KV("AddCacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheNone Set data to mc
func (d *Dao) AddCacheNone(c context.Context, val *Article) (err error) {
if val == nil {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := noneKey()
item := &memcache.Item{Key: key, Object: val, Expiration: d.articleExpire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheNone")
log.Errorv(c, log.KV("AddCacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// AddCacheString Set data to mc
func (d *Dao) AddCacheString(c context.Context, id int64, val string) (err error) {
if len(val) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
bs := []byte(val)
item := &memcache.Item{Key: key, Value: bs, Expiration: d.articleExpire, Flags: memcache.FlagRAW}
if err = conn.Set(item); err != nil {
prom.BusinessErrCount.Incr("mc:AddCacheString")
log.Errorv(c, log.KV("AddCacheString", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheArticles delete data from mc
func (d *Dao) DelCacheArticles(c context.Context, ids []int64) (err error) {
if len(ids) == 0 {
return
}
conn := d.mc.Get(c)
defer conn.Close()
for _, id := range ids {
key := articleKey(id)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
continue
}
prom.BusinessErrCount.Incr("mc:DelCacheArticles")
log.Errorv(c, log.KV("DelCacheArticles", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
}
return
}
// DelCacheArticle delete data from mc
func (d *Dao) DelCacheArticle(c context.Context, id int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := articleKey(id)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheArticle")
log.Errorv(c, log.KV("DelCacheArticle", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheArticle1 delete data from mc
func (d *Dao) DelCacheArticle1(c context.Context, id int64, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := keyMid(id, mid)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheArticle1")
log.Errorv(c, log.KV("DelCacheArticle1", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}
// DelCacheNone delete data from mc
func (d *Dao) DelCacheNone(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := noneKey()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
prom.BusinessErrCount.Incr("mc:DelCacheNone")
log.Errorv(c, log.KV("DelCacheNone", fmt.Sprintf("%+v", err)), log.KV("key", key))
return
}
return
}

View File

@@ -0,0 +1,328 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: model.proto
/*
Package model is a generated protocol buffer package.
It is generated from these files:
model.proto
It has these top-level messages:
Article
*/
package testdata
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Article struct {
ID int64 `protobuf:"varint,1,opt,name=ID,proto3" json:"id"`
Title string `protobuf:"bytes,3,opt,name=Title,proto3" json:"title"`
}
func (m *Article) Reset() { *m = Article{} }
func (m *Article) String() string { return proto.CompactTextString(m) }
func (*Article) ProtoMessage() {}
func (*Article) Descriptor() ([]byte, []int) { return fileDescriptorModel, []int{0} }
func init() {
proto.RegisterType((*Article)(nil), "model.Article")
}
func (m *Article) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Article) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.ID != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintModel(dAtA, i, uint64(m.ID))
}
if len(m.Title) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.Title)))
i += copy(dAtA[i:], m.Title)
}
return i, nil
}
func encodeVarintModel(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *Article) Size() (n int) {
var l int
_ = l
if m.ID != 0 {
n += 1 + sovModel(uint64(m.ID))
}
l = len(m.Title)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
return n
}
func sovModel(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozModel(x uint64) (n int) {
return sovModel(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Article) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Article: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Article: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ID", wireType)
}
m.ID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ID |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Title = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipModel(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthModel
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipModel(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthModel
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipModel(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthModel = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowModel = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("model.proto", fileDescriptorModel) }
var fileDescriptorModel = []byte{
// 166 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0xcd, 0x4f, 0x49,
0xcd, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0xa4, 0x74, 0xd3, 0x33, 0x4b,
0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0xd3, 0xf3, 0xd3, 0xf3, 0xf5, 0xc1, 0xb2, 0x49,
0xa5, 0x69, 0x60, 0x1e, 0x98, 0x03, 0x66, 0x41, 0x74, 0x29, 0x39, 0x71, 0xb1, 0x3b, 0x16, 0x95,
0x64, 0x26, 0xe7, 0xa4, 0x0a, 0x89, 0x71, 0x31, 0x79, 0xba, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x30,
0x3b, 0xb1, 0xbd, 0xba, 0x27, 0xcf, 0x94, 0x99, 0x12, 0xc4, 0xe4, 0xe9, 0x22, 0x24, 0xcf, 0xc5,
0x1a, 0x92, 0x59, 0x92, 0x93, 0x2a, 0xc1, 0xac, 0xc0, 0xa8, 0xc1, 0xe9, 0xc4, 0xf9, 0xea, 0x9e,
0x3c, 0x6b, 0x09, 0x48, 0x20, 0x08, 0x22, 0xee, 0x24, 0x71, 0xe2, 0xa1, 0x1c, 0xc3, 0x85, 0x87,
0x72, 0x0c, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x8c,
0xc7, 0x72, 0x0c, 0x49, 0x6c, 0x60, 0x4b, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x11, 0xa6,
0xfa, 0x1c, 0xa9, 0x00, 0x00, 0x00,
}

View File

@@ -0,0 +1,14 @@
syntax = "proto3";
package model;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
message Article {
int64 ID = 1 [(gogoproto.jsontag) = "id"];
string Title = 3 [(gogoproto.jsontag) = "title"];
}