Compare commits
No commits in common. "master" and "test_by_yulang" have entirely different histories.
master
...
test_by_yu
|
@ -7,7 +7,7 @@
|
||||||
### 描述(做了什么,变更了什么)
|
### 描述(做了什么,变更了什么)
|
||||||
|
|
||||||
|
|
||||||
### 影响到的模块
|
### 测试用例(新增、改动、可能影响的功能)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,17 +5,8 @@
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
|
|
||||||
|
|
||||||
# build file
|
|
||||||
/bin/storage
|
|
||||||
/bin/gateway
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/wheat-cache.iml" filepath="$PROJECT_DIR$/.idea/wheat-cache.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="Go" enabled="true" />
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
|
@ -1,7 +0,0 @@
|
||||||
FROM ubuntu:18.04
|
|
||||||
|
|
||||||
WORKDIR /home/src/gitee.com/wheat-os/wheat-cache
|
|
||||||
ADD . /home/src/gitee.com/wheat-os/wheat-cache
|
|
||||||
|
|
||||||
RUN mkdir /etc/wheat-cache
|
|
||||||
RUN mv /home/src/gitee.com/wheat-os/wheat-cache/conf/wheat-cache.yaml /etc/wheat-cache/
|
|
Binary file not shown.
|
@ -1,22 +0,0 @@
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitee.com/wheat-os/wheatCache/client/middle"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newWheatClient(targer string, opt ...middle.ClientMiddle) (proto.CommServerClient, error) {
|
|
||||||
|
|
||||||
interceptor := middle.GetUnaryInterceptor(opt...)
|
|
||||||
comm, err := grpc.Dial(targer, grpc.WithInsecure(), grpc.WithUnaryInterceptor(interceptor))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return proto.NewCommServerClient(comm), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewWheatClient(targer string, opt ...middle.ClientMiddle) (proto.CommServerClient, error) {
|
|
||||||
return newWheatClient(targer, opt...)
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/client/middle"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestClient(t *testing.T) {
|
|
||||||
cli, err := NewWheatClient("127.0.0.1:5891", middle.WithUnaryColonyClient)
|
|
||||||
require.NoError(t, err)
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
bKey := proto.NewBaseKey("apple")
|
|
||||||
resp, err := cli.Set(ctx, &proto.SetRequest{
|
|
||||||
Key: bKey,
|
|
||||||
Val: "yyyy",
|
|
||||||
})
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, resp.Result, "yyyy")
|
|
||||||
|
|
||||||
getResp, err := cli.Get(ctx, &proto.GetRequest{
|
|
||||||
Key: bKey,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, getResp.Result, "yyyy")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestClientGet(t *testing.T) {
|
|
||||||
cli, err := NewWheatClient("127.0.0.1:5891", middle.WithUnaryColonyClient)
|
|
||||||
require.NoError(t, err)
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
bKey := &proto.BaseKey{
|
|
||||||
Key: "apple",
|
|
||||||
}
|
|
||||||
|
|
||||||
getResp, err := cli.Get(ctx, &proto.GetRequest{
|
|
||||||
Key: bKey,
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, getResp.Result, "yyyy")
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
package middle
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
// type UnaryClientInterceptor func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error
|
|
||||||
type ClientMiddle func(ctx context.Context, method string, req, reply interface{}, header map[string]string) error
|
|
|
@ -1,53 +0,0 @@
|
||||||
package middle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/metadata"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
func WithUnaryColonyClient(ctx context.Context, method string, req, reply interface{}, header map[string]string) error {
|
|
||||||
key, ok := req.(proto.GetKeyBaseInterface)
|
|
||||||
if !ok {
|
|
||||||
return status.Errorf(codes.Unknown, "key base err")
|
|
||||||
}
|
|
||||||
if header == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// meta 解析会出现 全部小写问题
|
|
||||||
header[proto.BaseKeyMethodKey] = key.GetKey().Key
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getKeyByKeyMapvalue(m map[string]string) []string {
|
|
||||||
l := make([]string, 0)
|
|
||||||
for key, value := range m {
|
|
||||||
l = append(l, key, value)
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUnaryInterceptor(middleOpts ...ClientMiddle) grpc.UnaryClientInterceptor {
|
|
||||||
return func(ctx context.Context, method string, req, reply interface{},
|
|
||||||
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
|
||||||
// 加载中间件
|
|
||||||
header := make(map[string]string)
|
|
||||||
for _, mid := range middleOpts {
|
|
||||||
err := mid(ctx, method, req, reply, header)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lm := getKeyByKeyMapvalue(header)
|
|
||||||
|
|
||||||
headerData := metadata.Pairs(lm...)
|
|
||||||
ctxH := metadata.NewOutgoingContext(ctx, headerData)
|
|
||||||
|
|
||||||
return invoker(ctxH, method, req, reply, cc, opts...)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package conf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
linuxPath = "/etc/wheat-cache/"
|
|
||||||
)
|
|
||||||
|
|
||||||
var confLock sync.Once
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
confLock.Do(func() {
|
|
||||||
setDefaultConfValue()
|
|
||||||
err := LoadConf("")
|
|
||||||
switch err.(type) {
|
|
||||||
case nil:
|
|
||||||
case viper.ConfigFileNotFoundError:
|
|
||||||
formatPath := []string{linuxPath}
|
|
||||||
log.Fatalf("the profile could not be read, read path:%v", formatPath)
|
|
||||||
default:
|
|
||||||
log.Fatalf("the resolution of the profile failed, err: %v", err)
|
|
||||||
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setDefaultConfValue() {
|
|
||||||
// 设置一些默认值
|
|
||||||
viper.SetDefault("version", "base-01")
|
|
||||||
defaultStorage()
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadConf(path string) error {
|
|
||||||
if path != "" {
|
|
||||||
viper.AddConfigPath(path)
|
|
||||||
}
|
|
||||||
viper.SetConfigName("wheat-cache")
|
|
||||||
|
|
||||||
// 添加默认读取地址
|
|
||||||
// linux
|
|
||||||
viper.AddConfigPath(linuxPath)
|
|
||||||
|
|
||||||
viper.SetConfigType("yaml")
|
|
||||||
|
|
||||||
err := viper.ReadInConfig()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package conf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConf(t *testing.T) {
|
|
||||||
|
|
||||||
// 外部导入 conf.yaml 需要导入 conf 包
|
|
||||||
// 每次迁移文件时, 使用 sudo make init-conf来将yam文件迁移到指定的文件夹下
|
|
||||||
// get 使用, 读取 public_conf 配置文件
|
|
||||||
h := viper.Get("storage.host")
|
|
||||||
require.Equal(t, h, "127.0.0.1")
|
|
||||||
|
|
||||||
h = viper.Get("env")
|
|
||||||
require.Equal(t, h, "dev")
|
|
||||||
|
|
||||||
// set 使用
|
|
||||||
viper.Set("host", "1222")
|
|
||||||
host := viper.GetString("host")
|
|
||||||
require.Equal(t, host, "1222")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMiddleConf(t *testing.T) {
|
|
||||||
ct := viper.GetStringSlice("plugins-control.logcontext")
|
|
||||||
require.Equal(t, ct, []string{"logMiddle"})
|
|
||||||
|
|
||||||
d := viper.GetInt("middleware-driver.driverCount")
|
|
||||||
require.Equal(t, d, 1000)
|
|
||||||
c := viper.GetInt("middleware-driver.middleConsumerCount")
|
|
||||||
require.Equal(t, c, 5)
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package conf
|
|
||||||
|
|
||||||
import "github.com/spf13/viper"
|
|
||||||
|
|
||||||
func defaultStorage() {
|
|
||||||
// aof
|
|
||||||
viper.SetDefault("storage.aof-path", "/etc/wheat-cache/wheat.aof")
|
|
||||||
viper.SetDefault("storage.aof-flush-time", 5)
|
|
||||||
viper.SetDefault("storage.aof-check-time", 1)
|
|
||||||
viper.SetDefault("storage.aof-check-freq", 20)
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
version: 'v1.0'
|
|
||||||
|
|
||||||
env: 'dev'
|
|
||||||
|
|
||||||
storage:
|
|
||||||
host: '0.0.0.0'
|
|
||||||
port: 5890
|
|
||||||
timeOut: 2 # second
|
|
||||||
|
|
||||||
aof-codec: "b16" # 目前只实现了 b16 编码方案。
|
|
||||||
aof-path: "/etc/wheat-cache/wheat.aof"
|
|
||||||
aof-flush-time: 5 # second , 每 5 秒刷新缓冲区的内容到磁盘。
|
|
||||||
aof-check-time: 1 # 每 1 second 执行一次 io 检查
|
|
||||||
aof-check-freq: 20 # 在一个 aof-check-time 周期内,出现超过 aof-check-freq 的 IO 操作会刷新磁盘
|
|
||||||
|
|
||||||
|
|
||||||
# clearSize and maxSize must be Int
|
|
||||||
lruCache:
|
|
||||||
clearSize: "512mb"
|
|
||||||
maxSize: "1GB"
|
|
||||||
eventDriverSize: 2000
|
|
||||||
workTime: 1
|
|
||||||
detachNum: 300
|
|
||||||
|
|
||||||
|
|
||||||
logPrint:
|
|
||||||
stath: ["error"]
|
|
||||||
|
|
||||||
|
|
||||||
middleware-driver:
|
|
||||||
driverCount: 1000
|
|
||||||
middleConsumerCount: 5
|
|
||||||
|
|
||||||
# Register the message push type
|
|
||||||
# 在这里注册消息推送类型,
|
|
||||||
plugins-control:
|
|
||||||
|
|
||||||
# log-context: Logs generated by storage or gateway are pushed through this message
|
|
||||||
# log-context: storage 或者 gateway 产生的日志通过这个消息推送
|
|
||||||
log-context: [ "mock-plugins" ]
|
|
||||||
|
|
||||||
# lru-clean-context: Lru is pushed through this message when data cleansing occurs
|
|
||||||
# lru-clean-context: Lru 发生数据清理时通过这个消息推送
|
|
||||||
lru-clean-context: ["mock-plugins"]
|
|
||||||
|
|
||||||
# lru-ttl-context: Lru is pushed through this message when data expires
|
|
||||||
# lru-ttl-context: Lru 发生数据过期时通过这个消息推送
|
|
||||||
lru-ttl-context: ["mock-plugins"]
|
|
||||||
|
|
||||||
# plugins-info-context:All plugins information for the current project
|
|
||||||
# plugins-info-context: 当前项目全部的插件信息
|
|
||||||
plugins-infos-context: ["mock-plugins"]
|
|
||||||
|
|
||||||
gateway:
|
|
||||||
host: '0.0.0.0'
|
|
||||||
port: 5891
|
|
||||||
target: ["127.0.0.1:5890"]
|
|
||||||
|
|
||||||
mock-plugin:
|
|
||||||
pprof-addr: "127.0.0.1:8000"
|
|
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="94" height="20" role="img" aria-label="license: AFL3.0"><title>license: AFL3.0</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="94" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="47" height="20" fill="#555"/><rect x="47" width="47" height="20" fill="#97ca00"/><rect width="94" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="245" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">license</text><text x="245" y="140" transform="scale(.1)" fill="#fff" textLength="370">license</text><text aria-hidden="true" x="695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">AFL3.0</text><text x="695" y="140" transform="scale(.1)" fill="#fff" textLength="370">AFL3.0</text></g></svg>
|
|
Before Width: | Height: | Size: 1.1 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 37 KiB |
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="88" height="20" role="img" aria-label="Wheat: Cache"><title>Wheat: Cache</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="88" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="45" height="20" fill="#555"/><rect x="45" width="43" height="20" fill="#a4a61d"/><rect width="88" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="235" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">Wheat</text><text x="235" y="140" transform="scale(.1)" fill="#fff" textLength="350">Wheat</text><text aria-hidden="true" x="655" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="330">Cache</text><text x="655" y="140" transform="scale(.1)" fill="#fff" textLength="330">Cache</text></g></svg>
|
|
Before Width: | Height: | Size: 1.1 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 13 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 8.9 KiB |
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86" height="20" role="img" aria-label="version: v1.1"><title>version: v1.1</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="86" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="51" height="20" fill="#555"/><rect x="51" width="35" height="20" fill="#007ec6"/><rect width="86" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">version</text><text x="265" y="140" transform="scale(.1)" fill="#fff" textLength="410">version</text><text aria-hidden="true" x="675" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="250">v1.1</text><text x="675" y="140" transform="scale(.1)" fill="#fff" textLength="250">v1.1</text></g></svg>
|
|
Before Width: | Height: | Size: 1.1 KiB |
|
@ -1,11 +0,0 @@
|
||||||
### Cache 分布式方案-Getway
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
![getway方案](https://gitee.com/timedb/img/raw/master/images/getway方案.svg)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1. single 集群分布式方案中,使用 getway 方向代理客户端的 grpc 请求, 通过 hash 环实现 分布式。
|
|
||||||
2. 集群模式中, 通过主从来 实现 cache 的备份问题,提高容灾性。
|
|
||||||
|
|
32
doc/make.md
32
doc/make.md
|
@ -1,32 +0,0 @@
|
||||||
### 构建工具文档
|
|
||||||
|
|
||||||
#### dcgen
|
|
||||||
1. 根据结构体接口模板生成 proto 文件
|
|
||||||
2. 迁移 proto 到 pkg/proto 下
|
|
||||||
3. 更新结构体常量
|
|
||||||
|
|
||||||
>PS : 开发一个 storage 的新接口时一般有以下步骤
|
|
||||||
>1. 修改 storage 接口配置文件
|
|
||||||
>2. make dcgen
|
|
||||||
>3. 修改生成的 proto 文件
|
|
||||||
>4. make dcgen
|
|
||||||
>5. 添加 storage 的操作接口
|
|
||||||
|
|
||||||
|
|
||||||
#### build-storage
|
|
||||||
编译并且生成 /bin/storage
|
|
||||||
|
|
||||||
#### build-gateway
|
|
||||||
编译并且生成 /bin/gateway
|
|
||||||
|
|
||||||
#### install
|
|
||||||
1. 安装项目,需要 sudo
|
|
||||||
|
|
||||||
#### storage
|
|
||||||
根据配置文件启动 storage
|
|
||||||
|
|
||||||
#### gateway
|
|
||||||
根据配置文件启动 gateway
|
|
||||||
|
|
||||||
#### init-conf
|
|
||||||
根据配置文件文档初始化配置文件到 /etc/wheat-cache/wheat-cache.yaml
|
|
|
@ -1,13 +0,0 @@
|
||||||
### 事件驱动 2.0
|
|
||||||
|
|
||||||
### event 1.0 存在的问题
|
|
||||||
事件驱动 1.0 在 相互关联访问时,会发生 死锁问题, 导致一个事件执行周期失败
|
|
||||||
|
|
||||||
### event 2.0 新特性
|
|
||||||
- 异步事件支持
|
|
||||||
- 挂起操作
|
|
||||||
|
|
||||||
|
|
||||||
### event 2.0 设计图
|
|
||||||
![](../../_icon/event.svg)
|
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
### 事件驱动使用文档
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- 包目录: pkg/event
|
|
||||||
- 使用场景, 异步推送数据
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 事件驱动基本概念
|
|
||||||
|
|
||||||
- event
|
|
||||||
|
|
||||||
event 是事件驱动的事件部分, 主要负责一些信息的传递, 一共分为,有等待和无等待的事件, 无等待事件 consumer 消费事件后,不会给 produce 回复, 有等待事件, 支持事件消费后, 向 produce 发送一个回复。
|
|
||||||
|
|
||||||
- driver
|
|
||||||
|
|
||||||
driver 是事件的驱动, 主要复制连接 produce, 以及 consumer, 其中维护了一个 event 的队列。
|
|
||||||
|
|
||||||
- produce
|
|
||||||
|
|
||||||
produce 主要负责 推送 事件, 每个 produce 都需要维护一个 事件驱动通过 driver 来进行数据的推送。
|
|
||||||
|
|
||||||
- consumer
|
|
||||||
|
|
||||||
consumer 负责接收事件, 每个 consumer 都需要注册一个 事件驱动 来获取 event。
|
|
||||||
|
|
||||||
####
|
|
||||||
|
|
||||||
#### 应用场景
|
|
||||||
|
|
||||||
事件驱动主要用于 异步消息的推送(目前的实现也支持 同步的消息实现), 一般来说 produce 发送 event 后 event 被消费过程会完全于 produce 无关。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 无返回 event 使用例子
|
|
||||||
|
|
||||||
我们使用 借书为例子使用, 假设 A 要把 书 S 交还给 B, 他们约定, A 把书 S 放到图书馆, B 在空闲时去图书馆取出书 S。
|
|
||||||
|
|
||||||
```go
|
|
||||||
func TestNewConsumer(t *testing.T) {
|
|
||||||
// 定义一个图书馆
|
|
||||||
type Library struct {
|
|
||||||
driver DriverInterface
|
|
||||||
}
|
|
||||||
library := &Library{
|
|
||||||
driver: NewDriver(100),
|
|
||||||
}
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// 定义 A
|
|
||||||
type A struct {
|
|
||||||
produce ProduceInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
a := &A{
|
|
||||||
produce: NewProduce(library.driver),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义 B
|
|
||||||
type B struct {
|
|
||||||
consumer ConsumerInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
b := &B{
|
|
||||||
consumer: NewConsumer(library.driver),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义书 S 并且添加一些描述
|
|
||||||
book := NewEvent("S")
|
|
||||||
book.SetMsg("title", "hello world")
|
|
||||||
book.SetCtxValue("pages", 120)
|
|
||||||
|
|
||||||
// A 把书 S 放到图书馆
|
|
||||||
go func() {
|
|
||||||
a.produce.Call(ctx, book)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 模拟 B 去图书馆拿书
|
|
||||||
book = b.consumer.Receive(ctx)
|
|
||||||
fmt.Println(book.GetMsg("title"))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 有返回event的使用例子
|
|
||||||
|
|
||||||
在上述流程的情景下, 我们添加一些条件, B 拿到书以后检查书是否损坏,如果损坏, 需要告诉 A 书损坏情况。
|
|
||||||
|
|
||||||
```go
|
|
||||||
func TestNewConsumer(t *testing.T) {
|
|
||||||
// 定义一个图书馆
|
|
||||||
type Library struct {
|
|
||||||
driver DriverInterface
|
|
||||||
}
|
|
||||||
library := &Library{
|
|
||||||
driver: NewDriver(100),
|
|
||||||
}
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// 定义 A
|
|
||||||
type A struct {
|
|
||||||
produce ProduceInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
a := &A{
|
|
||||||
produce: NewProduce(library.driver),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义 B
|
|
||||||
type B struct {
|
|
||||||
consumer ConsumerInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
b := &B{
|
|
||||||
consumer: NewConsumer(library.driver),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定义书 S 并且添加一些描述
|
|
||||||
book := NewEvent("S")
|
|
||||||
book.SetMsg("title", "hello world")
|
|
||||||
book.SetValue("pages", 120)
|
|
||||||
|
|
||||||
// A 把书 S 放到图书馆
|
|
||||||
go func() {
|
|
||||||
book.InitWaitEvent()
|
|
||||||
a.produce.Call(ctx, book)
|
|
||||||
|
|
||||||
// A 等待 B 的回复, 但是他最多只会等待 B 2个小时
|
|
||||||
res, err := book.StartWaitEvent(2 * time.Hour)
|
|
||||||
require.NoError(t, err)
|
|
||||||
fmt.Println(res)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 模拟 B 去图书馆拿书
|
|
||||||
book = b.consumer.Receive(ctx)
|
|
||||||
fmt.Println(book.GetMsg("title"))
|
|
||||||
|
|
||||||
// 书完好
|
|
||||||
book.ExecWorkAndSendResult(func() (interface{}, error) {
|
|
||||||
// b 检查书
|
|
||||||
return "OK", nil
|
|
||||||
})
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
![](https://gitee.com/HuangJiaLuo/imgbed/raw/master/LRUdesign.svg)
|
|
||||||
|
|
||||||
EventP : 生产事件
|
|
||||||
|
|
||||||
EventQ : 事件队列
|
|
||||||
|
|
||||||
Event CP : 清理事件
|
|
|
@ -1,5 +0,0 @@
|
||||||
### RDB + AOF 的事务解决方案
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
![事务RDB方案](https://gitee.com/timedb/img/raw/master/images/事务RDB方案.svg)
|
|
|
@ -1,47 +0,0 @@
|
||||||
### 中间件调用
|
|
||||||
|
|
||||||
|
|
||||||
### 创建事件
|
|
||||||
|
|
||||||
event := event.NewEvent("logcontext")
|
|
||||||
|
|
||||||
|
|
||||||
### 创建驱动
|
|
||||||
|
|
||||||
middleware := NewMiddleWare()
|
|
||||||
|
|
||||||
### 将事件推入驱动
|
|
||||||
|
|
||||||
middleware.eventProduce.Call(ctx, event)
|
|
||||||
|
|
||||||
|
|
||||||
### 获取驱动的事件
|
|
||||||
middleware.eventConsumer.Reciver(ctx)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 插件接口
|
|
||||||
type MiddleToolsInterface interface {
|
|
||||||
Init() // 初始化
|
|
||||||
Exec(interface{}) (interface{}, error) // 处理用户发送事件
|
|
||||||
Name() string // 获取中间件名称
|
|
||||||
Describe() string // 描述
|
|
||||||
}
|
|
||||||
|
|
||||||
### 插件的New方法规定为 NewMiddleWare()
|
|
||||||
每个插件都要定义 NewMiddleWare()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 将插件名 “logMiddle” 注册到配置文件wheat-cache.yaml,其他插件注册
|
|
||||||
plugins-control:
|
|
||||||
logcontext: ["logMiddle"]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
### 结构体开发文档
|
|
||||||
|
|
||||||
#### 基础结构体开发
|
|
||||||
|
|
||||||
- 基础结构体放到 /pkg/structure。
|
|
||||||
|
|
||||||
- 每个结构 类型都以 x 结尾,如 listx, stringx。
|
|
||||||
|
|
||||||
- 在 pkg/structure/define.go 文件中添加对应结构体的接口,主要为 了保证项目可以扩展线程安全结构体, 以及结构体接口的实现, 目前 lru 采用 single 模式, 可以只开发 single 的结构体,如 stringxSingle。
|
|
||||||
|
|
||||||
- 请在结构体包中 补充单元测试。
|
|
||||||
|
|
||||||
#### 目前实现结构体接口说明
|
|
||||||
|
|
||||||
> ps: 所有的详细用法都可以查看单元测试文件。
|
|
||||||
|
|
||||||
```go
|
|
||||||
// stringx
|
|
||||||
type StringXInterface interface {
|
|
||||||
KeyBaseInterface
|
|
||||||
// 重新设置一个 值
|
|
||||||
Set(string) (string, UpdateLength)
|
|
||||||
// 获取值的 string 形式
|
|
||||||
Get() string
|
|
||||||
// 值自动增加 一个值,只对 float 和 string 有效
|
|
||||||
Add(int32) (string, error)
|
|
||||||
// 值自动增加 减少值,只对 float 和 string 有效
|
|
||||||
Reduce(int32) (string, error)
|
|
||||||
// 使用位图类型
|
|
||||||
Setbit(int32, bool) UpdateLength
|
|
||||||
Getbit(int32) (bool, error)
|
|
||||||
// 获取字符串的切片
|
|
||||||
Getrange(start, end int32) (string, error)
|
|
||||||
GetLength() int
|
|
||||||
}
|
|
||||||
|
|
||||||
// listx
|
|
||||||
type ListXInterface interface {
|
|
||||||
KeyBaseInterface
|
|
||||||
LPush(...string) UpdateLength
|
|
||||||
RPush(...string) UpdateLength
|
|
||||||
LPop(int) ([]string, UpdateLength)
|
|
||||||
RPop(int) ([]string, UpdateLength)
|
|
||||||
Index(int) (string, error)
|
|
||||||
// 插入一组数据, bool 类型表示是否右插(尾插),false 时采用左插(头插)
|
|
||||||
Insert(int, bool, ...string) (UpdateLength, error)
|
|
||||||
Length() int
|
|
||||||
// 切片, O(n)复杂度
|
|
||||||
Slice(start, end int) (UpdateLength, error)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### structure.Value 类型
|
|
||||||
- 结构体的数据区域全部使用 structure.Value 类型存储。
|
|
||||||
- structure.Value 主要实现了 sting, int64, float64 的存储接口。
|
|
||||||
- structure.Value 非常容易计算内存占用。
|
|
||||||
- structure.UpdateLength 指的是在进行某一个操作以后,内存大小的变化。
|
|
||||||
- 为了保证 lru 的存储效率,lru 不会去遍历全部的 key 来重新计算大小,而是根据 UpdateLength 来动态更新 lru 的大小,具体实现在 dao 中。
|
|
||||||
- structure.Value 类型的使用方法可以在 pkg/structure/value_test.go 中获取。
|
|
|
@ -1,46 +0,0 @@
|
||||||
### 快速进行 storage 开发
|
|
||||||
|
|
||||||
#### 开发环境
|
|
||||||
- ubuntu18, 可以使用 wsl
|
|
||||||
- go1.15+, python3
|
|
||||||
- jinja2
|
|
||||||
- go mod
|
|
||||||
- protobuf 3.17.3
|
|
||||||
- protoc-gen-go v1.26.0
|
|
||||||
|
|
||||||
#### storage 执行流程
|
|
||||||
![](../_icon/storage-dao.svg)
|
|
||||||
#### 分层,简介
|
|
||||||
```sh
|
|
||||||
.
|
|
||||||
├── cmd # storage 启动函数
|
|
||||||
│ └── root.go
|
|
||||||
├── dao # 实际处理层,接口实现全部再 dao 层里实现
|
|
||||||
│ ├── dao.go
|
|
||||||
│ ├── dao_test.go
|
|
||||||
│ ├── interface.gen.go
|
|
||||||
│ ├── listx.go # listx 相关功能
|
|
||||||
│ └── stringx.go
|
|
||||||
├── main.go
|
|
||||||
├── service # 接口层,由 gen-service 自动生成
|
|
||||||
│ ├── define.go
|
|
||||||
│ ├── single.go
|
|
||||||
│ └── single_service.gen.go
|
|
||||||
└── temp # 开发模板层
|
|
||||||
├── const.gen.go
|
|
||||||
├── const.template
|
|
||||||
├── dao.template
|
|
||||||
├── service.template
|
|
||||||
└── tem.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 快速开发接口
|
|
||||||
|
|
||||||
> [快速开发视频 blibli](https://www.bilibili.com/video/BV1HL4y1v7ps)
|
|
||||||
|
|
||||||
1. 修改 temp/tem.yaml 文件,添加新接口
|
|
||||||
2. 在项目根目录执行 `make dcgen` 生成 proto 原始结构
|
|
||||||
3. 修改对应新添加接口的 proto 文件,再次执行 `make dcgen` 完成 proto 迁移
|
|
||||||
4. 执行 `make gen-service` 生成 dao 接口
|
|
||||||
5. 完成 新 dao 层接口, 根据需要添加单元测试。
|
|
||||||
6. 使用 make install 编译并且安装项目
|
|
|
@ -1,6 +0,0 @@
|
||||||
### 前端技术选择
|
|
||||||
- react框架
|
|
||||||
- 组件(antd或React-bootstrap或其他css组件)
|
|
||||||
- 图表库(BizCharts)
|
|
||||||
- protobufjs
|
|
||||||
- grafana
|
|
|
@ -1,54 +0,0 @@
|
||||||
### 单元测试文档
|
|
||||||
|
|
||||||
#### 样例
|
|
||||||
```go
|
|
||||||
package dao
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/lru"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 规范1. 每个 package 应该都至少有一个单测
|
|
||||||
|
|
||||||
// 规范2. 包里有公用的 mock 数据应该分离出来。
|
|
||||||
func mockData(t *testing.T, d *Dao) {
|
|
||||||
|
|
||||||
values := []string{"1", "1.3", "abcdefg"}
|
|
||||||
|
|
||||||
for _, val := range values {
|
|
||||||
key := &proto.BaseKey{
|
|
||||||
Key: val,
|
|
||||||
}
|
|
||||||
_, err := d.Set(key, val)
|
|
||||||
|
|
||||||
// 规范3. 使用 require 包来完成单测
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 规范4. 单元测试应该尽可能覆盖全部情况,不要使用依赖注入。
|
|
||||||
func TestDao_Reduce(t *testing.T) {
|
|
||||||
lruCache := lru.NewLRUCache()
|
|
||||||
dao := NewDao(lruCache)
|
|
||||||
mockData(t, dao)
|
|
||||||
|
|
||||||
resp, err := dao.Reduce(&proto.BaseKey{Key: "1"}, 2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, resp, "-1")
|
|
||||||
|
|
||||||
resp, err = dao.Reduce(&proto.BaseKey{Key: "1.3"}, 2)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, resp, "-0.70")
|
|
||||||
|
|
||||||
_, err = dao.Reduce(&proto.BaseKey{Key: "abcdefg"}, 2)
|
|
||||||
require.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
|
@ -1,69 +0,0 @@
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
|
||||||
wheatCodec "gitee.com/wheat-os/wheatCache/gateway/codec"
|
|
||||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
|
||||||
"gitee.com/wheat-os/wheatCache/gateway/proxy"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/util/server"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// rootCmd represents the base command when called without any subcommands
|
|
||||||
var rootCmd = &cobra.Command{
|
|
||||||
Use: "getway",
|
|
||||||
Short: "getway",
|
|
||||||
Long: `start getway server`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
host := viper.GetString("gateway.host")
|
|
||||||
port := viper.GetInt("gateway.port")
|
|
||||||
|
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
|
|
||||||
if err != nil {
|
|
||||||
logx.Panic("get gateway addr err:%v", err)
|
|
||||||
}
|
|
||||||
listen, err := net.ListenTCP("tcp", tcpAddr)
|
|
||||||
if err != nil {
|
|
||||||
logx.Panic("get gateway tcp conn err:%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
gatewayServer := GetGatewayServer()
|
|
||||||
server.ElegantExitServer(gatewayServer)
|
|
||||||
|
|
||||||
logx.Info("start gateway in addr: %s", tcpAddr.String())
|
|
||||||
if err := gatewayServer.Serve(listen); err != nil {
|
|
||||||
logx.Errorln(err)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
|
||||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
|
||||||
func Execute() {
|
|
||||||
cobra.CheckErr(rootCmd.Execute())
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGatewayServer() *grpc.Server {
|
|
||||||
|
|
||||||
targets := viper.GetStringSlice("gateway.target")
|
|
||||||
|
|
||||||
logx.Debug("service target in %v", targets)
|
|
||||||
|
|
||||||
stream := proxy.GetDirectorByServiceHash()
|
|
||||||
endpoint := endpoint.NewHashEndpoint(endpoint.HashReplicasDefault, nil, targets...)
|
|
||||||
|
|
||||||
opts := make([]grpc.ServerOption, 0)
|
|
||||||
opts = append(
|
|
||||||
opts,
|
|
||||||
grpc.ForceServerCodec(wheatCodec.Codec()),
|
|
||||||
grpc.UnknownServiceHandler(proxy.TransparentHandler(stream, endpoint)),
|
|
||||||
)
|
|
||||||
|
|
||||||
return grpc.NewServer(opts...)
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
package codec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"google.golang.org/grpc/encoding"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
// protoCodec 用于 gateway 解析全部的 grpc 类型的消息
|
|
||||||
type protoCodec struct{}
|
|
||||||
|
|
||||||
func (protoCodec) Name() string {
|
|
||||||
return "wheat-cache-proto"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
|
||||||
return proto.Marshal(v.(proto.Message))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
|
|
||||||
return proto.Unmarshal(data, v.(proto.Message))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Frame struct {
|
|
||||||
payload []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type proxyCodec struct {
|
|
||||||
baseCodec encoding.Codec
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *proxyCodec) Name() string {
|
|
||||||
return "wheat-cache-proxy"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *proxyCodec) Marshal(v interface{}) ([]byte, error) {
|
|
||||||
out, ok := v.(*Frame)
|
|
||||||
if !ok {
|
|
||||||
return p.Marshal(v)
|
|
||||||
}
|
|
||||||
return out.payload, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *proxyCodec) Unmarshal(data []byte, v interface{}) error {
|
|
||||||
dst, ok := v.(*Frame)
|
|
||||||
if !ok {
|
|
||||||
return p.Unmarshal(data, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
dst.payload = data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CodeWithParent 生成基于 proto 的解码器
|
|
||||||
func CodeWithParent(parent encoding.Codec) encoding.Codec {
|
|
||||||
return &proxyCodec{parent}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Codec() encoding.Codec {
|
|
||||||
return CodeWithParent(protoCodec{})
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package endpoint
|
|
||||||
|
|
||||||
type EndpointInterface interface {
|
|
||||||
GetTargetAddr(...string) (string, error)
|
|
||||||
IsEmpty() bool
|
|
||||||
AddTarget(targets ...string)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
HashReplicasDefault = 3
|
|
||||||
)
|
|
|
@ -1,85 +0,0 @@
|
||||||
package endpoint
|
|
||||||
|
|
||||||
import (
|
|
||||||
"hash/crc32"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HashFunc func(data []byte) uint32
|
|
||||||
|
|
||||||
// 实现 sort
|
|
||||||
type UInt32Slice []uint32
|
|
||||||
|
|
||||||
func (s UInt32Slice) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s UInt32Slice) Less(i, j int) bool {
|
|
||||||
return s[i] < s[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s UInt32Slice) Swap(i, j int) {
|
|
||||||
s[i], s[j] = s[j], s[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
type HashEndpoint struct {
|
|
||||||
hash HashFunc
|
|
||||||
replicas int // 复制因子
|
|
||||||
keys UInt32Slice
|
|
||||||
hashMap map[uint32]string // taraget 隐射
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHashEndpoint(replicas int, fn HashFunc, target ...string) EndpointInterface {
|
|
||||||
endpoint := &HashEndpoint{
|
|
||||||
replicas: replicas,
|
|
||||||
hash: fn,
|
|
||||||
hashMap: make(map[uint32]string, len(target)),
|
|
||||||
}
|
|
||||||
|
|
||||||
if endpoint.hash == nil {
|
|
||||||
endpoint.hash = crc32.ChecksumIEEE // 默认使用 CRC32 算法
|
|
||||||
}
|
|
||||||
|
|
||||||
endpoint.AddTarget(target...)
|
|
||||||
|
|
||||||
return endpoint
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HashEndpoint) IsEmpty() bool {
|
|
||||||
return len(h.keys) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HashEndpoint) AddTarget(targets ...string) {
|
|
||||||
for _, tar := range targets {
|
|
||||||
|
|
||||||
for i := 0; i < h.replicas; i++ {
|
|
||||||
hash := h.hash([]byte(strconv.Itoa(i) + tar))
|
|
||||||
h.keys = append(h.keys, hash)
|
|
||||||
h.hashMap[hash] = tar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 虚拟值排序,方便查找
|
|
||||||
sort.Sort(h.keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HashEndpoint) GetTargetAddr(str ...string) (string, error) {
|
|
||||||
if h.IsEmpty() {
|
|
||||||
return "", errorx.New("gateway not register transport")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(str) != 1 {
|
|
||||||
return "", errorx.New("must give key")
|
|
||||||
|
|
||||||
}
|
|
||||||
hash := h.hash([]byte(str[0]))
|
|
||||||
idx := sort.Search(len(h.keys), func(i int) bool { return h.keys[i] >= hash })
|
|
||||||
if idx == len(h.keys) {
|
|
||||||
return h.hashMap[h.keys[0]], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.hashMap[h.keys[idx]], nil
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package endpoint
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestHashTransport_GetTargetAddr(t *testing.T) {
|
|
||||||
tran := NewHashEndpoint(3, nil, "127.0.0.1:5581", "127.0.0.1:5582", "127.0.0.1:5583")
|
|
||||||
|
|
||||||
key := "test"
|
|
||||||
|
|
||||||
target, err := tran.GetTargetAddr(key)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, target, "127.0.0.1:5582")
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import "gitee.com/wheat-os/wheatCache/gateway/cmd"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
cmd.Execute()
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StreamDirector func(ctx context.Context, fullMethodName string, endpoint endpoint.EndpointInterface) (context.Context, *grpc.ClientConn, error)
|
|
||||||
|
|
||||||
var (
|
|
||||||
clientStreamDescForProxying = &grpc.StreamDesc{
|
|
||||||
ServerStreams: true,
|
|
||||||
ClientStreams: true,
|
|
||||||
}
|
|
||||||
)
|
|
|
@ -1,37 +0,0 @@
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/gateway/codec"
|
|
||||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/metadata"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetDirectorByServiceHash() StreamDirector {
|
|
||||||
return func(ctx context.Context, fullMethodName string, endpoint endpoint.EndpointInterface) (context.Context, *grpc.ClientConn, error) {
|
|
||||||
|
|
||||||
md, ok := metadata.FromIncomingContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
return nil, nil, status.Errorf(codes.Unknown, "from FromIncomingContext err")
|
|
||||||
}
|
|
||||||
|
|
||||||
baseKey, ok := md[proto.BaseKeyMethodKey]
|
|
||||||
if !ok {
|
|
||||||
return nil, nil, status.Errorf(codes.Unknown,
|
|
||||||
"grpc header is not found %s, please check the client interceptor", proto.BaseKeyMethodKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
target, err := endpoint.GetTargetAddr(baseKey...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, status.Errorf(codes.Unknown, "get transport err, err:%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cli, err := grpc.DialContext(ctx, target, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.Codec())))
|
|
||||||
return ctx, cli, err
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,131 +0,0 @@
|
||||||
package proxy
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
wheatCodec "gitee.com/wheat-os/wheatCache/gateway/codec"
|
|
||||||
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TransparentHandler returns a handler that attempts to proxy all requests that are not registered in the server.
|
|
||||||
// The indented use here is as a transparent proxy, where the server doesn't know about the services implemented by the
|
|
||||||
// backends. It should be used as a `grpc.UnknownServiceHandler`.
|
|
||||||
//
|
|
||||||
// This can *only* be used if the `server` also uses grpcproxy.CodecForServer() ServerOption.
|
|
||||||
func TransparentHandler(director StreamDirector, endpoint endpoint.EndpointInterface) grpc.StreamHandler {
|
|
||||||
streamer := &handler{
|
|
||||||
director,
|
|
||||||
endpoint,
|
|
||||||
}
|
|
||||||
return streamer.handler
|
|
||||||
}
|
|
||||||
|
|
||||||
type handler struct {
|
|
||||||
director StreamDirector
|
|
||||||
endpoint endpoint.EndpointInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
// handler is where the real magic of proxying happens.
|
|
||||||
// It is invoked like any gRPC server stream and uses the gRPC server framing to get and receive bytes from the wire,
|
|
||||||
// forwarding it to a ClientStream established against the relevant ClientConn.
|
|
||||||
func (s *handler) handler(srv interface{}, serverStream grpc.ServerStream) error {
|
|
||||||
fullMethodName, ok := grpc.MethodFromServerStream(serverStream)
|
|
||||||
if !ok {
|
|
||||||
return status.Errorf(codes.Internal, "lowLevelServerStream not exists in context")
|
|
||||||
}
|
|
||||||
|
|
||||||
outgoingCtx, backendConn, err := s.director(serverStream.Context(), fullMethodName, s.endpoint)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
clientCtx, clientCancel := context.WithCancel(outgoingCtx)
|
|
||||||
defer clientCancel()
|
|
||||||
|
|
||||||
clientStream, err := grpc.NewClientStream(clientCtx, clientStreamDescForProxying, backendConn, fullMethodName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
s2cErrChan := s.forwardServerToClient(serverStream, clientStream)
|
|
||||||
c2sErrChan := s.forwardClientToServer(clientStream, serverStream)
|
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
select {
|
|
||||||
case s2cErr := <-s2cErrChan:
|
|
||||||
if s2cErr == io.EOF {
|
|
||||||
// 客户端流发送完毕正常关闭结束, Proxy 关闭对 Backend 的连接
|
|
||||||
clientStream.CloseSend()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
clientCancel()
|
|
||||||
return status.Errorf(codes.Internal, "failed proxying s2c: %v", s2cErr)
|
|
||||||
case c2sErr := <-c2sErrChan:
|
|
||||||
// 服务的没用在提供数据触发这个分支
|
|
||||||
serverStream.SetTrailer(clientStream.Trailer())
|
|
||||||
|
|
||||||
if c2sErr != io.EOF {
|
|
||||||
return c2sErr
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status.Errorf(codes.Internal, "gRPC proxying should never reach this stage.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *handler) forwardClientToServer(src grpc.ClientStream, dst grpc.ServerStream) chan error {
|
|
||||||
ret := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
f := &wheatCodec.Frame{}
|
|
||||||
for i := 0; ; i++ {
|
|
||||||
if err := src.RecvMsg(f); err != nil {
|
|
||||||
ret <- err // this can be io.EOF which is happy case
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if i == 0 {
|
|
||||||
// This is a bit of a hack, but client to server headers are only readable after first client msg is
|
|
||||||
// received but must be written to server stream before the first msg is flushed.
|
|
||||||
// This is the only place to do it nicely.
|
|
||||||
md, err := src.Header()
|
|
||||||
if err != nil {
|
|
||||||
ret <- err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err := dst.SendHeader(md); err != nil {
|
|
||||||
ret <- err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := dst.SendMsg(f); err != nil {
|
|
||||||
ret <- err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *handler) forwardServerToClient(src grpc.ServerStream, dst grpc.ClientStream) chan error {
|
|
||||||
ret := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
f := &wheatCodec.Frame{}
|
|
||||||
for i := 0; ; i++ {
|
|
||||||
if err := src.RecvMsg(f); err != nil {
|
|
||||||
ret <- err // this can be io.EOF which is happy case
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if err := dst.SendMsg(f); err != nil {
|
|
||||||
ret <- err
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return ret
|
|
||||||
}
|
|
6
go.mod
6
go.mod
|
@ -1,12 +1,8 @@
|
||||||
module gitee.com/wheat-os/wheatCache
|
module gitee.com/timedb/wheatCache
|
||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/mock v1.5.0
|
|
||||||
github.com/spf13/cobra v1.2.1
|
github.com/spf13/cobra v1.2.1
|
||||||
github.com/spf13/viper v1.8.1
|
github.com/spf13/viper v1.8.1
|
||||||
github.com/stretchr/testify v1.7.0
|
|
||||||
google.golang.org/grpc v1.41.0
|
|
||||||
google.golang.org/protobuf v1.26.0
|
|
||||||
)
|
)
|
||||||
|
|
13
go.sum
13
go.sum
|
@ -46,7 +46,6 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
|
@ -54,7 +53,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
@ -67,7 +65,6 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
@ -89,7 +86,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||||
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
|
|
||||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
@ -107,7 +103,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
@ -121,7 +116,6 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
@ -256,7 +250,6 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
|
@ -337,7 +330,6 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -470,7 +462,6 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
@ -541,7 +532,6 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D
|
||||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
@ -563,8 +553,6 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
|
||||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
@ -576,7 +564,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
|
|
58
makefile
58
makefile
|
@ -1,58 +0,0 @@
|
||||||
BASE_PATH = $(shell pwd)
|
|
||||||
STORAGE_PATH = $(BASE_PATH)/storage
|
|
||||||
BASE_OUT = $(BASE_PATH)/bin
|
|
||||||
|
|
||||||
MAKEFLAGS+= --no-print-directory
|
|
||||||
|
|
||||||
dcgen:
|
|
||||||
@python3 ./shell/gen_protobuf.py
|
|
||||||
@python3 ./shell/proto.py
|
|
||||||
@python3 ./shell/make-struct.py
|
|
||||||
|
|
||||||
.PHONY: build-storage
|
|
||||||
build-storage:
|
|
||||||
@cd storage && go build -o $(BASE_OUT)/storage
|
|
||||||
|
|
||||||
.PHONY: build-gateway
|
|
||||||
build-gateway:
|
|
||||||
@cd gateway && go build -o $(BASE_OUT)/gateway
|
|
||||||
|
|
||||||
.PHONY: install
|
|
||||||
install:
|
|
||||||
@make gen-middleware
|
|
||||||
@make build-storage
|
|
||||||
@make build-gateway
|
|
||||||
@sudo python3 ./shell/init_conf.py
|
|
||||||
|
|
||||||
.PHONY: storage
|
|
||||||
storage:
|
|
||||||
@./bin/storage storage
|
|
||||||
|
|
||||||
.PHONY: gateway
|
|
||||||
gateway:
|
|
||||||
@./bin/gateway gateway
|
|
||||||
|
|
||||||
.PHONY: gen-struct
|
|
||||||
gen-struct:
|
|
||||||
@python3 ./shell/make-struct.py
|
|
||||||
|
|
||||||
.PHONY: gen-protobuf
|
|
||||||
gen-protobuf:
|
|
||||||
@python3 ./shell/gen_protobuf.py
|
|
||||||
|
|
||||||
.PHONY: gen-middleware
|
|
||||||
gen-middleware:
|
|
||||||
@python3 ./shell/gen_middleware.py
|
|
||||||
|
|
||||||
.PHONY: init-conf
|
|
||||||
init-conf:
|
|
||||||
@python3 ./shell/init_conf.py
|
|
||||||
|
|
||||||
|
|
||||||
.PHONY: gen-service
|
|
||||||
gen-service:
|
|
||||||
@python3 ./shell/make_service.py
|
|
||||||
|
|
||||||
.PHONY: gen-mock
|
|
||||||
gen-mock:
|
|
||||||
@mockgen -source=./pkg/proto/storage.pb.go CommServerClient > ./mock/storage/mock_client.gen.go
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +0,0 @@
|
||||||
package errorx
|
|
||||||
|
|
||||||
func DaoTypeErr(typ string) error {
|
|
||||||
return New("the type is not: %s", typ)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NotKeyErr(key string) error {
|
|
||||||
return New("the key is not exist, key:%s", key)
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package errorx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// New TODO 添加链路追踪等 @bandl @lgq
|
|
||||||
func New(msg string, format ...interface{}) error {
|
|
||||||
msg = fmt.Sprintf(msg, format...)
|
|
||||||
return errors.New(msg)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
package errorx
|
|
||||||
|
|
||||||
func EventRecoveryErr() error {
|
|
||||||
return New("this event has been recycled")
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package errorx
|
|
||||||
|
|
||||||
func LruNotWorkFuncEventErr() error {
|
|
||||||
return New("the event haven't work of function")
|
|
||||||
}
|
|
||||||
|
|
||||||
func KeyBaseIsNilErr() error {
|
|
||||||
return New("key base can't be nil")
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
package errorx
|
|
||||||
|
|
||||||
func TimeOutErr() error {
|
|
||||||
return New("time out err")
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package event
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type Consumer struct {
|
|
||||||
driver DriverInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Consumer) Receive(ctx context.Context) *event {
|
|
||||||
return c.driver.Get()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Consumer) NewEvent(name string) *event {
|
|
||||||
return c.driver.NewEvent(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Consumer) Recovery(e *event) {
|
|
||||||
c.driver.Recovery(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConsumer(driver DriverInterface) ConsumerInterface {
|
|
||||||
return &Consumer{
|
|
||||||
driver: driver,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package event
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultEventState = int32(iota) //默认情况下的状态
|
|
||||||
waitEventState // 等待状态
|
|
||||||
workEventState //工作状态
|
|
||||||
closeEventState //事件关闭状态
|
|
||||||
)
|
|
||||||
|
|
||||||
type EventWorkFunc func() (interface{}, error)
|
|
||||||
|
|
||||||
type DriverInterface interface {
|
|
||||||
Get() *event
|
|
||||||
Put(*event)
|
|
||||||
GetLength() int
|
|
||||||
NewEvent(string) *event
|
|
||||||
Recovery(*event)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProduceInterface interface {
|
|
||||||
Call(context.Context, *event)
|
|
||||||
NewEvent(string) *event
|
|
||||||
Recovery(*event)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConsumerInterface interface {
|
|
||||||
Receive(ctx context.Context) *event
|
|
||||||
Recovery(*event)
|
|
||||||
}
|
|
|
@ -1,189 +0,0 @@
|
||||||
package event
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 事件 poll 降低 new 对象的频率
|
|
||||||
type eventPoll struct {
|
|
||||||
poll chan *event
|
|
||||||
maxSize int32
|
|
||||||
nowSize *int32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *eventPoll) getEvent() *event {
|
|
||||||
issSize := atomic.LoadInt32(e.nowSize)
|
|
||||||
if issSize < e.maxSize {
|
|
||||||
atomic.AddInt32(e.nowSize, 1)
|
|
||||||
return newEvent()
|
|
||||||
}
|
|
||||||
|
|
||||||
return <-e.poll
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *eventPoll) recovery(rEvent *event) {
|
|
||||||
rEvent.Reset()
|
|
||||||
e.poll <- rEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEventPoll(maxSize int) *eventPoll {
|
|
||||||
return &eventPoll{
|
|
||||||
poll: make(chan *event, maxSize),
|
|
||||||
maxSize: int32(maxSize),
|
|
||||||
nowSize: new(int32),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type event struct {
|
|
||||||
msgCtx map[string]interface{}
|
|
||||||
eventName string
|
|
||||||
msg map[string]string // 消息
|
|
||||||
waitResult chan interface{} // 等待返回
|
|
||||||
err error
|
|
||||||
eventStatus *int32
|
|
||||||
ttlManage *time.Timer
|
|
||||||
}
|
|
||||||
|
|
||||||
func newEvent() *event {
|
|
||||||
status := defaultEventState
|
|
||||||
return &event{
|
|
||||||
eventStatus: &status,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) Reset() {
|
|
||||||
if e.ttlManage != nil {
|
|
||||||
e.ttlManage.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
e.err = nil
|
|
||||||
|
|
||||||
atomic.SwapInt32(e.eventStatus, defaultEventState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) SetMsg(key string, val string) {
|
|
||||||
if e.msg == nil {
|
|
||||||
e.msg = make(map[string]string)
|
|
||||||
}
|
|
||||||
e.msg[key] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) GetMsg(key string) string {
|
|
||||||
return e.msg[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) GetEventName() string {
|
|
||||||
return e.eventName
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetValue 写入 ctx 传递用参数
|
|
||||||
func (e *event) SetValue(key string, value interface{}) {
|
|
||||||
if e.msgCtx == nil {
|
|
||||||
e.msgCtx = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
e.msgCtx[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) GetValue(key string) (interface{}, bool) {
|
|
||||||
val, ok := e.msgCtx[key]
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitWaitEvent 初始化 wait event 必须调用才拥有等待特性
|
|
||||||
func (e *event) InitWaitEvent() {
|
|
||||||
if e.waitResult == nil || len(e.waitResult) > 0 {
|
|
||||||
e.waitResult = make(chan interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清理残留
|
|
||||||
if e.ttlManage == nil {
|
|
||||||
e.ttlManage = time.NewTimer(0)
|
|
||||||
}
|
|
||||||
e.ttlManage.Stop()
|
|
||||||
if len(e.ttlManage.C) > 0 {
|
|
||||||
<-e.ttlManage.C
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.CompareAndSwapInt32(e.eventStatus, defaultEventState, waitEventState)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartWaitEvent 开始一个等待任务
|
|
||||||
func (e *event) StartWaitEvent(ttl time.Duration) (interface{}, error) {
|
|
||||||
e.ttlManage.Reset(ttl)
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-e.ttlManage.C:
|
|
||||||
if atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, closeEventState) {
|
|
||||||
return nil, errorx.TimeOutErr()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
|
|
||||||
case result := <-e.waitResult:
|
|
||||||
atomic.CompareAndSwapInt32(e.eventStatus, workEventState, closeEventState)
|
|
||||||
return result, e.err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) ExecWorkAndSendResult(work EventWorkFunc) (interface{}, error) {
|
|
||||||
if !atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, workEventState) {
|
|
||||||
return nil, errorx.New("not wait status, exec err")
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := work()
|
|
||||||
e.err = err
|
|
||||||
e.waitResult <- res
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) SetResultErr(err error) {
|
|
||||||
if !atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, workEventState) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
e.err = err
|
|
||||||
e.waitResult <- nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Driver struct {
|
|
||||||
maxQueueSize int
|
|
||||||
queue chan *event
|
|
||||||
poll *eventPoll
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get 获取驱动
|
|
||||||
func (d *Driver) Get() *event {
|
|
||||||
return <-d.queue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) Put(event *event) {
|
|
||||||
d.queue <- event
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) GetLength() int {
|
|
||||||
return len(d.queue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Driver) NewEvent(name string) *event {
|
|
||||||
event := d.poll.getEvent()
|
|
||||||
event.eventName = name
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
|
|
||||||
// 任何时候回收事件都应该由 最后使用者回收
|
|
||||||
func (d *Driver) Recovery(e *event) {
|
|
||||||
d.poll.recovery(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDriver 新建 Driver
|
|
||||||
func NewDriver(maxSize int) DriverInterface {
|
|
||||||
return &Driver{
|
|
||||||
maxQueueSize: maxSize,
|
|
||||||
queue: make(chan *event, maxSize),
|
|
||||||
poll: newEventPoll(maxSize),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package event
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
const testEvent = "1001"
|
|
||||||
const waitTestEvent = "1002"
|
|
||||||
|
|
||||||
// 简单的 单向 event 使用
|
|
||||||
func Test_EventDriver(t *testing.T) {
|
|
||||||
driver := NewDriver(2000)
|
|
||||||
produce := NewProduce(driver)
|
|
||||||
consumer := NewConsumer(driver)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
wait := sync.WaitGroup{}
|
|
||||||
wait.Add(30000)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for i := 0; i < 30000; i++ {
|
|
||||||
event := produce.NewEvent(testEvent)
|
|
||||||
event.SetMsg("k", strconv.Itoa(i))
|
|
||||||
produce.Call(ctx, event)
|
|
||||||
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
event := consumer.Receive(ctx)
|
|
||||||
fmt.Println(event.GetMsg("k"))
|
|
||||||
consumer.Recovery(event)
|
|
||||||
wait.Done()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
wait.Wait()
|
|
||||||
|
|
||||||
fmt.Println(*driver.(*Driver).poll.nowSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 双向 event
|
|
||||||
func Test_WaitEventDriver(t *testing.T) {
|
|
||||||
driver := NewDriver(200)
|
|
||||||
produce := NewProduce(driver)
|
|
||||||
consumer := NewConsumer(driver)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
wait := sync.WaitGroup{}
|
|
||||||
wait.Add(300000)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for i := 0; i < 300000; i++ {
|
|
||||||
event := produce.NewEvent(testEvent)
|
|
||||||
event.SetMsg("k", strconv.Itoa(i))
|
|
||||||
event.InitWaitEvent()
|
|
||||||
produce.Call(ctx, event)
|
|
||||||
val, err := event.StartWaitEvent(2 * time.Second)
|
|
||||||
require.NoError(t, err)
|
|
||||||
fmt.Println(val)
|
|
||||||
produce.Recovery(event)
|
|
||||||
wait.Done()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
event := consumer.Receive(ctx)
|
|
||||||
event.ExecWorkAndSendResult(func() (interface{}, error) {
|
|
||||||
msg := event.GetMsg("k")
|
|
||||||
return "hello: " + msg, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
wait.Wait()
|
|
||||||
|
|
||||||
fmt.Println(*driver.(*Driver).poll.nowSize)
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package event
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type Produce struct {
|
|
||||||
driver DriverInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Produce) NewEvent(name string) *event {
|
|
||||||
return p.driver.NewEvent(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Produce) Recovery(e *event) {
|
|
||||||
p.driver.Recovery(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Produce) Call(ctx context.Context, e *event) {
|
|
||||||
p.driver.Put(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProduce(driver DriverInterface) ProduceInterface {
|
|
||||||
return &Produce{
|
|
||||||
driver: driver,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package event2
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type Consumer struct {
|
|
||||||
driver DriverInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Consumer) Receive(ctx context.Context) *event {
|
|
||||||
return c.driver.Get()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Consumer) NewEvent(name string) *event {
|
|
||||||
return c.driver.NewEvent(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConsumer(driver DriverInterface) ConsumerInterface {
|
|
||||||
return &Consumer{
|
|
||||||
driver: driver,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package event2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
initEventState = int32(iota) // 初始化状态
|
|
||||||
waitEventState // 等待状态
|
|
||||||
workEventState // 工作状态
|
|
||||||
closeEventState // 事件关闭状态
|
|
||||||
recoveryEventState // 事件回收状态
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
awaitThread = 3
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
WorkFuncEventKey = "workFunc"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 线程安全
|
|
||||||
type EventWorkFunc func() (interface{}, error)
|
|
||||||
|
|
||||||
// 挂起事件, 线程不安全
|
|
||||||
type EventAwaitFunc func() (interface{}, error)
|
|
||||||
|
|
||||||
// 实际操作
|
|
||||||
type awaitFunc func() (*event, interface{}, error)
|
|
||||||
|
|
||||||
type DriverInterface interface {
|
|
||||||
Get() *event
|
|
||||||
Put(*event)
|
|
||||||
GetLength() int
|
|
||||||
NewEvent(string) *event
|
|
||||||
|
|
||||||
await(awaitFunc)
|
|
||||||
recovery(e *event)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProduceInterface interface {
|
|
||||||
Call(context.Context, *event)
|
|
||||||
NewEvent(string) *event
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConsumerInterface interface {
|
|
||||||
Receive(ctx context.Context) *event
|
|
||||||
}
|
|
|
@ -1,221 +0,0 @@
|
||||||
package event2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
|
||||||
)
|
|
||||||
|
|
||||||
type event struct {
|
|
||||||
msgCtx map[string]interface{}
|
|
||||||
eventName string
|
|
||||||
msg map[string]string // 消息
|
|
||||||
waitResult chan interface{} // 等待返回
|
|
||||||
err error
|
|
||||||
eventStatus int32
|
|
||||||
ttlManage *time.Timer
|
|
||||||
parentDriver DriverInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) reset() {
|
|
||||||
if e.ttlManage != nil {
|
|
||||||
e.ttlManage.Stop()
|
|
||||||
|
|
||||||
if len(e.ttlManage.C) > 0 {
|
|
||||||
<-e.ttlManage.C
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.err = nil
|
|
||||||
|
|
||||||
// 清空结果
|
|
||||||
if len(e.waitResult) != 0 {
|
|
||||||
<-e.waitResult
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) Recovery() {
|
|
||||||
e.parentDriver.recovery(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) SetMsg(key string, val string) {
|
|
||||||
if e.msg == nil {
|
|
||||||
e.msg = make(map[string]string)
|
|
||||||
}
|
|
||||||
e.msg[key] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) GetMsg(key string) string {
|
|
||||||
if e.msg == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return e.msg[key]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) GetEventName() string {
|
|
||||||
return e.eventName
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetValue 写入 ctx 传递用参数
|
|
||||||
func (e *event) SetValue(key string, value interface{}) {
|
|
||||||
if e.msgCtx == nil {
|
|
||||||
e.msgCtx = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
e.msgCtx[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) GetValue(key string) (interface{}, bool) {
|
|
||||||
if e.msgCtx == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
val, ok := e.msgCtx[key]
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) InitWaitEvent() {
|
|
||||||
e.reset()
|
|
||||||
if e.waitResult == nil {
|
|
||||||
e.waitResult = make(chan interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.SwapInt32(&e.eventStatus, waitEventState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) SetResultErr(err error) {
|
|
||||||
if !atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, workEventState) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
e.err = err
|
|
||||||
e.waitResult <- nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartWaitEvent 开始一个等待任务
|
|
||||||
func (e *event) StartWaitEvent(ttl time.Duration) (interface{}, error) {
|
|
||||||
if e.ttlManage == nil {
|
|
||||||
e.ttlManage = time.NewTimer(ttl)
|
|
||||||
} else {
|
|
||||||
e.ttlManage.Reset(ttl)
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-e.ttlManage.C:
|
|
||||||
if atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, closeEventState) {
|
|
||||||
return nil, errorx.TimeOutErr()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
|
|
||||||
case result := <-e.waitResult:
|
|
||||||
atomic.SwapInt32(&e.eventStatus, closeEventState)
|
|
||||||
return result, e.err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 实际执行推送
|
|
||||||
func (e *event) execWorker(res interface{}, err error) {
|
|
||||||
switch work := res.(type) {
|
|
||||||
case EventAwaitFunc:
|
|
||||||
await := func() (*event, interface{}, error) {
|
|
||||||
result, err := work()
|
|
||||||
return e, result, err
|
|
||||||
}
|
|
||||||
e.parentDriver.await(await)
|
|
||||||
|
|
||||||
case EventWorkFunc:
|
|
||||||
e.InitWaitEvent()
|
|
||||||
e.SetValue(WorkFuncEventKey, work)
|
|
||||||
e.parentDriver.Put(e)
|
|
||||||
|
|
||||||
default:
|
|
||||||
e.err = err
|
|
||||||
e.waitResult <- res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) ExecWorkAndSendResult(work EventWorkFunc) (interface{}, error) {
|
|
||||||
if !atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, workEventState) {
|
|
||||||
return nil, errorx.New("not wait status, exec err")
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := work()
|
|
||||||
e.execWorker(res, err)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type driver struct {
|
|
||||||
waitQueue chan awaitFunc
|
|
||||||
eventQueue chan *event
|
|
||||||
levelQueue chan *event
|
|
||||||
|
|
||||||
// event 池的实现
|
|
||||||
poll chan *event
|
|
||||||
maxPoolSize int32
|
|
||||||
nowPoolSize int32
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDriver(maxSize int) DriverInterface {
|
|
||||||
d := &driver{
|
|
||||||
// pool
|
|
||||||
maxPoolSize: int32(maxSize),
|
|
||||||
nowPoolSize: 0,
|
|
||||||
poll: make(chan *event, maxSize),
|
|
||||||
|
|
||||||
// waitQueue 1/3 的挂起指标
|
|
||||||
waitQueue: make(chan awaitFunc, maxSize/3),
|
|
||||||
levelQueue: make(chan *event, maxSize/3),
|
|
||||||
eventQueue: make(chan *event, maxSize),
|
|
||||||
}
|
|
||||||
d.awaitWorker()
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *driver) NewEvent(name string) *event {
|
|
||||||
|
|
||||||
issSize := atomic.LoadInt32(&d.nowPoolSize)
|
|
||||||
if issSize < d.maxPoolSize {
|
|
||||||
atomic.AddInt32(&d.nowPoolSize, 1)
|
|
||||||
return d.newEvent(name)
|
|
||||||
}
|
|
||||||
e := <-d.poll
|
|
||||||
e.eventName = name
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *driver) newEvent(name string) *event {
|
|
||||||
status := initEventState
|
|
||||||
return &event{
|
|
||||||
eventStatus: status,
|
|
||||||
parentDriver: d,
|
|
||||||
eventName: name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先尝试 level
|
|
||||||
func (d *driver) Get() *event {
|
|
||||||
if len(d.levelQueue) > 0 {
|
|
||||||
return <-d.levelQueue
|
|
||||||
}
|
|
||||||
return <-d.eventQueue
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *driver) Put(e *event) {
|
|
||||||
d.eventQueue <- e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *driver) GetLength() int {
|
|
||||||
return len(d.eventQueue) + len(d.levelQueue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *driver) recovery(e *event) {
|
|
||||||
atomic.SwapInt32(&e.eventStatus, recoveryEventState)
|
|
||||||
e.reset()
|
|
||||||
d.poll <- e
|
|
||||||
}
|
|
||||||
|
|
||||||
// 挂起操作相关
|
|
||||||
func (d *driver) await(a awaitFunc) {
|
|
||||||
d.waitQueue <- a
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
package event2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
const testEvent = "1001"
|
|
||||||
const waitTestEvent = "1002"
|
|
||||||
|
|
||||||
// 简单的 单向 event 使用
|
|
||||||
func Test_EventDriver(t *testing.T) {
|
|
||||||
driver := NewDriver(2000)
|
|
||||||
produce := NewProduce(driver)
|
|
||||||
consumer := NewConsumer(driver)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
wait := sync.WaitGroup{}
|
|
||||||
wait.Add(30000)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for i := 0; i < 30000; i++ {
|
|
||||||
event := produce.NewEvent(testEvent)
|
|
||||||
event.SetMsg("k", strconv.Itoa(i))
|
|
||||||
produce.Call(ctx, event)
|
|
||||||
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
event := consumer.Receive(ctx)
|
|
||||||
fmt.Println(event.GetMsg("k"))
|
|
||||||
event.Recovery()
|
|
||||||
wait.Done()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
wait.Wait()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 双向 event
|
|
||||||
func Test_EventDriver_Tow_way(t *testing.T) {
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
driver := NewDriver(2000)
|
|
||||||
produce := NewProduce(driver)
|
|
||||||
consumer := NewConsumer(driver)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
event := consumer.Receive(ctx)
|
|
||||||
work, ok := event.GetValue(WorkFuncEventKey)
|
|
||||||
if !ok {
|
|
||||||
panic("get work key err")
|
|
||||||
}
|
|
||||||
workFunc, ok := work.(EventWorkFunc)
|
|
||||||
if !ok {
|
|
||||||
panic("work func err")
|
|
||||||
}
|
|
||||||
_, err := event.ExecWorkAndSendResult(workFunc)
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 一般的 two-way 模式
|
|
||||||
for i := 0; i < 10000; i++ {
|
|
||||||
event := produce.NewEvent(waitTestEvent)
|
|
||||||
event.InitWaitEvent()
|
|
||||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
|
||||||
return i + 1, nil
|
|
||||||
}))
|
|
||||||
produce.Call(ctx, event)
|
|
||||||
res, err := event.StartWaitEvent(2 * time.Second)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, res, i+1)
|
|
||||||
event.Recovery()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 挂起模式,2 秒左右的执行时间
|
|
||||||
group := sync.WaitGroup{}
|
|
||||||
group.Add(5)
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
go func(i int) {
|
|
||||||
event := produce.NewEvent(waitTestEvent)
|
|
||||||
event.InitWaitEvent()
|
|
||||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
|
||||||
// 访问 await Work 来发起一个 异步请求操作
|
|
||||||
return EventAwaitFunc(func() (interface{}, error) {
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
return i + 1, nil
|
|
||||||
}), nil
|
|
||||||
}))
|
|
||||||
produce.Call(ctx, event)
|
|
||||||
res, err := event.StartWaitEvent(2 * time.Second)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, res, i+1)
|
|
||||||
event.Recovery()
|
|
||||||
group.Done()
|
|
||||||
}(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 挂起成功不发生超时
|
|
||||||
for i := 0; i < 10000; i++ {
|
|
||||||
event := produce.NewEvent(waitTestEvent)
|
|
||||||
event.InitWaitEvent()
|
|
||||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
|
||||||
return i + 1, nil
|
|
||||||
}))
|
|
||||||
produce.Call(ctx, event)
|
|
||||||
res, err := event.StartWaitEvent(500 * time.Millisecond)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, res, i+1)
|
|
||||||
event.Recovery()
|
|
||||||
}
|
|
||||||
|
|
||||||
group.Wait()
|
|
||||||
|
|
||||||
// 挂起一个高延迟操作, 保证局部操作还在事件中
|
|
||||||
group = sync.WaitGroup{}
|
|
||||||
group.Add(5)
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
event := produce.NewEvent(waitTestEvent)
|
|
||||||
event.InitWaitEvent()
|
|
||||||
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
|
|
||||||
return EventAwaitFunc(func() (interface{}, error) {
|
|
||||||
// 返回值为 EventWorkFunc 时, 会重新加入末端队列
|
|
||||||
return EventWorkFunc(func() (interface{}, error) {
|
|
||||||
return i + 1, nil
|
|
||||||
}), nil
|
|
||||||
|
|
||||||
}), nil
|
|
||||||
}))
|
|
||||||
produce.Call(ctx, event)
|
|
||||||
res, err := event.StartWaitEvent(2 * time.Second)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, res, i+1)
|
|
||||||
event.Recovery()
|
|
||||||
group.Done()
|
|
||||||
fmt.Println(i)
|
|
||||||
}
|
|
||||||
group.Wait()
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package event2
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type Produce struct {
|
|
||||||
driver DriverInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Produce) NewEvent(name string) *event {
|
|
||||||
return p.driver.NewEvent(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Produce) Call(ctx context.Context, e *event) {
|
|
||||||
p.driver.Put(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProduce(driver DriverInterface) ProduceInterface {
|
|
||||||
return &Produce{
|
|
||||||
driver: driver,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package event2
|
|
||||||
|
|
||||||
func (d *driver) awaitWorker() {
|
|
||||||
for i := 0; i < awaitThread; i++ {
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
awaitFunc := <-d.waitQueue
|
|
||||||
e, res, err := awaitFunc()
|
|
||||||
e.execWorker(res, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1 @@
|
||||||
|
package define
|
|
@ -1,43 +0,0 @@
|
||||||
package logx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LogLevelState int8
|
|
||||||
|
|
||||||
var (
|
|
||||||
once sync.Once
|
|
||||||
stath []string
|
|
||||||
)
|
|
||||||
|
|
||||||
type upLogger struct {
|
|
||||||
ctx context.Context
|
|
||||||
produce event.ProduceInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
once.Do(func() {
|
|
||||||
stath = viper.GetStringSlice("logPrint.stath")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type logInterface interface {
|
|
||||||
Debug(format string, msg ...interface{})
|
|
||||||
Info(format string, msg ...interface{})
|
|
||||||
Warn(format string, msg ...interface{})
|
|
||||||
Error(format string, msg ...interface{})
|
|
||||||
Panic(format string, msg ...interface{})
|
|
||||||
|
|
||||||
Debugln(msg ...interface{})
|
|
||||||
Infoln(msg ...interface{})
|
|
||||||
Warnln(msg ...interface{})
|
|
||||||
Errorln(msg ...interface{})
|
|
||||||
Panicln(msg ...interface{})
|
|
||||||
|
|
||||||
Print(level string, format string, msg ...interface{})
|
|
||||||
}
|
|
161
pkg/logx/logx.go
161
pkg/logx/logx.go
|
@ -1,161 +0,0 @@
|
||||||
package logx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
|
||||||
)
|
|
||||||
|
|
||||||
func With(ctx context.Context, p event.ProduceInterface) *upLogger {
|
|
||||||
return &upLogger{
|
|
||||||
ctx: ctx,
|
|
||||||
produce: p,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Debug(format string, msg ...interface{}) {
|
|
||||||
l.Print("DEBUG", format, msg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Info(format string, msg ...interface{}) {
|
|
||||||
l.Print("INFO", format, msg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Warn(format string, msg ...interface{}) {
|
|
||||||
l.Print("WARN", format, msg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Error(format string, msg ...interface{}) {
|
|
||||||
l.Print("ERROR", format, msg...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Panic(format string, msg ...interface{}) {
|
|
||||||
l.Print("ERROR", format, msg...)
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Print(level string, format string, msg ...interface{}) {
|
|
||||||
logPrint(4, level, format, msg...)
|
|
||||||
sendMsg := &middleMsg.LogContext{
|
|
||||||
Level: level,
|
|
||||||
Data: time.Now(),
|
|
||||||
Msg: fmt.Sprintf(format, msg...),
|
|
||||||
Route: findPlace(4),
|
|
||||||
}
|
|
||||||
middleMsg.SendMiddleMsg(l.ctx, l.produce, sendMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Debugln(msg ...interface{}) {
|
|
||||||
l.Print("DEBUG", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Infoln(msg ...interface{}) {
|
|
||||||
l.Print("INFO", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Warnln(msg ...interface{}) {
|
|
||||||
l.Print("WARN", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Errorln(msg ...interface{}) {
|
|
||||||
l.Print("ERROR", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *upLogger) Panicln(msg ...interface{}) {
|
|
||||||
l.Print("ERROR", "%s", format(msg...))
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Debug(format string, msg ...interface{}) {
|
|
||||||
logPrint(3, "DEBUG", format, msg...)
|
|
||||||
}
|
|
||||||
func Info(format string, msg ...interface{}) {
|
|
||||||
logPrint(3, "INFO", format, msg...)
|
|
||||||
}
|
|
||||||
func Warn(format string, msg ...interface{}) {
|
|
||||||
logPrint(3, "WARN", format, msg...)
|
|
||||||
}
|
|
||||||
func Error(format string, msg ...interface{}) {
|
|
||||||
logPrint(3, "ERROR", format, msg...)
|
|
||||||
}
|
|
||||||
func Panic(format string, msg ...interface{}) {
|
|
||||||
logPrint(3, "PANIC", format, msg...)
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Debugln(msg ...interface{}) {
|
|
||||||
logPrint(3, "DEBUG", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
func Infoln(msg ...interface{}) {
|
|
||||||
logPrint(3, "INFO", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
func Warnln(msg ...interface{}) {
|
|
||||||
logPrint(3, "WARN", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
func Errorln(msg ...interface{}) {
|
|
||||||
logPrint(3, "ERROR", "%s", format(msg...))
|
|
||||||
}
|
|
||||||
func Panicln(msg ...interface{}) {
|
|
||||||
logPrint(3, "PANIC", "%s", format(msg...))
|
|
||||||
os.Exit(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func logPrint(floor int, level string, format string, msg ...interface{}) {
|
|
||||||
place := findPlace(floor)
|
|
||||||
datetime := fmt.Sprintf("%s", time.Now())[0:19]
|
|
||||||
|
|
||||||
switch level {
|
|
||||||
case "DEBUG":
|
|
||||||
fmt.Printf("\033[1;37;40m")
|
|
||||||
case "INFO":
|
|
||||||
fmt.Printf("\033[1;32;40m")
|
|
||||||
case "WARN":
|
|
||||||
fmt.Printf("\033[1;33;40m")
|
|
||||||
default:
|
|
||||||
fmt.Printf("\033[1;31;40m")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//fmt.Println(level, datetime, fmt.Sprintf(format, msg...))
|
|
||||||
fmt.Printf("%s\t%v\t%s\n", level, datetime, fmt.Sprintf(format, msg...))
|
|
||||||
|
|
||||||
for _, lv := range stath {
|
|
||||||
if strings.ToUpper(lv) == strings.ToUpper(level) {
|
|
||||||
fmt.Println(place)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func findPlace(floor int) string {
|
|
||||||
|
|
||||||
var (
|
|
||||||
place string
|
|
||||||
i = floor
|
|
||||||
)
|
|
||||||
|
|
||||||
for {
|
|
||||||
_, file, line, _ := runtime.Caller(i)
|
|
||||||
if line == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
place = fmt.Sprintf("%s:%d\n%s", file, line, place)
|
|
||||||
}
|
|
||||||
|
|
||||||
return place
|
|
||||||
}
|
|
||||||
|
|
||||||
func format(message ...interface{}) (context string) {
|
|
||||||
for _, msg := range message {
|
|
||||||
context = fmt.Sprintf("%s\t%v", context, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return context
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package logx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStd(t *testing.T) {
|
|
||||||
Info("%d%s", 11, "Info")
|
|
||||||
Debug("%d%s", 11, "Debug")
|
|
||||||
Warn("%d%s", 11, "Warn")
|
|
||||||
Error("%d%s", 11, "Error")
|
|
||||||
|
|
||||||
Infoln(1321, "dwad", 0x9812933)
|
|
||||||
Debugln(1321, "dwad", 0x9812933)
|
|
||||||
Warnln(1321, "dwad", 0x9812933)
|
|
||||||
Errorln(1321, "dwad", 0x9812933)
|
|
||||||
|
|
||||||
//Panic("%d%s", 11, "Panic")
|
|
||||||
|
|
||||||
logger := With(context.Background(),
|
|
||||||
event.NewProduce(event.NewDriver(100)))
|
|
||||||
|
|
||||||
logger.Info("%d%s", 11, "Info")
|
|
||||||
logger.Debug("%d%s", 11, "Debug")
|
|
||||||
logger.Warn("%d%s", 11, "Warn")
|
|
||||||
logger.Error("%d%s", 11, "Error")
|
|
||||||
//logger.Panic("%d%s", 11, "Panic")
|
|
||||||
|
|
||||||
logger.Infoln(11, "Info")
|
|
||||||
logger.Debugln(11, "Debug")
|
|
||||||
logger.Warnln(11, "Warn")
|
|
||||||
logger.Errorln(11, "Error")
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/structure"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SingleWorkFunc func() interface{}
|
|
||||||
|
|
||||||
const (
|
|
||||||
OptionEventName = "operateEvent"
|
|
||||||
CleanEventName = "clearEvent"
|
|
||||||
TtlEventName = "ttlEvent"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
lruCacheOnce sync.Once
|
|
||||||
lruCache *SingleCache
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultLruMaxSize = 1 * 1024 * 1024 * 1024
|
|
||||||
defaultLruClearSize = 0.5 * 1024 * 1024 * 1024
|
|
||||||
defaultLruEventDriver = 2000
|
|
||||||
)
|
|
||||||
const (
|
|
||||||
defaultWaitTime = 20 * time.Minute
|
|
||||||
)
|
|
||||||
|
|
||||||
type CacheInterface interface {
|
|
||||||
Del() error
|
|
||||||
Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool)
|
|
||||||
Add(key *proto.BaseKey, val structure.KeyBaseInterface) error
|
|
||||||
UpdateLruSize(length structure.UpdateLength)
|
|
||||||
DelByKey(key *proto.BaseKey) error
|
|
||||||
DelToClearSize() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// TTL
|
|
||||||
const (
|
|
||||||
defaultDetachNum = 300
|
|
||||||
defaultTtlMaxLevel = 18
|
|
||||||
)
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
package define
|
||||||
|
|
||||||
|
// define
|
225
pkg/lru/lru.go
225
pkg/lru/lru.go
|
@ -1,225 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"container/list"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event2"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/middle"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/structure"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/util"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
type keyBaseValue struct {
|
|
||||||
key string
|
|
||||||
val structure.KeyBaseInterface
|
|
||||||
expire int64 // 过期时间戳
|
|
||||||
}
|
|
||||||
|
|
||||||
type SingleCache struct {
|
|
||||||
maxsize int64 //最大的长度
|
|
||||||
clearSize int64 // 清理长度
|
|
||||||
nowSize int64 // 现在的长度
|
|
||||||
li *list.List
|
|
||||||
lruMap map[string]*list.Element
|
|
||||||
lruMaxDiverSize int
|
|
||||||
lruTtlManage *lruTTl // 定时清理器
|
|
||||||
|
|
||||||
lruDriver event2.DriverInterface
|
|
||||||
lruConsumer event2.ConsumerInterface
|
|
||||||
lruCleanProduce event2.ProduceInterface // 发送清理事件
|
|
||||||
|
|
||||||
middleProduce event.ProduceInterface // 中间件驱动
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateLruSize 更新现在的长度
|
|
||||||
func (lru *SingleCache) UpdateLruSize(length structure.UpdateLength) {
|
|
||||||
atomic.AddInt64(&lru.nowSize, int64(length))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cacheInit() (int64, int64, int, int) {
|
|
||||||
maxSize := viper.GetString("lruCache.maxSize")
|
|
||||||
retMaxSize, maxErr := util.ParseSizeToBit(maxSize)
|
|
||||||
if maxErr != nil {
|
|
||||||
return 0, 0, 0, 0
|
|
||||||
}
|
|
||||||
if retMaxSize == 0 {
|
|
||||||
retMaxSize = defaultLruMaxSize
|
|
||||||
}
|
|
||||||
|
|
||||||
clearSize := viper.GetString("lruCache.clearSize")
|
|
||||||
retClearSize, clearErr := util.ParseSizeToBit(clearSize)
|
|
||||||
if clearErr != nil {
|
|
||||||
return 0, 0, 0, 0
|
|
||||||
}
|
|
||||||
if retClearSize == 0 {
|
|
||||||
retClearSize = defaultLruClearSize
|
|
||||||
}
|
|
||||||
|
|
||||||
maxDriver := viper.GetInt("lruCache.eventDriverSize")
|
|
||||||
if maxDriver == 0 {
|
|
||||||
maxDriver = defaultLruEventDriver
|
|
||||||
}
|
|
||||||
|
|
||||||
detachNum := viper.GetInt("lruCache.detachNum")
|
|
||||||
if detachNum == 0 {
|
|
||||||
detachNum = defaultDetachNum
|
|
||||||
}
|
|
||||||
|
|
||||||
return retMaxSize, retClearSize, maxDriver, detachNum
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLRUCache lru初始化
|
|
||||||
func NewLRUCache() *SingleCache {
|
|
||||||
maxSize, clearSize, maxDriverSize, detachNum := cacheInit()
|
|
||||||
lruDriver := event2.NewDriver(maxDriverSize)
|
|
||||||
lruCacheOnce.Do(func() {
|
|
||||||
lru := &SingleCache{
|
|
||||||
maxsize: maxSize,
|
|
||||||
clearSize: clearSize,
|
|
||||||
nowSize: 0,
|
|
||||||
li: list.New(),
|
|
||||||
lruMap: make(map[string]*list.Element),
|
|
||||||
lruMaxDiverSize: maxDriverSize,
|
|
||||||
lruDriver: lruDriver,
|
|
||||||
lruConsumer: event2.NewConsumer(lruDriver),
|
|
||||||
lruCleanProduce: event2.NewProduce(lruDriver),
|
|
||||||
middleProduce: event.NewProduce(middle.NewMiddleWare().GetEventDriver()),
|
|
||||||
lruTtlManage: newLruTTl(detachNum),
|
|
||||||
}
|
|
||||||
lruCache = lru
|
|
||||||
|
|
||||||
// 启动 lru 事件驱动
|
|
||||||
go lru.lruSingleWork()
|
|
||||||
go lru.lruTtlWork()
|
|
||||||
go lru.cleanWork()
|
|
||||||
|
|
||||||
})
|
|
||||||
return lruCache
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDriver 获取驱动
|
|
||||||
func (lru *SingleCache) GetDriver() event2.DriverInterface {
|
|
||||||
return lru.lruDriver
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add 增加
|
|
||||||
func (lru *SingleCache) Add(key *proto.BaseKey, val structure.KeyBaseInterface) error {
|
|
||||||
|
|
||||||
if key == nil {
|
|
||||||
return errorx.KeyBaseIsNilErr()
|
|
||||||
}
|
|
||||||
|
|
||||||
exp := lru.lruTtlManage.setKeys(key)
|
|
||||||
keyBaseVal := &keyBaseValue{
|
|
||||||
key: key.Key,
|
|
||||||
val: val,
|
|
||||||
expire: exp,
|
|
||||||
}
|
|
||||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
|
||||||
lru.li.MoveToFront(elVal)
|
|
||||||
oldSize := elVal.Value.(structure.KeyBaseInterface).SizeByte()
|
|
||||||
|
|
||||||
lru.UpdateLruSize(structure.UpdateLength(val.SizeByte() - oldSize))
|
|
||||||
elVal.Value = keyBaseVal
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
valEl := lru.li.PushFront(keyBaseVal)
|
|
||||||
lru.lruMap[key.Key] = valEl
|
|
||||||
//增加大小
|
|
||||||
lru.UpdateLruSize(structure.UpdateLength(valEl.Value.(*keyBaseValue).val.SizeByte()))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get 查找key对应的value
|
|
||||||
func (lru *SingleCache) Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool) {
|
|
||||||
|
|
||||||
if key == nil {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
|
||||||
lru.li.MoveToFront(elVal)
|
|
||||||
return elVal.Value.(*keyBaseValue).val, true
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
//Del 删除机制
|
|
||||||
func (lru *SingleCache) Del() error {
|
|
||||||
if lru.lruMap == nil {
|
|
||||||
return errorx.New("lru is nil")
|
|
||||||
}
|
|
||||||
data := lru.li.Back()
|
|
||||||
delete(lru.lruMap, data.Value.(*keyBaseValue).key)
|
|
||||||
//删除大小
|
|
||||||
lru.UpdateLruSize(structure.UpdateLength(-1 * data.Value.(*keyBaseValue).val.SizeByte()))
|
|
||||||
lru.li.Remove(data)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//DelByKey 根据key删除
|
|
||||||
func (lru *SingleCache) DelByKey(key *proto.BaseKey) error {
|
|
||||||
|
|
||||||
if key == nil {
|
|
||||||
return errorx.KeyBaseIsNilErr()
|
|
||||||
}
|
|
||||||
|
|
||||||
if lru.lruMap == nil {
|
|
||||||
return errorx.New("lru is nil")
|
|
||||||
}
|
|
||||||
if el, ok := lru.lruMap[key.Key]; ok {
|
|
||||||
delete(lru.lruMap, key.Key)
|
|
||||||
lru.li.Remove(el)
|
|
||||||
lru.UpdateLruSize(structure.UpdateLength(-1 * el.Value.(*keyBaseValue).val.SizeByte()))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errorx.New("lru no this key")
|
|
||||||
}
|
|
||||||
|
|
||||||
//DelByKeyAndExTtl 根据key(string)删除已经过期的 key
|
|
||||||
func (lru *SingleCache) delByKeyAndExTtl(key string, beforeTime int64) {
|
|
||||||
if elVal, ok := lru.lruMap[key]; ok {
|
|
||||||
exp := elVal.Value.(*keyBaseValue).expire
|
|
||||||
if exp <= beforeTime {
|
|
||||||
delete(lru.lruMap, key)
|
|
||||||
lru.li.Remove(elVal)
|
|
||||||
lru.UpdateLruSize(structure.UpdateLength(-1 * elVal.Value.(*keyBaseValue).val.SizeByte()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lru *SingleCache) DelToClearSize() error {
|
|
||||||
if lru.lruMap == nil {
|
|
||||||
return errorx.New("lru is nil")
|
|
||||||
}
|
|
||||||
for lru.nowSize > lru.clearSize {
|
|
||||||
//del自动给nowSize进行大小的改变
|
|
||||||
err := lru.Del()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新过期时间
|
|
||||||
func (lru *SingleCache) UpdateTTl(key *proto.BaseKey) error {
|
|
||||||
|
|
||||||
if key == nil {
|
|
||||||
return errorx.KeyBaseIsNilErr()
|
|
||||||
}
|
|
||||||
|
|
||||||
if elVal, ok := lru.lruMap[key.Key]; ok {
|
|
||||||
expire := lru.lruTtlManage.setKeys(key)
|
|
||||||
elVal.Value.(*keyBaseValue).expire = expire
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorx.New("the key is not in lru cache, key:%s", key.Key)
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewLRUCache(t *testing.T) {
|
|
||||||
cache := NewLRUCache()
|
|
||||||
v1 := stringx.NewStringSingle()
|
|
||||||
v2 := stringx.NewStringSingle()
|
|
||||||
v3 := stringx.NewStringSingle()
|
|
||||||
key1 := proto.BaseKey{
|
|
||||||
Key: "1",
|
|
||||||
}
|
|
||||||
key2 := proto.BaseKey{
|
|
||||||
Key: "2",
|
|
||||||
}
|
|
||||||
key3 := proto.BaseKey{
|
|
||||||
Key: "3",
|
|
||||||
}
|
|
||||||
cache.Add(&key1, v1)
|
|
||||||
cache.Add(&key2, v2)
|
|
||||||
cache.Add(&key3, v3)
|
|
||||||
cache.Add(&key1, v1)
|
|
||||||
fmt.Println(cache.nowSize)
|
|
||||||
cache.Del()
|
|
||||||
fmt.Println(cache.nowSize)
|
|
||||||
_, isTrue := cache.Get(&key1)
|
|
||||||
require.Equal(t, isTrue, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewLRUCache2(t *testing.T) {
|
|
||||||
//根据key删除
|
|
||||||
cache := NewLRUCache()
|
|
||||||
v1 := stringx.NewStringSingle()
|
|
||||||
v2 := stringx.NewStringSingle()
|
|
||||||
v3 := stringx.NewStringSingle()
|
|
||||||
key1 := proto.BaseKey{
|
|
||||||
Key: "1",
|
|
||||||
}
|
|
||||||
key2 := proto.BaseKey{
|
|
||||||
Key: "2",
|
|
||||||
}
|
|
||||||
key3 := proto.BaseKey{
|
|
||||||
Key: "3",
|
|
||||||
}
|
|
||||||
cache.Add(&key1, v1)
|
|
||||||
cache.Add(&key2, v2)
|
|
||||||
cache.Add(&key3, v3)
|
|
||||||
cache.DelByKey(&key1)
|
|
||||||
_, ok := cache.Get(&key1)
|
|
||||||
require.Equal(t, ok, false)
|
|
||||||
require.Error(t, cache.DelByKey(&key1))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLruProcess(t *testing.T) {
|
|
||||||
lru := NewLRUCache()
|
|
||||||
lru.clearSize = 3600
|
|
||||||
|
|
||||||
for i := 100; i < 200; i++ {
|
|
||||||
lru.Add(&proto.BaseKey{
|
|
||||||
Key: fmt.Sprint(i),
|
|
||||||
Ttl: 20 << 2,
|
|
||||||
}, stringx.NewStringSingle())
|
|
||||||
}
|
|
||||||
|
|
||||||
// mock LruKey
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
lru.Add(&proto.BaseKey{
|
|
||||||
Key: fmt.Sprint(i),
|
|
||||||
Ttl: 4,
|
|
||||||
}, stringx.NewStringSingle())
|
|
||||||
}
|
|
||||||
|
|
||||||
require.Equal(t, lru.nowSize, int64(200*24))
|
|
||||||
|
|
||||||
// 自动清理测试
|
|
||||||
fmt.Println(lru.clearSize)
|
|
||||||
require.Equal(t, lru.li.Len(), 200)
|
|
||||||
time.Sleep(3 * time.Second)
|
|
||||||
require.Less(t, lru.nowSize, lru.clearSize+1)
|
|
||||||
|
|
||||||
// TTL 测试, 100-200 key 发生自动清理 留下 50-100 共 100(0-100) + 20个 key,5s 后,前 0-100的 key 过期,剩下
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
require.Equal(t, lru.li.Len(), 50)
|
|
||||||
|
|
||||||
// 过期全部的 Key
|
|
||||||
for i := 100; i < 200; i++ {
|
|
||||||
lru.UpdateTTl(&proto.BaseKey{
|
|
||||||
Key: fmt.Sprint(i),
|
|
||||||
Ttl: -1,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
require.Equal(t, lru.nowSize, int64(0))
|
|
||||||
}
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package lrutest
|
||||||
|
|
||||||
|
|
||||||
|
func Test(a int) bool{
|
||||||
|
return a==1
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package lrutest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTest(t *testing.T) {
|
||||||
|
ts , err := Test(2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Regexp(t, '\d', ts)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,56 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/util/skiplist"
|
|
||||||
)
|
|
||||||
|
|
||||||
// lru 的 ttl 管理器
|
|
||||||
type lruTTl struct {
|
|
||||||
sk *skiplist.SkipList
|
|
||||||
memoryKey chan string // 缓存过期的 key
|
|
||||||
detachNum int // 每次移除的数量
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *lruTTl) setKeys(key *proto.BaseKey) int64 {
|
|
||||||
l.mu.Lock()
|
|
||||||
defer l.mu.Unlock()
|
|
||||||
|
|
||||||
// 永久存储
|
|
||||||
if key.Expire == nil && key.Ttl == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
ttlTime := time.Now().Unix()
|
|
||||||
if key.Expire != nil {
|
|
||||||
ttlTime = key.Expire.GetSeconds()
|
|
||||||
}
|
|
||||||
|
|
||||||
ttlTime += key.GetTtl()
|
|
||||||
l.sk.Insert(float64(ttlTime), key.GetKey())
|
|
||||||
|
|
||||||
return ttlTime
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载过期的 Key 到 Memory
|
|
||||||
func (l *lruTTl) ttlKeyToMemoryBySecond() {
|
|
||||||
t := time.Now()
|
|
||||||
values := l.sk.PopLeft(float64(t.Unix()))
|
|
||||||
|
|
||||||
for _, val := range values {
|
|
||||||
l.memoryKey <- val.(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newLruTTl(detachNum int) *lruTTl {
|
|
||||||
return &lruTTl{
|
|
||||||
sk: skiplist.NewSkipList(defaultTtlMaxLevel),
|
|
||||||
// 默认 10000 个 Key
|
|
||||||
memoryKey: make(chan string, 10000),
|
|
||||||
detachNum: detachNum,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTTlCup(t *testing.T) {
|
|
||||||
k := make([]string, 100, 3000)
|
|
||||||
fmt.Println(cap(k))
|
|
||||||
p := k[:50]
|
|
||||||
fmt.Println(cap(p))
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_LruTTl(t *testing.T) {
|
|
||||||
lru := NewLRUCache()
|
|
||||||
s := stringx.NewStringSingle()
|
|
||||||
lru.Add(&proto.BaseKey{
|
|
||||||
Key: "k8s",
|
|
||||||
Ttl: 1,
|
|
||||||
}, s)
|
|
||||||
lru.Add(&proto.BaseKey{
|
|
||||||
Key: "990",
|
|
||||||
Ttl: 10,
|
|
||||||
}, s)
|
|
||||||
require.Equal(t, lru.nowSize, int64(48))
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second)
|
|
||||||
require.Equal(t, lru.nowSize, int64(24))
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event2"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/proto"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWorker(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
lru := NewLRUCache()
|
|
||||||
produce := event2.NewProduce(lru.GetDriver())
|
|
||||||
workEvent := produce.NewEvent(OptionEventName)
|
|
||||||
workEvent.SetValue(event2.WorkFuncEventKey, event2.EventWorkFunc(func() (interface{}, error) {
|
|
||||||
v1 := stringx.NewStringSingle()
|
|
||||||
key := proto.BaseKey{
|
|
||||||
Key: "v1",
|
|
||||||
}
|
|
||||||
res, _ := v1.Set("123")
|
|
||||||
lru.Add(&key, v1)
|
|
||||||
return res, nil
|
|
||||||
}))
|
|
||||||
workEvent.InitWaitEvent()
|
|
||||||
produce.Call(ctx, workEvent)
|
|
||||||
res, err := workEvent.StartWaitEvent(2 * time.Second)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, res, "123")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSingleCache_DelToClearSize(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
lru := NewLRUCache()
|
|
||||||
produce := event2.NewProduce(lru.GetDriver())
|
|
||||||
|
|
||||||
for i := int32(20000); i > 0; i-- {
|
|
||||||
workEvent := produce.NewEvent(OptionEventName)
|
|
||||||
workEvent.SetValue(event2.WorkFuncEventKey, event2.EventWorkFunc(func() (interface{}, error) {
|
|
||||||
v1 := stringx.NewStringSingle()
|
|
||||||
key := proto.BaseKey{
|
|
||||||
Key: string(i),
|
|
||||||
Ttl: 1,
|
|
||||||
}
|
|
||||||
u := v1.Setbit(i, true)
|
|
||||||
lru.Add(&key, v1)
|
|
||||||
return u, nil
|
|
||||||
}))
|
|
||||||
workEvent.InitWaitEvent()
|
|
||||||
produce.Call(ctx, workEvent)
|
|
||||||
workEvent.StartWaitEvent(2 * time.Second)
|
|
||||||
workEvent.Recovery()
|
|
||||||
}
|
|
||||||
|
|
||||||
logx.Info("start size is %d", lru.nowSize)
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
logx.Info("end size is %d", lru.nowSize)
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event2"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
|
||||||
mMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (lru *SingleCache) lruSingleWork() {
|
|
||||||
ctx := context.Background()
|
|
||||||
for {
|
|
||||||
workEvent := lru.lruConsumer.Receive(ctx)
|
|
||||||
workFunc, ok := workEvent.GetValue(event2.WorkFuncEventKey)
|
|
||||||
if !ok {
|
|
||||||
workEvent.SetResultErr(errorx.LruNotWorkFuncEventErr())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch workEvent.GetEventName() {
|
|
||||||
case OptionEventName:
|
|
||||||
if work, ok := workFunc.(event2.EventWorkFunc); ok {
|
|
||||||
workEvent.ExecWorkAndSendResult(work)
|
|
||||||
}
|
|
||||||
|
|
||||||
case CleanEventName:
|
|
||||||
// 对当前的io数量进行判断
|
|
||||||
ioNum := lru.GetDriver().GetLength()
|
|
||||||
if ioNum > lru.lruMaxDiverSize/2 {
|
|
||||||
lru.lruCleanProduce.Call(ctx, workEvent)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if work, ok := workFunc.(event2.EventWorkFunc); ok {
|
|
||||||
workEvent.ExecWorkAndSendResult(work)
|
|
||||||
}
|
|
||||||
|
|
||||||
case TtlEventName:
|
|
||||||
if work, ok := workFunc.(event2.EventWorkFunc); ok {
|
|
||||||
workEvent.ExecWorkAndSendResult(work)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行过期事件
|
|
||||||
func (lru *SingleCache) lruTtlWork() {
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// 清理事件
|
|
||||||
go func() {
|
|
||||||
work := event2.EventWorkFunc(func() (interface{}, error) {
|
|
||||||
|
|
||||||
beforeTime := time.Now().Unix()
|
|
||||||
cle := lru.lruTtlManage.detachNum
|
|
||||||
if cle > len(lru.lruTtlManage.memoryKey) {
|
|
||||||
cle = len(lru.lruTtlManage.memoryKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
keys := make([]string, 0)
|
|
||||||
for i := 0; i < cle; i++ {
|
|
||||||
key := <-lru.lruTtlManage.memoryKey
|
|
||||||
keys = append(keys, key)
|
|
||||||
lru.delByKeyAndExTtl(key, beforeTime)
|
|
||||||
}
|
|
||||||
return keys, nil
|
|
||||||
})
|
|
||||||
|
|
||||||
cleanTTlTicker := time.NewTicker(500 * time.Millisecond)
|
|
||||||
defer cleanTTlTicker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
// 清理事件
|
|
||||||
<-cleanTTlTicker.C
|
|
||||||
if len(lru.lruTtlManage.memoryKey) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ttlEvent := lru.lruCleanProduce.NewEvent(TtlEventName)
|
|
||||||
ttlEvent.SetValue(event2.WorkFuncEventKey, work)
|
|
||||||
ttlEvent.InitWaitEvent()
|
|
||||||
|
|
||||||
lru.lruCleanProduce.Call(ctx, ttlEvent)
|
|
||||||
keys, err := ttlEvent.StartWaitEvent(time.Second * 2)
|
|
||||||
ttlEvent.Recovery()
|
|
||||||
|
|
||||||
mMsg.SendMiddleMsg(ctx, lru.middleProduce, mMsg.LruTTlContext{
|
|
||||||
Keys: keys.([]string),
|
|
||||||
CleanTime: time.Now(),
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logx.With(ctx, lru.middleProduce).Errorln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 收集事件
|
|
||||||
for {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
lru.lruTtlManage.ttlKeyToMemoryBySecond()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (lru *SingleCache) cleanWork() {
|
|
||||||
cxt := context.Background()
|
|
||||||
work := event.EventWorkFunc(func() (interface{}, error) {
|
|
||||||
err := lru.DelToClearSize()
|
|
||||||
return nil, err
|
|
||||||
})
|
|
||||||
|
|
||||||
for {
|
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
|
||||||
if lru.clearSize < lru.nowSize {
|
|
||||||
lruCleanEvent := lru.lruCleanProduce.NewEvent(CleanEventName)
|
|
||||||
lruCleanEvent.SetValue(event2.WorkFuncEventKey, work)
|
|
||||||
|
|
||||||
lruCleanEvent.InitWaitEvent()
|
|
||||||
lru.lruCleanProduce.Call(cxt, lruCleanEvent)
|
|
||||||
_, err := lruCleanEvent.StartWaitEvent(defaultWaitTime)
|
|
||||||
if err != nil {
|
|
||||||
logx.With(cxt, lru.middleProduce).Errorln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 归还
|
|
||||||
lruCleanEvent.Recovery()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package middlemsg
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
MiddleMsgKey = "middleMsgKey"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SendMiddleMsg(
|
|
||||||
ctx context.Context,
|
|
||||||
middleProduce event.ProduceInterface,
|
|
||||||
val interface{},
|
|
||||||
) error {
|
|
||||||
if middleProduce == nil {
|
|
||||||
return errorx.New("middleProduce not is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventName string
|
|
||||||
|
|
||||||
switch val.(type) {
|
|
||||||
case *LogContext:
|
|
||||||
eventName = LogContextName
|
|
||||||
case *LruCleanContext:
|
|
||||||
eventName = LruCleanContextName
|
|
||||||
case *LruTTlContext:
|
|
||||||
eventName = LruTTlContextName
|
|
||||||
case *PulginsInfos:
|
|
||||||
eventName = PulginsInfosName
|
|
||||||
}
|
|
||||||
|
|
||||||
msgEvent := middleProduce.NewEvent(eventName)
|
|
||||||
msgEvent.SetValue(MiddleMsgKey, val)
|
|
||||||
middleProduce.Call(ctx, msgEvent)
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package middlemsg
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
var (
|
|
||||||
LogContextName = "log-context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LogContext struct {
|
|
||||||
Level string
|
|
||||||
Data time.Time
|
|
||||||
Msg string
|
|
||||||
Route string
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package middlemsg
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
const LruCleanContextName = "lru-clean-context"
|
|
||||||
|
|
||||||
type LruCleanContext struct {
|
|
||||||
Keys []string
|
|
||||||
BeforeCleanSize int64
|
|
||||||
BehindCleanSize int64
|
|
||||||
|
|
||||||
StartTime time.Time
|
|
||||||
EndTime time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
const LruTTlContextName = "lru-ttl-context"
|
|
||||||
|
|
||||||
type LruTTlContext struct {
|
|
||||||
Keys []string
|
|
||||||
CleanTime time.Time
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package middlemsg
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PulginsInfosName = "plugins-infos-context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PulginsInfo struct {
|
|
||||||
Version string
|
|
||||||
Desc string
|
|
||||||
Name string
|
|
||||||
Statux string
|
|
||||||
Time time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type PulginsInfos struct {
|
|
||||||
Infos []*PulginsInfo
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package middle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
oneMiddle sync.Once
|
|
||||||
middleWareDriver *MiddleWare
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultConsumerCount = 5
|
|
||||||
defaultDriverCount = 1000
|
|
||||||
)
|
|
|
@ -0,0 +1 @@
|
||||||
|
package define
|
|
@ -1,74 +0,0 @@
|
||||||
package middle
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "gitee.com/wheat-os/wheatCache/conf"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
"gitee.com/wheat-os/wheatCache/plugins"
|
|
||||||
"gitee.com/wheat-os/wheatCache/plugins/config"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MiddleWare struct {
|
|
||||||
eventDriver event.DriverInterface
|
|
||||||
eventConsumer event.ConsumerInterface
|
|
||||||
eventProduce event.ProduceInterface
|
|
||||||
plugins map[string][]plugins.PluginInterface
|
|
||||||
consumerCount int
|
|
||||||
driverCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMiddleWare() *MiddleWare {
|
|
||||||
oneMiddle.Do(func() {
|
|
||||||
consumerCount, driverCount := loadConfigAndDefault()
|
|
||||||
|
|
||||||
driver := event.NewDriver(driverCount)
|
|
||||||
middleWareDriver = &MiddleWare{
|
|
||||||
eventDriver: driver,
|
|
||||||
eventConsumer: event.NewConsumer(driver),
|
|
||||||
eventProduce: event.NewProduce(driver),
|
|
||||||
driverCount: driverCount,
|
|
||||||
consumerCount: consumerCount,
|
|
||||||
}
|
|
||||||
middleWareDriver.loadPlugins()
|
|
||||||
|
|
||||||
// 多消费 middle
|
|
||||||
middleWareDriver.startWork()
|
|
||||||
})
|
|
||||||
return middleWareDriver
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MiddleWare) GetEventDriver() event.DriverInterface {
|
|
||||||
return m.eventDriver
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MiddleWare) loadPlugins() {
|
|
||||||
plug := viper.GetStringMapStringSlice("plugins-control")
|
|
||||||
|
|
||||||
pluginsMap := config.GetMiddlewareMap()
|
|
||||||
|
|
||||||
pluginsContext := make(map[string][]plugins.PluginInterface)
|
|
||||||
|
|
||||||
for msg, pluNames := range plug {
|
|
||||||
pulgSingle := make([]plugins.PluginInterface, 0)
|
|
||||||
for _, name := range pluNames {
|
|
||||||
pulgSingle = append(pulgSingle, pluginsMap[name])
|
|
||||||
}
|
|
||||||
|
|
||||||
pluginsContext[msg] = pulgSingle
|
|
||||||
}
|
|
||||||
|
|
||||||
m.plugins = pluginsContext
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConfigAndDefault() (int, int) {
|
|
||||||
// 加载 consumerCount
|
|
||||||
consumerCount := viper.GetInt("middle-driver.middleConsumerCount")
|
|
||||||
if consumerCount == 0 {
|
|
||||||
consumerCount = defaultConsumerCount
|
|
||||||
}
|
|
||||||
driverCount := viper.GetInt("middle-driver.driverCount")
|
|
||||||
if driverCount == 0 {
|
|
||||||
driverCount = defaultDriverCount
|
|
||||||
}
|
|
||||||
return consumerCount, driverCount
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package middle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/logx"
|
|
||||||
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (m *MiddleWare) startWork() {
|
|
||||||
|
|
||||||
for i := 0; i < m.consumerCount; i++ {
|
|
||||||
go func() {
|
|
||||||
ctx := context.Background()
|
|
||||||
for {
|
|
||||||
workEvent := m.eventConsumer.Receive(ctx)
|
|
||||||
plugs := m.plugins[workEvent.GetEventName()]
|
|
||||||
msg, ok := workEvent.GetValue(middleMsg.MiddleMsgKey)
|
|
||||||
m.eventConsumer.Recovery(workEvent)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
logx.With(ctx, m.eventProduce).Error("get event value err,not key:%s", middleMsg.MiddleMsgKey)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送事件到 全部的 plugs 里
|
|
||||||
for _, val := range plugs {
|
|
||||||
_, err := val.Exec(msg)
|
|
||||||
if err != nil {
|
|
||||||
logx.With(ctx, m.eventProduce).Errorln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package middle
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/event"
|
|
||||||
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_middleware_loadPlugins(t *testing.T) {
|
|
||||||
m := NewMiddleWare()
|
|
||||||
m.loadPlugins()
|
|
||||||
|
|
||||||
fmt.Println(m.plugins)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWorker(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
m := NewMiddleWare()
|
|
||||||
|
|
||||||
product := event.NewProduce(m.GetEventDriver())
|
|
||||||
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.LogContext{
|
|
||||||
Msg: "debug msg",
|
|
||||||
})
|
|
||||||
|
|
||||||
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.PulginsInfos{
|
|
||||||
Infos: []*middleMsg.PulginsInfo{
|
|
||||||
{
|
|
||||||
Desc: "miss",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.LruTTlContext{
|
|
||||||
Keys: []string{"1", "2", "3"},
|
|
||||||
})
|
|
||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
|
@ -1,218 +0,0 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.26.0
|
|
||||||
// protoc v3.17.3
|
|
||||||
// source: base.proto
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type BaseKey struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
Ttl int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"`
|
|
||||||
Expire *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expire,proto3" json:"expire,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *BaseKey) Reset() {
|
|
||||||
*x = BaseKey{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_base_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *BaseKey) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*BaseKey) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *BaseKey) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_base_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use BaseKey.ProtoReflect.Descriptor instead.
|
|
||||||
func (*BaseKey) Descriptor() ([]byte, []int) {
|
|
||||||
return file_base_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *BaseKey) GetKey() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Key
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *BaseKey) GetTtl() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Ttl
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *BaseKey) GetExpire() *timestamppb.Timestamp {
|
|
||||||
if x != nil {
|
|
||||||
return x.Expire
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type External struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *External) Reset() {
|
|
||||||
*x = External{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_base_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *External) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*External) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *External) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_base_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use External.ProtoReflect.Descriptor instead.
|
|
||||||
func (*External) Descriptor() ([]byte, []int) {
|
|
||||||
return file_base_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_base_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_base_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f,
|
|
||||||
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69,
|
|
||||||
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x61, 0x0a,
|
|
||||||
0x07, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
|
||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74,
|
|
||||||
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x32, 0x0a, 0x06,
|
|
||||||
0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
|
|
||||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
|
|
||||||
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65,
|
|
||||||
0x22, 0x0a, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x0b, 0x5a, 0x09,
|
|
||||||
0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_base_proto_rawDescOnce sync.Once
|
|
||||||
file_base_proto_rawDescData = file_base_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_base_proto_rawDescGZIP() []byte {
|
|
||||||
file_base_proto_rawDescOnce.Do(func() {
|
|
||||||
file_base_proto_rawDescData = protoimpl.X.CompressGZIP(file_base_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_base_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_base_proto_goTypes = []interface{}{
|
|
||||||
(*BaseKey)(nil), // 0: BaseKey
|
|
||||||
(*External)(nil), // 1: External
|
|
||||||
(*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp
|
|
||||||
}
|
|
||||||
var file_base_proto_depIdxs = []int32{
|
|
||||||
2, // 0: BaseKey.expire:type_name -> google.protobuf.Timestamp
|
|
||||||
1, // [1:1] is the sub-list for method output_type
|
|
||||||
1, // [1:1] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_base_proto_init() }
|
|
||||||
func file_base_proto_init() {
|
|
||||||
if File_base_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_base_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*BaseKey); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_base_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*External); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_base_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_base_proto_goTypes,
|
|
||||||
DependencyIndexes: file_base_proto_depIdxs,
|
|
||||||
MessageInfos: file_base_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_base_proto = out.File
|
|
||||||
file_base_proto_rawDesc = nil
|
|
||||||
file_base_proto_goTypes = nil
|
|
||||||
file_base_proto_depIdxs = nil
|
|
||||||
}
|
|
|
@ -1,733 +0,0 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.26.0
|
|
||||||
// protoc v3.17.3
|
|
||||||
// source: channelx.proto
|
|
||||||
|
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type CPushRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
Value []string `protobuf:"bytes,2,rep,name=value,proto3" json:"value,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPushRequest) Reset() {
|
|
||||||
*x = CPushRequest{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPushRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CPushRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CPushRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CPushRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CPushRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPushRequest) GetKey() *BaseKey {
|
|
||||||
if x != nil {
|
|
||||||
return x.Key
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPushRequest) GetValue() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Value
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CPushResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
E *External `protobuf:"bytes,1,opt,name=e,proto3" json:"e,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPushResponse) Reset() {
|
|
||||||
*x = CPushResponse{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPushResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CPushResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CPushResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CPushResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CPushResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPushResponse) GetE() *External {
|
|
||||||
if x != nil {
|
|
||||||
return x.E
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CPopRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
Count int32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopRequest) Reset() {
|
|
||||||
*x = CPopRequest{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CPopRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CPopRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[2]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CPopRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CPopRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopRequest) GetKey() *BaseKey {
|
|
||||||
if x != nil {
|
|
||||||
return x.Key
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopRequest) GetCount() int32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Count
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type CPopResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
E *External `protobuf:"bytes,1,opt,name=e,proto3" json:"e,omitempty"`
|
|
||||||
Result []string `protobuf:"bytes,2,rep,name=result,proto3" json:"result,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopResponse) Reset() {
|
|
||||||
*x = CPopResponse{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CPopResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CPopResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[3]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CPopResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CPopResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopResponse) GetE() *External {
|
|
||||||
if x != nil {
|
|
||||||
return x.E
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CPopResponse) GetResult() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Result
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CMakeRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
Length int32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CMakeRequest) Reset() {
|
|
||||||
*x = CMakeRequest{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[4]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CMakeRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CMakeRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CMakeRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[4]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CMakeRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CMakeRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{4}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CMakeRequest) GetKey() *BaseKey {
|
|
||||||
if x != nil {
|
|
||||||
return x.Key
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CMakeRequest) GetLength() int32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Length
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type CMakeResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CMakeResponse) Reset() {
|
|
||||||
*x = CMakeResponse{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[5]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CMakeResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CMakeResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CMakeResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[5]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CMakeResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CMakeResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{5}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CLenRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CLenRequest) Reset() {
|
|
||||||
*x = CLenRequest{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[6]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CLenRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CLenRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CLenRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[6]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CLenRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CLenRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{6}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CLenRequest) GetKey() *BaseKey {
|
|
||||||
if x != nil {
|
|
||||||
return x.Key
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CLenResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Length int32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CLenResponse) Reset() {
|
|
||||||
*x = CLenResponse{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[7]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CLenResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CLenResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CLenResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[7]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CLenResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CLenResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{7}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CLenResponse) GetLength() int32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Length
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type CCleanRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CCleanRequest) Reset() {
|
|
||||||
*x = CCleanRequest{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[8]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CCleanRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CCleanRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CCleanRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[8]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CCleanRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CCleanRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{8}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CCleanRequest) GetKey() *BaseKey {
|
|
||||||
if x != nil {
|
|
||||||
return x.Key
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type CCleanResponse struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CCleanResponse) Reset() {
|
|
||||||
*x = CCleanResponse{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_channelx_proto_msgTypes[9]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CCleanResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CCleanResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CCleanResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_channelx_proto_msgTypes[9]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CCleanResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CCleanResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_channelx_proto_rawDescGZIP(), []int{9}
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_channelx_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_channelx_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x1a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x0c,
|
|
||||||
0x43, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03,
|
|
||||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65,
|
|
||||||
0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
|
|
||||||
0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x28,
|
|
||||||
0x0a, 0x0d, 0x43, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
|
||||||
0x17, 0x0a, 0x01, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x45, 0x78, 0x74,
|
|
||||||
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52, 0x01, 0x65, 0x22, 0x3f, 0x0a, 0x0b, 0x43, 0x50, 0x6f, 0x70,
|
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03,
|
|
||||||
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
|
|
||||||
0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3f, 0x0a, 0x0c, 0x43, 0x50, 0x6f,
|
|
||||||
0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x01, 0x65, 0x18, 0x01,
|
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52,
|
|
||||||
0x01, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x03,
|
|
||||||
0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x42, 0x0a, 0x0c, 0x43, 0x4d,
|
|
||||||
0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65,
|
|
||||||
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65,
|
|
||||||
0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x0f,
|
|
||||||
0x0a, 0x0d, 0x43, 0x4d, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
|
||||||
0x29, 0x0a, 0x0b, 0x43, 0x4c, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
|
|
||||||
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61,
|
|
||||||
0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x26, 0x0a, 0x0c, 0x43, 0x4c,
|
|
||||||
0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65,
|
|
||||||
0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67,
|
|
||||||
0x74, 0x68, 0x22, 0x2b, 0x0a, 0x0d, 0x43, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
|
||||||
0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
|
||||||
0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22,
|
|
||||||
0x10, 0x0a, 0x0e, 0x43, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
|
||||||
0x65, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_channelx_proto_rawDescOnce sync.Once
|
|
||||||
file_channelx_proto_rawDescData = file_channelx_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_channelx_proto_rawDescGZIP() []byte {
|
|
||||||
file_channelx_proto_rawDescOnce.Do(func() {
|
|
||||||
file_channelx_proto_rawDescData = protoimpl.X.CompressGZIP(file_channelx_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_channelx_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_channelx_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
|
||||||
var file_channelx_proto_goTypes = []interface{}{
|
|
||||||
(*CPushRequest)(nil), // 0: CPushRequest
|
|
||||||
(*CPushResponse)(nil), // 1: CPushResponse
|
|
||||||
(*CPopRequest)(nil), // 2: CPopRequest
|
|
||||||
(*CPopResponse)(nil), // 3: CPopResponse
|
|
||||||
(*CMakeRequest)(nil), // 4: CMakeRequest
|
|
||||||
(*CMakeResponse)(nil), // 5: CMakeResponse
|
|
||||||
(*CLenRequest)(nil), // 6: CLenRequest
|
|
||||||
(*CLenResponse)(nil), // 7: CLenResponse
|
|
||||||
(*CCleanRequest)(nil), // 8: CCleanRequest
|
|
||||||
(*CCleanResponse)(nil), // 9: CCleanResponse
|
|
||||||
(*BaseKey)(nil), // 10: BaseKey
|
|
||||||
(*External)(nil), // 11: External
|
|
||||||
}
|
|
||||||
var file_channelx_proto_depIdxs = []int32{
|
|
||||||
10, // 0: CPushRequest.key:type_name -> BaseKey
|
|
||||||
11, // 1: CPushResponse.e:type_name -> External
|
|
||||||
10, // 2: CPopRequest.key:type_name -> BaseKey
|
|
||||||
11, // 3: CPopResponse.e:type_name -> External
|
|
||||||
10, // 4: CMakeRequest.key:type_name -> BaseKey
|
|
||||||
10, // 5: CLenRequest.key:type_name -> BaseKey
|
|
||||||
10, // 6: CCleanRequest.key:type_name -> BaseKey
|
|
||||||
7, // [7:7] is the sub-list for method output_type
|
|
||||||
7, // [7:7] is the sub-list for method input_type
|
|
||||||
7, // [7:7] is the sub-list for extension type_name
|
|
||||||
7, // [7:7] is the sub-list for extension extendee
|
|
||||||
0, // [0:7] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_channelx_proto_init() }
|
|
||||||
func file_channelx_proto_init() {
|
|
||||||
if File_channelx_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file_base_proto_init()
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_channelx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CPushRequest); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CPushResponse); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CPopRequest); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CPopResponse); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CMakeRequest); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CMakeResponse); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CLenRequest); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CLenResponse); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CCleanRequest); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_channelx_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*CCleanResponse); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_channelx_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 10,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_channelx_proto_goTypes,
|
|
||||||
DependencyIndexes: file_channelx_proto_depIdxs,
|
|
||||||
MessageInfos: file_channelx_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_channelx_proto = out.File
|
|
||||||
file_channelx_proto_rawDesc = nil
|
|
||||||
file_channelx_proto_goTypes = nil
|
|
||||||
file_channelx_proto_depIdxs = nil
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package proto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GetKeyBaseInterface interface {
|
|
||||||
GetKey() *BaseKey
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
BaseKeyMethodKey = "basekey"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewBaseKey
|
|
||||||
// key,ttl,expire
|
|
||||||
func NewBaseKey(key string, t ...int64) *BaseKey {
|
|
||||||
var expire *timestamppb.Timestamp = nil
|
|
||||||
var ttl int64
|
|
||||||
|
|
||||||
if len(t) > 1 {
|
|
||||||
expire = ×tamppb.Timestamp{
|
|
||||||
Seconds: t[1],
|
|
||||||
}
|
|
||||||
ttl = t[0]
|
|
||||||
} else if len(t) == 1 {
|
|
||||||
ttl = t[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return &BaseKey{
|
|
||||||
Key: key,
|
|
||||||
Expire: expire,
|
|
||||||
Ttl: ttl,
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1913
pkg/proto/setx.pb.go
1913
pkg/proto/setx.pb.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,66 +0,0 @@
|
||||||
package channelx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/structure"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChannelX struct {
|
|
||||||
channel chan *structure.Value
|
|
||||||
sizeByte int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeChannelX(length int) structure.ChannelXInterface {
|
|
||||||
return &ChannelX{
|
|
||||||
channel: make(chan *structure.Value, length),
|
|
||||||
sizeByte: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChannelX) SizeByte() int64 {
|
|
||||||
return c.sizeByte
|
|
||||||
}
|
|
||||||
|
|
||||||
// RollBack TODO 事务相关, V2 实现
|
|
||||||
func (c *ChannelX) RollBack() error {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin 事务相关, V2 实现
|
|
||||||
func (c *ChannelX) Begin() error {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comment 事务相关, V2 实现
|
|
||||||
func (c *ChannelX) Comment() error {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChannelX) Encode() ([]byte, error) {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChannelX) Push(value string) structure.UpdateLength {
|
|
||||||
val := structure.NewValue(value)
|
|
||||||
up := val.GetSize()
|
|
||||||
c.channel <- val
|
|
||||||
atomic.AddInt64(&c.sizeByte, int64(up))
|
|
||||||
return structure.UpdateLength(up)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChannelX) Pop() (string, structure.UpdateLength) {
|
|
||||||
val := <-c.channel
|
|
||||||
return val.ToString(), structure.UpdateLength(val.GetSize()) * -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChannelX) Length() int {
|
|
||||||
return len(c.channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ChannelX) Clean() structure.UpdateLength {
|
|
||||||
c.channel = make(chan *structure.Value, cap(c.channel))
|
|
||||||
up := c.sizeByte
|
|
||||||
c.sizeByte = 0
|
|
||||||
return structure.UpdateLength(up) * -1
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package channelx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestChannelX_Push(t *testing.T) {
|
|
||||||
c := MakeChannelX(10)
|
|
||||||
require.Equal(t, c.Length(), 0)
|
|
||||||
|
|
||||||
up := c.Push("111")
|
|
||||||
require.Equal(t, 24, int(up))
|
|
||||||
|
|
||||||
res, up := c.Pop()
|
|
||||||
require.Equal(t, -24, int(up))
|
|
||||||
require.Equal(t, res, "111")
|
|
||||||
|
|
||||||
up = c.Push("111")
|
|
||||||
c.Clean()
|
|
||||||
|
|
||||||
require.Equal(t, c.Length(), 0)
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
package structure
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultLen = 8 // 默认创建的 value 大小
|
|
||||||
)
|
|
||||||
|
|
||||||
type DynamicType int8
|
|
||||||
|
|
||||||
type UpdateLength int64
|
|
||||||
|
|
||||||
const (
|
|
||||||
DynamicNull = DynamicType(iota)
|
|
||||||
DynamicInt
|
|
||||||
DynamicFloat
|
|
||||||
DynamicString
|
|
||||||
)
|
|
||||||
|
|
||||||
type KeyBaseInterface interface {
|
|
||||||
SizeByte() int64
|
|
||||||
|
|
||||||
// RollBack TODO 事务相关, V2 实现
|
|
||||||
RollBack() error
|
|
||||||
// Begin 事务相关, V2 实现
|
|
||||||
Begin() error
|
|
||||||
// Comment 事务相关, V2 实现
|
|
||||||
Comment() error
|
|
||||||
|
|
||||||
Encode() ([]byte, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type StringXInterface interface {
|
|
||||||
KeyBaseInterface
|
|
||||||
Set(string) (string, UpdateLength)
|
|
||||||
Get() string
|
|
||||||
Add(int32) (string, error)
|
|
||||||
Reduce(int32) (string, error)
|
|
||||||
Setbit(int32, bool) UpdateLength
|
|
||||||
Getbit(int32) (bool, error)
|
|
||||||
Getrange(start, end int32) (string, error)
|
|
||||||
GetLength() int
|
|
||||||
}
|
|
||||||
|
|
||||||
type ListXInterface interface {
|
|
||||||
KeyBaseInterface
|
|
||||||
LPush(...string) UpdateLength
|
|
||||||
RPush(...string) UpdateLength
|
|
||||||
LPop(int) ([]string, UpdateLength)
|
|
||||||
RPop(int) ([]string, UpdateLength)
|
|
||||||
Index(int) (string, error)
|
|
||||||
Insert(int, bool, ...string) (UpdateLength, error)
|
|
||||||
Length() int
|
|
||||||
Slice(start, end int) (UpdateLength, error) // 切片, O(n)复杂度
|
|
||||||
Range(start, end int) ([]string, error)
|
|
||||||
Remove(value string, count int) (int, UpdateLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
type HashXInterface interface {
|
|
||||||
KeyBaseInterface
|
|
||||||
Set(key string, val string) UpdateLength
|
|
||||||
Get(key string) (string, error)
|
|
||||||
Del(key string) (UpdateLength, error)
|
|
||||||
Key() []string
|
|
||||||
Value() []string
|
|
||||||
Item() map[string]string
|
|
||||||
Add(renewal int, key ...string) (int, []string, error) // 访问影响成功的结果
|
|
||||||
SetX(key string, val string) (bool, UpdateLength) // 不存在才插入
|
|
||||||
Length() int
|
|
||||||
Range(consur, count int, regex string) []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChannelXInterface interface {
|
|
||||||
KeyBaseInterface
|
|
||||||
Push(value string) UpdateLength
|
|
||||||
Pop() (string, UpdateLength)
|
|
||||||
Length() int
|
|
||||||
Clean() UpdateLength
|
|
||||||
}
|
|
|
@ -1,157 +0,0 @@
|
||||||
package hashx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/errorx"
|
|
||||||
"gitee.com/wheat-os/wheatCache/pkg/structure"
|
|
||||||
)
|
|
||||||
|
|
||||||
type HashX map[string]*structure.Value
|
|
||||||
|
|
||||||
func NewHashXSingle() structure.HashXInterface {
|
|
||||||
return make(HashX)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) SizeByte() int64 {
|
|
||||||
var size int
|
|
||||||
for _, val := range h {
|
|
||||||
size += val.GetSize()
|
|
||||||
}
|
|
||||||
return int64(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RollBack TODO 事务相关, V2 实现
|
|
||||||
func (h HashX) RollBack() error {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
// Begin 事务相关, V2 实现
|
|
||||||
func (h HashX) Begin() error {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comment 事务相关, V2 实现
|
|
||||||
func (h HashX) Comment() error {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Encode() ([]byte, error) {
|
|
||||||
panic("not implemented") // TODO: Implement
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Set(key string, val string) structure.UpdateLength {
|
|
||||||
|
|
||||||
var Length structure.UpdateLength
|
|
||||||
if v, ok := h[key]; ok {
|
|
||||||
Length -= structure.UpdateLength(v.GetSize())
|
|
||||||
}
|
|
||||||
|
|
||||||
strVal := structure.NewValue(val)
|
|
||||||
h[key] = strVal
|
|
||||||
return Length + structure.UpdateLength(strVal.GetSize())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Get(key string) (string, error) {
|
|
||||||
if v, ok := h[key]; ok {
|
|
||||||
return v.ToString(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errorx.New("this key does not exist in hashx, key:%s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Del(key string) (structure.UpdateLength, error) {
|
|
||||||
if v, ok := h[key]; ok {
|
|
||||||
delete(h, key)
|
|
||||||
return structure.UpdateLength(v.GetSize()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, errorx.New("this key does not exist in hashx, key:%s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Key() []string {
|
|
||||||
result := make([]string, 0, len(h))
|
|
||||||
for key := range h {
|
|
||||||
result = append(result, key)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Value() []string {
|
|
||||||
result := make([]string, 0, len(h))
|
|
||||||
for _, val := range h {
|
|
||||||
result = append(result, val.ToString())
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Item() map[string]string {
|
|
||||||
result := make(map[string]string, len(h))
|
|
||||||
for key, val := range h {
|
|
||||||
result[key] = val.ToString()
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Add(renewal int, keys ...string) (count int, result []string, err error) {
|
|
||||||
for _, key := range keys {
|
|
||||||
if v, ok := h[key]; ok {
|
|
||||||
res, err := v.Incr(int32(renewal))
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
count += 1
|
|
||||||
result = append(result, res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count, result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) SetX(key string, val string) (bool, structure.UpdateLength) {
|
|
||||||
if _, ok := h[key]; ok {
|
|
||||||
return false, 0
|
|
||||||
}
|
|
||||||
strVal := structure.NewValue(val)
|
|
||||||
h[key] = strVal
|
|
||||||
return true, structure.UpdateLength(strVal.GetSize())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Length() int {
|
|
||||||
return len(h)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h HashX) Range(consur, count int, regex string) []string {
|
|
||||||
|
|
||||||
var reComp *regexp.Regexp
|
|
||||||
if regex == "" {
|
|
||||||
reComp = nil
|
|
||||||
} else {
|
|
||||||
reComp = regexp.MustCompile(regex)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]string, 0)
|
|
||||||
for _, val := range h {
|
|
||||||
if consur > 0 {
|
|
||||||
consur--
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if count == 0 && count != -1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
s := val.ToString()
|
|
||||||
if reComp == nil {
|
|
||||||
count--
|
|
||||||
result = append(result, s)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if reComp.MatchString(s) {
|
|
||||||
count--
|
|
||||||
result = append(result, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue