Apply .gitignore rules
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
未实现的哈希表方法:
|
||||
MOVE、SCAN、SORT、FLUSHDB、FLUSHALL、SELECT、SWAPDB
|
||||
*/
|
||||
package redisUtil
|
||||
|
||||
import (
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
/*
|
||||
EXISTS key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
检查给定 key 是否存在。
|
||||
|
||||
返回值
|
||||
若 key 存在,返回 1 ,否则返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) Exists(key string) (exist bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
result, err = redis.Int(conn.Do("EXISTS", key))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if result == 1 {
|
||||
exist = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
TYPE key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
返回 key 所储存的值的类型。
|
||||
|
||||
返回值
|
||||
none (key不存在)
|
||||
|
||||
string (字符串)
|
||||
|
||||
list (列表)
|
||||
|
||||
set (集合)
|
||||
|
||||
zset (有序集)
|
||||
|
||||
hash (哈希表)
|
||||
|
||||
stream (流)
|
||||
*/
|
||||
func (this *RedisPool) Type(key string) (_type string, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
_type, err = redis.String(conn.Do("TYPE", key))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
RENAME key newkey
|
||||
|
||||
将 key 改名为 newkey 。
|
||||
|
||||
当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。
|
||||
|
||||
当 newkey 已经存在时, RENAME 命令将覆盖旧值。
|
||||
|
||||
可用版本:
|
||||
>= 1.0.0
|
||||
时间复杂度:
|
||||
O(1)
|
||||
返回值:
|
||||
改名成功时提示 OK ,失败时候返回一个错误。
|
||||
*/
|
||||
func (this *RedisPool) Rename(key, newkey string) (err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
_, err = conn.Do("RENAME", key, newkey)
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
RENAMENX key newkey
|
||||
|
||||
当且仅当 newkey 不存在时,将 key 改名为 newkey 。
|
||||
|
||||
当 key 不存在时,返回一个错误。
|
||||
|
||||
可用版本:
|
||||
>= 1.0.0
|
||||
时间复杂度:
|
||||
O(1)
|
||||
返回值:
|
||||
修改成功时,返回 1 。
|
||||
如果 newkey 已经存在,返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) RenameNX(key, newkey string) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
result, err = redis.Int(conn.Do("RENAMENX", key, newkey))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if result == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DEL key [key ...]
|
||||
|
||||
删除给定的一个或多个 key 。
|
||||
|
||||
不存在的 key 会被忽略。
|
||||
|
||||
可用版本:
|
||||
>= 1.0.0
|
||||
时间复杂度:
|
||||
O(N), N 为被删除的 key 的数量。
|
||||
删除单个字符串类型的 key ,时间复杂度为O(1)。
|
||||
删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为O(M), M 为以上数据结构内的元素数量。
|
||||
返回值:
|
||||
被删除 key 的数量。
|
||||
*/
|
||||
func (this *RedisPool) Del(keys ...string) (count int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
count, err = redis.Int(conn.Do("DEL", redis.Args{}.AddFlat(keys)...))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
从当前数据库中随机返回(不删除)一个 key 。
|
||||
|
||||
可用版本:
|
||||
>= 1.0.0
|
||||
时间复杂度:
|
||||
O(1)
|
||||
返回值:
|
||||
当数据库不为空时,返回一个 key 。
|
||||
当数据库为空时,返回 nil 。
|
||||
*/
|
||||
func (this *RedisPool) RandomKey() (key string, exist bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var reply interface{}
|
||||
reply, err = conn.Do("RANDOMKEY")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if reply == nil {
|
||||
return
|
||||
}
|
||||
|
||||
key, err = redis.String(reply, err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
exist = true
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
DBSIZE
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
返回当前数据库的 key 的数量。
|
||||
|
||||
返回值
|
||||
当前数据库的 key 的数量。
|
||||
*/
|
||||
func (this *RedisPool) DBSize() (keyCount int, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
keyCount, err = redis.Int(conn.Do("DBSIZE"))
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
KEYS pattern
|
||||
|
||||
查找所有符合给定模式 pattern 的 key 。
|
||||
|
||||
KEYS * 匹配数据库中所有 key 。
|
||||
KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
|
||||
KEYS h*llo 匹配 hllo 和 heeeeello 等。
|
||||
KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo 。
|
||||
特殊符号用 \ 隔开
|
||||
|
||||
KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 key ,你最好还是用 Redis 的集合结构(set)来代替。
|
||||
可用版本:
|
||||
>= 1.0.0
|
||||
时间复杂度:
|
||||
O(N), N 为数据库中 key 的数量。
|
||||
返回值:
|
||||
符合给定模式的 key 列表。
|
||||
*/
|
||||
func (this *RedisPool) Keys(pattern string) (keyList []string, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
keyList, err = redis.Strings(conn.Do("KEYS", pattern))
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
package coroutine_timer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"goutil/logUtil"
|
||||
"goutil/stringUtil"
|
||||
)
|
||||
|
||||
const (
|
||||
// 启动暂停时间
|
||||
con_STAR_SLEEP_NUM = 3
|
||||
|
||||
// 秒级定时器卡槽数量
|
||||
con_SECOND_SLOT_NUM = 60
|
||||
|
||||
//分钟级定时器卡槽数量
|
||||
con_MINUTES_SLOT_NUM = 60
|
||||
)
|
||||
|
||||
var (
|
||||
// 秒级定时器下标
|
||||
secIndex = 0
|
||||
|
||||
// 秒级定时器当前开始时间
|
||||
secondStarTime int64
|
||||
|
||||
// 秒级定时器槽
|
||||
secondsTimers [con_SECOND_SLOT_NUM]*timersModel
|
||||
|
||||
// 分钟级定时器下标
|
||||
minIndex = 0
|
||||
|
||||
// 分钟级定时器当前开始时间
|
||||
minStarTime int64
|
||||
|
||||
// 分钟级定时器槽
|
||||
minutesTimers [con_MINUTES_SLOT_NUM]*timersModel
|
||||
|
||||
// 其他定时器存放槽
|
||||
otherTimers *timersModel
|
||||
|
||||
// 操作通道
|
||||
cmdChan chan *cmdModel
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := 0; i < con_SECOND_SLOT_NUM; i++ {
|
||||
secondsTimers[i] = newTimersModel()
|
||||
}
|
||||
for i := 0; i < con_MINUTES_SLOT_NUM; i++ {
|
||||
minutesTimers[i] = newTimersModel()
|
||||
}
|
||||
|
||||
otherTimers = newTimersModel()
|
||||
cmdChan = make(chan *cmdModel, 1000)
|
||||
secondStarTime = time.Now().Unix()
|
||||
minStarTime = secondStarTime + con_SECOND_SLOT_NUM
|
||||
|
||||
go chanHandler()
|
||||
}
|
||||
|
||||
// AddTimer
|
||||
// @description: 添加定时回调
|
||||
// parameter:
|
||||
//
|
||||
// @afterSecond:延后多少时间执行
|
||||
// @exfun:执行方法
|
||||
// @obj:执行传入的参数
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @string:
|
||||
func AddTimer(afterSecond int, exfun func(interface{}), obj interface{}) string {
|
||||
tick := time.Now().Unix() + int64(afterSecond)
|
||||
return AddTimer3(tick, exfun, obj)
|
||||
}
|
||||
|
||||
// AddTimer2
|
||||
// @description: 添加定时回调
|
||||
// parameter:
|
||||
//
|
||||
// @t:执行时间点
|
||||
// @exfun:执行方法
|
||||
// @obj:执行传入的参数
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @string:
|
||||
func AddTimer2(t time.Time, exfun func(interface{}), obj interface{}) string {
|
||||
tick := t.Unix()
|
||||
return AddTimer3(tick, exfun, obj)
|
||||
}
|
||||
|
||||
// AddTimer3
|
||||
// @description: 添加定时回调
|
||||
// parameter:
|
||||
//
|
||||
// @tick:执行时间点
|
||||
// @exfun:执行方法
|
||||
// @obj:执行传入的参数
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @newId:
|
||||
func AddTimer3(tick int64, exfun func(interface{}), obj interface{}) (newId string) {
|
||||
newId = stringUtil.GetNewUUID()
|
||||
newObj := newTimerObj(newId, tick, exfun, obj)
|
||||
|
||||
cnm := newCmdModel(cmd_add, newObj)
|
||||
cmdChan <- cnm
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddTimer4
|
||||
// @description: 添加定时回调(此方法会在内部校验id,所以性能会比其他AddTimer方法低)
|
||||
// parameter:
|
||||
//
|
||||
// @id:定时id(外部需要自行保证id唯一)
|
||||
// @tick:执行时间点
|
||||
// @exfun:执行方法
|
||||
// @obj:执行传入的参数
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @err:
|
||||
func AddTimer4(id string, tick int64, exfun func(interface{}), obj interface{}) (err error) {
|
||||
newObj := newTimerObj(id, tick, exfun, obj)
|
||||
newObj.needCheckId = true
|
||||
|
||||
// 加入处理队列
|
||||
cnm := newCmdModel(cmd_add, newObj)
|
||||
cmdChan <- cnm
|
||||
|
||||
// 等待处理结束
|
||||
<-cnm.waitChan
|
||||
|
||||
// 返回处理结果
|
||||
err = cnm.err
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DeleteTimer
|
||||
// @description: 删除定时器
|
||||
// parameter:
|
||||
//
|
||||
// @id:
|
||||
//
|
||||
// return:
|
||||
func DeleteTimer(id string) {
|
||||
cnm := newCmdModel(cmd_del, id)
|
||||
cmdChan <- cnm
|
||||
}
|
||||
|
||||
// chanHandler
|
||||
// @description: channel处理
|
||||
// parameter:
|
||||
// return:
|
||||
func chanHandler() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logUtil.ErrorLog("coroutine-timer.excute err:%s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 暂停一下再处理,避免启动立即处理,其他数据还没准备好
|
||||
time.Sleep(con_STAR_SLEEP_NUM * time.Second)
|
||||
|
||||
at := time.After(time.Second * 1)
|
||||
for {
|
||||
select {
|
||||
case cm := <-cmdChan:
|
||||
switch cm.cmd {
|
||||
case cmd_add:
|
||||
cmdAdd(cm)
|
||||
case cmd_del:
|
||||
cmdDel(cm)
|
||||
}
|
||||
case <-at:
|
||||
// byron:需要处理时间后调导致跳时间的问题:调整后应该马上执行的
|
||||
|
||||
// 计算需要执行的次数
|
||||
n := time.Now().Unix() - secondStarTime - int64(secIndex)
|
||||
if n > 0 {
|
||||
|
||||
// 执行对应次数的方法 --- 正常应该只执行1此,调时间后,此处会追时间
|
||||
var i int64
|
||||
for i = 0; i < n; i++ {
|
||||
cmdRun()
|
||||
}
|
||||
}
|
||||
|
||||
at = time.After(time.Second * 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cmdAdd
|
||||
// @description: 添加定时器
|
||||
// parameter:
|
||||
//
|
||||
// @cm:
|
||||
//
|
||||
// return:
|
||||
func cmdAdd(cm *cmdModel) {
|
||||
newObj := cm.paramObj.(*timerObj)
|
||||
if newObj.needCheckId && checkTimerExist(newObj.id) {
|
||||
cm.err = fmt.Errorf("已经存在id=%s的timer", newObj.id)
|
||||
cm.waitChan <- struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
// 如果执行时间比当前时间小,则放入最近的调度卡槽,以便尽快执行
|
||||
tick := newObj.tick
|
||||
if tick <= (secondStarTime + int64(secIndex)) {
|
||||
tick = (secondStarTime + int64(secIndex)) + 1
|
||||
}
|
||||
|
||||
// 落在秒钟级别定时器上
|
||||
if tick < (secondStarTime + con_SECOND_SLOT_NUM) {
|
||||
index := (int)(tick - secondStarTime)
|
||||
secondsTimers[index].addTimer(newObj)
|
||||
cm.waitChan <- struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
// 落在分钟级别定时器上
|
||||
if tick < (minStarTime + con_MINUTES_SLOT_NUM*con_SECOND_SLOT_NUM) {
|
||||
index := (int)(tick-minStarTime) / con_SECOND_SLOT_NUM
|
||||
minutesTimers[index].addTimer(newObj)
|
||||
cm.waitChan <- struct{}{}
|
||||
return
|
||||
}
|
||||
|
||||
//落在小时级别定时器上
|
||||
otherTimers.addTimer(newObj)
|
||||
|
||||
// 返回操作完成
|
||||
cm.waitChan <- struct{}{}
|
||||
}
|
||||
|
||||
// cmdDel
|
||||
// @description: 删除timer
|
||||
// parameter:
|
||||
//
|
||||
// @cm:
|
||||
//
|
||||
// return:
|
||||
func cmdDel(cm *cmdModel) {
|
||||
id := cm.paramObj.(string)
|
||||
|
||||
// 移除秒级别定时器
|
||||
for _, item := range secondsTimers {
|
||||
item.delTimer(id)
|
||||
}
|
||||
|
||||
// 移除分种级定时器
|
||||
for _, item := range minutesTimers {
|
||||
item.delTimer(id)
|
||||
}
|
||||
|
||||
// 移除时钟级定时器
|
||||
otherTimers.delTimer(id)
|
||||
|
||||
// 返回操作完成
|
||||
cm.waitChan <- struct{}{}
|
||||
}
|
||||
|
||||
// cmdRun
|
||||
// @description: 运行定时器
|
||||
// parameter:
|
||||
// return:
|
||||
func cmdRun() {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logUtil.ErrorLog("coroutine-timer.inExcute err:%s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// 执行秒级定时器
|
||||
timers := getSencondTimers()
|
||||
if len(timers) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, t := range timers {
|
||||
go safeRun(t)
|
||||
}
|
||||
}
|
||||
|
||||
// checkTimerExist
|
||||
// @description: 校验timer是否存在
|
||||
// parameter:
|
||||
//
|
||||
// @id:id
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @bool:
|
||||
func checkTimerExist(id string) bool {
|
||||
// 秒级别定时器检测
|
||||
for _, item := range secondsTimers {
|
||||
if item.exist(id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 分种级定时器检测
|
||||
for _, item := range minutesTimers {
|
||||
if item.exist(id) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 时钟级定时器检测
|
||||
return otherTimers.exist(id)
|
||||
}
|
||||
|
||||
// getSencondTimers
|
||||
// @description: 获取秒级定时器
|
||||
// parameter:
|
||||
// return:
|
||||
//
|
||||
// @result:
|
||||
func getSencondTimers() (result []*timerObj) {
|
||||
// 获取对应slot里面的定时对象
|
||||
result = secondsTimers[secIndex].getAllTimers2()
|
||||
secondsTimers[secIndex] = newTimersModel()
|
||||
secIndex++
|
||||
|
||||
// 如果达到最大,则重新填装新的调度对象
|
||||
if secIndex == con_SECOND_SLOT_NUM {
|
||||
secIndex = 0
|
||||
secondStarTime = secondStarTime + con_SECOND_SLOT_NUM
|
||||
minTaskList := getMinutesTasks()
|
||||
for _, t := range minTaskList {
|
||||
index := t.tick - secondStarTime
|
||||
secondsTimers[index].addTimer(t)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// getMinutesTasks
|
||||
// @description: 获取分钟级定时器
|
||||
// parameter:
|
||||
// return:
|
||||
//
|
||||
// @result:
|
||||
func getMinutesTasks() (result []*timerObj) {
|
||||
// 获取对应slot里面的定时对象
|
||||
result = minutesTimers[minIndex].getAllTimers2()
|
||||
minutesTimers[minIndex] = newTimersModel()
|
||||
minIndex++
|
||||
|
||||
// 如果达到最大,则重新填装新的调度对象
|
||||
if minIndex == con_MINUTES_SLOT_NUM {
|
||||
reInputMin()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// reInputMin
|
||||
// @description: 重新填入分钟级定时器
|
||||
// parameter:
|
||||
// return:
|
||||
func reInputMin() {
|
||||
minIndex = 0
|
||||
minStarTime = minStarTime + con_MINUTES_SLOT_NUM*con_SECOND_SLOT_NUM
|
||||
|
||||
delMap := make(map[string]struct{})
|
||||
for _, t := range otherTimers.getAllTimers() {
|
||||
index := (t.tick - minStarTime) / con_SECOND_SLOT_NUM
|
||||
if index > math.MaxInt || index >= con_MINUTES_SLOT_NUM {
|
||||
continue
|
||||
}
|
||||
minutesTimers[index].addTimer(t)
|
||||
delMap[t.id] = struct{}{}
|
||||
}
|
||||
|
||||
if len(delMap) > 0 {
|
||||
for k := range delMap {
|
||||
otherTimers.delTimer(k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// safeRun
|
||||
// @description: 安全运行定时器回调
|
||||
// parameter:
|
||||
//
|
||||
// @t:
|
||||
//
|
||||
// return:
|
||||
func safeRun(t *timerObj) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logUtil.ErrorLog("coroutine-timer.safeRun id:%s err:%s", t.id, err)
|
||||
}
|
||||
}()
|
||||
|
||||
t.excuteAction(t.paramObj)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#配置项说明
|
||||
log.es.enable=false #(false,默认值,关闭es日志记录,后续配置可不填写; true 打开日志记录)
|
||||
log.es.url= #(es服务地址)
|
||||
log.es.indexName=1 #(es服务中Index名)
|
||||
log.es.level=info #(debug|info|warn|error|fatal等级,等于或高于配置项则记录)
|
||||
|
||||
log.file.enable=false #(默认false)
|
||||
log.file.path=log #(运行目录下log目录,默认logs)
|
||||
log.file.pre=log #(文件名前缀,默认log)
|
||||
log.file.enableHour=true #(文件以小时划分,格式:yyyyMMddHH,默认true,false 一天一个文件,格式:yyyyMMdd)
|
||||
log.file.level=info
|
||||
|
||||
log.console.enable=false #(默认false)
|
||||
log.console.level=info
|
||||
|
||||
modelcenter.modelDBConnStr=root:moqikaka3306@tcp(10.255.0.10:3306)/xj_model_mr?charset=utf8&parseTime=true&loc=Local&timeout=60s||MaxOpenConns=10||MaxIdleConns=5 #(model数据库信息)
|
||||
Reference in New Issue
Block a user