mirror of
https://github.com/duanhf2012/origin.git
synced 2026-02-04 06:54:45 +08:00
提交origin2.0版本
This commit is contained in:
10
util/Log.go
10
util/Log.go
@@ -1,10 +0,0 @@
|
||||
package util
|
||||
|
||||
|
||||
|
||||
type PrintLog func(uint, string, ...interface{})
|
||||
|
||||
var Log PrintLog
|
||||
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package util
|
||||
|
||||
import "time"
|
||||
|
||||
type Timer struct {
|
||||
lasttime int64
|
||||
timeinterval int64
|
||||
|
||||
setupZeroDBase time.Duration //0表示普通模式 1表示切换分钟模式
|
||||
}
|
||||
|
||||
func (slf *Timer) GetTimerinterval() int64 {
|
||||
return slf.timeinterval
|
||||
}
|
||||
|
||||
func (slf *Timer) SetupTimer(ms int32) {
|
||||
slf.lasttime = time.Now().UnixNano()
|
||||
slf.timeinterval = int64(ms) * 1e6
|
||||
}
|
||||
|
||||
func (slf *Timer) SetupTimerEx(tm time.Duration) {
|
||||
slf.lasttime = time.Now().UnixNano()
|
||||
slf.timeinterval = int64(tm)
|
||||
}
|
||||
|
||||
|
||||
func (slf *Timer) SetupTimerDouble() {
|
||||
slf.lasttime = time.Now().UnixNano()
|
||||
slf.timeinterval *= 2
|
||||
}
|
||||
|
||||
func (slf *Timer) SetTimerHalf() {
|
||||
slf.lasttime = time.Now().UnixNano()
|
||||
slf.timeinterval /= 2
|
||||
}
|
||||
|
||||
//检查整点分钟数触发
|
||||
func (slf *Timer) SetupZeroTimer(baseD time.Duration, interval int64) {
|
||||
timeNow := time.Now()
|
||||
nt := timeNow.Truncate(baseD)
|
||||
slf.lasttime = nt.UnixNano()
|
||||
slf.timeinterval = baseD.Nanoseconds() * interval
|
||||
slf.setupZeroDBase = baseD
|
||||
}
|
||||
|
||||
func (slf *Timer) ResetStartTime() {
|
||||
slf.lasttime = 0
|
||||
}
|
||||
|
||||
func (slf *Timer) CheckTimeOut() bool {
|
||||
now := time.Now()
|
||||
if slf.setupZeroDBase.Nanoseconds() == 0 {
|
||||
if now.UnixNano() > slf.lasttime+slf.timeinterval {
|
||||
slf.lasttime = now.UnixNano()
|
||||
return true
|
||||
}
|
||||
} else { //整点模式
|
||||
if now.UnixNano() > slf.lasttime+slf.timeinterval {
|
||||
slf.SetupZeroTimer(slf.setupZeroDBase, slf.timeinterval/slf.setupZeroDBase.Nanoseconds())
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GetTomorrowTimestamp() int64{
|
||||
timeStr := time.Now().Format("2006-01-02")
|
||||
t, _ := time.ParseInLocation("2006-01-02 15:04:05", timeStr+" 23:59:59", time.Local)
|
||||
return t.Unix()+1
|
||||
}
|
||||
|
||||
func IsSameDay(timeFir, timeSec int64) bool{
|
||||
firTime:=time.Unix(timeFir,0)
|
||||
secTime:=time.Unix(timeSec,0)
|
||||
if firTime.Day()==secTime.Day()&&firTime.Month()==secTime.Month()&&firTime.Year()==secTime.Year(){
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func IsCrossOneDay(timeFir,timeSec int64)bool{
|
||||
firTime := time.Unix(timeFir,0)
|
||||
secTime := time.Unix(timeSec,0)
|
||||
firTime.Add(time.Hour*24).Day()
|
||||
|
||||
if firTime.Day() == secTime.Day() &&
|
||||
firTime.Month()==secTime.Month()&&
|
||||
firTime.Year()==secTime.Year(){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,17 +1,4 @@
|
||||
// Copyright 2014 mqantserver Author. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package util
|
||||
package aesencrypt
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
@@ -86,4 +73,4 @@ func (this *AesEncrypt) Decrypt(src []byte) (strDesc string, err error) {
|
||||
aesDecrypter := cipher.NewCFBDecrypter(aesBlockDecrypter, iv)
|
||||
aesDecrypter.XORKeyStream(decrypted, src)
|
||||
return string(decrypted), nil
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package util
|
||||
package coroutine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -12,11 +12,7 @@ func F(callback interface{},recoverNum int, args ...interface{}) {
|
||||
var coreInfo string
|
||||
coreInfo = string(debug.Stack())
|
||||
coreInfo += "\n" + fmt.Sprintf("Core information is %v\n", r)
|
||||
if Log != nil {
|
||||
Log(5, coreInfo)
|
||||
} else {
|
||||
fmt.Print(coreInfo)
|
||||
}
|
||||
fmt.Print(coreInfo)
|
||||
|
||||
if recoverNum==-1 ||recoverNum-1 >= 0 {
|
||||
recoverNum -= 1
|
||||
@@ -1,9 +1,6 @@
|
||||
package util
|
||||
package deepcopy
|
||||
|
||||
// reference: https://github.com/mohae/deepcopy
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
import "reflect"
|
||||
|
||||
func deepCopy(dst, src reflect.Value) {
|
||||
switch src.Kind() {
|
||||
@@ -1,35 +0,0 @@
|
||||
package util_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/duanhf2012/origin/util"
|
||||
)
|
||||
|
||||
func ExampleMap(t *testing.T) {
|
||||
maps := util.NewMapEx()
|
||||
for i := 0; i < 10000; i++ {
|
||||
maps.Set(i, i)
|
||||
}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
ret := maps.Get(i)
|
||||
if ret.(int) != i {
|
||||
fmt.Printf("cannot find i:%d\n", i)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
maps.LockSet(i, func(key interface{}, val interface{}) interface{} {
|
||||
return val.(int) + 1
|
||||
})
|
||||
}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
ret := maps.Get(i)
|
||||
if ret.(int) != i {
|
||||
fmt.Printf("cannot find i:%d\n", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
1
util/has/hash.go
Normal file
1
util/has/hash.go
Normal file
@@ -0,0 +1 @@
|
||||
package has
|
||||
@@ -4,4 +4,4 @@ import "hash/crc32"
|
||||
|
||||
func HashNumber(s string) uint {
|
||||
return uint(crc32.ChecksumIEEE([]byte(s)))
|
||||
}
|
||||
}
|
||||
101
util/queue.go
101
util/queue.go
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
Package queue provides a fast, ring-buffer queue based on the version suggested by Dariusz Górecki.
|
||||
Using this instead of other, simpler, queue implementations (slice+append or linked list) provides
|
||||
substantial memory and time benefits, and fewer GC pauses.
|
||||
The queue implemented here is as fast as it is for an additional reason: it is *not* thread-safe.
|
||||
*/
|
||||
package util
|
||||
|
||||
// minQueueLen is smallest capacity that queue may have.
|
||||
// Must be power of 2 for bitwise modulus: x % n == x & (n - 1).
|
||||
const minQueueLen = 16
|
||||
|
||||
// Queue represents a single instance of the queue data structure.
|
||||
type Queue struct {
|
||||
buf []interface{}
|
||||
head, tail, count int
|
||||
}
|
||||
|
||||
// New constructs and returns a new Queue.
|
||||
func NewQueue() *Queue {
|
||||
return &Queue{
|
||||
buf: make([]interface{}, minQueueLen),
|
||||
}
|
||||
}
|
||||
|
||||
// Length returns the number of elements currently stored in the queue.
|
||||
func (q *Queue) Length() int {
|
||||
return q.count
|
||||
}
|
||||
|
||||
// resizes the queue to fit exactly twice its current contents
|
||||
// this can result in shrinking if the queue is less than half-full
|
||||
func (q *Queue) resize() {
|
||||
newBuf := make([]interface{}, q.count<<1)
|
||||
|
||||
if q.tail > q.head {
|
||||
copy(newBuf, q.buf[q.head:q.tail])
|
||||
} else {
|
||||
n := copy(newBuf, q.buf[q.head:])
|
||||
copy(newBuf[n:], q.buf[:q.tail])
|
||||
}
|
||||
|
||||
q.head = 0
|
||||
q.tail = q.count
|
||||
q.buf = newBuf
|
||||
}
|
||||
|
||||
// Add puts an element on the end of the queue.
|
||||
func (q *Queue) Add(elem interface{}) {
|
||||
if q.count == len(q.buf) {
|
||||
q.resize()
|
||||
}
|
||||
|
||||
q.buf[q.tail] = elem
|
||||
// bitwise modulus
|
||||
q.tail = (q.tail + 1) & (len(q.buf) - 1)
|
||||
q.count++
|
||||
}
|
||||
|
||||
// Peek returns the element at the head of the queue. This call panics
|
||||
// if the queue is empty.
|
||||
func (q *Queue) Peek() interface{} {
|
||||
if q.count <= 0 {
|
||||
panic("queue: Peek() called on empty queue")
|
||||
}
|
||||
return q.buf[q.head]
|
||||
}
|
||||
|
||||
// Get returns the element at index i in the queue. If the index is
|
||||
// invalid, the call will panic. This method accepts both positive and
|
||||
// negative index values. Index 0 refers to the first element, and
|
||||
// index -1 refers to the last.
|
||||
func (q *Queue) Get(i int) interface{} {
|
||||
// If indexing backwards, convert to positive index.
|
||||
if i < 0 {
|
||||
i += q.count
|
||||
}
|
||||
if i < 0 || i >= q.count {
|
||||
panic("queue: Get() called with index out of range")
|
||||
}
|
||||
// bitwise modulus
|
||||
return q.buf[(q.head+i)&(len(q.buf)-1)]
|
||||
}
|
||||
|
||||
// Remove removes and returns the element from the front of the queue. If the
|
||||
// queue is empty, the call will panic.
|
||||
func (q *Queue) Remove() interface{} {
|
||||
if q.count <= 0 {
|
||||
panic("queue: Remove() called on empty queue")
|
||||
}
|
||||
ret := q.buf[q.head]
|
||||
q.buf[q.head] = nil
|
||||
// bitwise modulus
|
||||
q.head = (q.head + 1) & (len(q.buf) - 1)
|
||||
q.count--
|
||||
// Resize down if buffer 1/4 full.
|
||||
if len(q.buf) > minQueueLen && (q.count<<2) == len(q.buf) {
|
||||
q.resize()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
23
util/queue/.gitignore
vendored
23
util/queue/.gitignore
vendored
@@ -1,23 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
@@ -1,7 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Evan Huus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,16 +0,0 @@
|
||||
Queue
|
||||
=====
|
||||
|
||||
[](https://travis-ci.org/eapache/queue)
|
||||
[](https://godoc.org/github.com/eapache/queue)
|
||||
[](https://eapache.github.io/conduct.html)
|
||||
|
||||
A fast Golang queue using a ring-buffer, based on the version suggested by Dariusz Górecki.
|
||||
Using this instead of other, simpler, queue implementations (slice+append or linked list) provides
|
||||
substantial memory and time benefits, and fewer GC pauses.
|
||||
|
||||
The queue implemented here is as fast as it is in part because it is *not* thread-safe.
|
||||
|
||||
Follows semantic versioning using https://gopkg.in/ - import from
|
||||
[`gopkg.in/eapache/queue.v1`](https://gopkg.in/eapache/queue.v1)
|
||||
for guaranteed API stability.
|
||||
@@ -1,4 +1,4 @@
|
||||
package util
|
||||
package rand
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
@@ -1,4 +1,4 @@
|
||||
package util
|
||||
package semaphore
|
||||
|
||||
type Semaphore chan struct{}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Synchronous FIFO queue
|
||||
type SyncQueue struct {
|
||||
lock sync.Mutex
|
||||
popable *sync.Cond
|
||||
buffer *Queue
|
||||
closed bool
|
||||
}
|
||||
|
||||
// Create a new SyncQueue
|
||||
func NewSyncQueue() *SyncQueue {
|
||||
ch := &SyncQueue{
|
||||
buffer: NewQueue(),
|
||||
}
|
||||
ch.popable = sync.NewCond(&ch.lock)
|
||||
return ch
|
||||
}
|
||||
|
||||
// Pop an item from SyncQueue, will block if SyncQueue is empty
|
||||
func (q *SyncQueue) Pop() (v interface{}) {
|
||||
c := q.popable
|
||||
buffer := q.buffer
|
||||
|
||||
q.lock.Lock()
|
||||
for buffer.Length() == 0 && !q.closed {
|
||||
c.Wait()
|
||||
}
|
||||
|
||||
if buffer.Length() > 0 {
|
||||
v = buffer.Peek()
|
||||
buffer.Remove()
|
||||
}
|
||||
|
||||
q.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Try to pop an item from SyncQueue, will return immediately with bool=false if SyncQueue is empty
|
||||
func (q *SyncQueue) TryPop() (v interface{}, ok bool) {
|
||||
buffer := q.buffer
|
||||
|
||||
q.lock.Lock()
|
||||
|
||||
if buffer.Length() > 0 {
|
||||
v = buffer.Peek()
|
||||
buffer.Remove()
|
||||
ok = true
|
||||
} else if q.closed {
|
||||
ok = true
|
||||
}
|
||||
|
||||
q.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Push an item to SyncQueue. Always returns immediately without blocking
|
||||
func (q *SyncQueue) Push(v interface{}) {
|
||||
q.lock.Lock()
|
||||
if !q.closed {
|
||||
q.buffer.Add(v)
|
||||
q.popable.Signal()
|
||||
}
|
||||
q.lock.Unlock()
|
||||
}
|
||||
|
||||
// Get the length of SyncQueue
|
||||
func (q *SyncQueue) Len() (l int) {
|
||||
q.lock.Lock()
|
||||
l = q.buffer.Length()
|
||||
q.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Close SyncQueue
|
||||
//
|
||||
// After close, Pop will return nil without block, and TryPop will return v=nil, ok=True
|
||||
func (q *SyncQueue) Close() {
|
||||
q.lock.Lock()
|
||||
if !q.closed {
|
||||
q.closed = true
|
||||
q.popable.Signal()
|
||||
}
|
||||
q.lock.Unlock()
|
||||
}
|
||||
|
||||
func (q *SyncQueue) IsClose() (v bool) {
|
||||
q.lock.Lock()
|
||||
v = q.closed
|
||||
q.lock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (q *SyncQueue) Get(i int) interface{} {
|
||||
q.lock.Lock()
|
||||
defer q.lock.Unlock()
|
||||
return q.buffer.Get(i)
|
||||
}
|
||||
268
util/timer/cronexpr.go
Normal file
268
util/timer/cronexpr.go
Normal file
@@ -0,0 +1,268 @@
|
||||
package timer
|
||||
|
||||
// reference: https://github.com/robfig/cron
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Field name | Mandatory? | Allowed values | Allowed special characters
|
||||
// ---------- | ---------- | -------------- | --------------------------
|
||||
// Seconds | No | 0-59 | * / , -
|
||||
// Minutes | Yes | 0-59 | * / , -
|
||||
// Hours | Yes | 0-23 | * / , -
|
||||
// Day of month | Yes | 1-31 | * / , -
|
||||
// Month | Yes | 1-12 | * / , -
|
||||
// Day of week | Yes | 0-6 | * / , -
|
||||
type CronExpr struct {
|
||||
sec uint64
|
||||
min uint64
|
||||
hour uint64
|
||||
dom uint64
|
||||
month uint64
|
||||
dow uint64
|
||||
}
|
||||
|
||||
// goroutine safe
|
||||
func NewCronExpr(expr string) (cronExpr *CronExpr, err error) {
|
||||
fields := strings.Fields(expr)
|
||||
if len(fields) != 5 && len(fields) != 6 {
|
||||
err = fmt.Errorf("invalid expr %v: expected 5 or 6 fields, got %v", expr, len(fields))
|
||||
return
|
||||
}
|
||||
|
||||
if len(fields) == 5 {
|
||||
fields = append([]string{"0"}, fields...)
|
||||
}
|
||||
|
||||
cronExpr = new(CronExpr)
|
||||
// Seconds
|
||||
cronExpr.sec, err = parseCronField(fields[0], 0, 59)
|
||||
if err != nil {
|
||||
goto onError
|
||||
}
|
||||
// Minutes
|
||||
cronExpr.min, err = parseCronField(fields[1], 0, 59)
|
||||
if err != nil {
|
||||
goto onError
|
||||
}
|
||||
// Hours
|
||||
cronExpr.hour, err = parseCronField(fields[2], 0, 23)
|
||||
if err != nil {
|
||||
goto onError
|
||||
}
|
||||
// Day of month
|
||||
cronExpr.dom, err = parseCronField(fields[3], 1, 31)
|
||||
if err != nil {
|
||||
goto onError
|
||||
}
|
||||
// Month
|
||||
cronExpr.month, err = parseCronField(fields[4], 1, 12)
|
||||
if err != nil {
|
||||
goto onError
|
||||
}
|
||||
// Day of week
|
||||
cronExpr.dow, err = parseCronField(fields[5], 0, 6)
|
||||
if err != nil {
|
||||
goto onError
|
||||
}
|
||||
return
|
||||
|
||||
onError:
|
||||
err = fmt.Errorf("invalid expr %v: %v", expr, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 1. *
|
||||
// 2. num
|
||||
// 3. num-num
|
||||
// 4. */num
|
||||
// 5. num/num (means num-max/num)
|
||||
// 6. num-num/num
|
||||
func parseCronField(field string, min int, max int) (cronField uint64, err error) {
|
||||
fields := strings.Split(field, ",")
|
||||
for _, field := range fields {
|
||||
rangeAndIncr := strings.Split(field, "/")
|
||||
if len(rangeAndIncr) > 2 {
|
||||
err = fmt.Errorf("too many slashes: %v", field)
|
||||
return
|
||||
}
|
||||
|
||||
// range
|
||||
startAndEnd := strings.Split(rangeAndIncr[0], "-")
|
||||
if len(startAndEnd) > 2 {
|
||||
err = fmt.Errorf("too many hyphens: %v", rangeAndIncr[0])
|
||||
return
|
||||
}
|
||||
|
||||
var start, end int
|
||||
if startAndEnd[0] == "*" {
|
||||
if len(startAndEnd) != 1 {
|
||||
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
|
||||
return
|
||||
}
|
||||
start = min
|
||||
end = max
|
||||
} else {
|
||||
// start
|
||||
start, err = strconv.Atoi(startAndEnd[0])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
|
||||
return
|
||||
}
|
||||
// end
|
||||
if len(startAndEnd) == 1 {
|
||||
if len(rangeAndIncr) == 2 {
|
||||
end = max
|
||||
} else {
|
||||
end = start
|
||||
}
|
||||
} else {
|
||||
end, err = strconv.Atoi(startAndEnd[1])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if start > end {
|
||||
err = fmt.Errorf("invalid range: %v", rangeAndIncr[0])
|
||||
return
|
||||
}
|
||||
if start < min {
|
||||
err = fmt.Errorf("out of range [%v, %v]: %v", min, max, rangeAndIncr[0])
|
||||
return
|
||||
}
|
||||
if end > max {
|
||||
err = fmt.Errorf("out of range [%v, %v]: %v", min, max, rangeAndIncr[0])
|
||||
return
|
||||
}
|
||||
|
||||
// increment
|
||||
var incr int
|
||||
if len(rangeAndIncr) == 1 {
|
||||
incr = 1
|
||||
} else {
|
||||
incr, err = strconv.Atoi(rangeAndIncr[1])
|
||||
if err != nil {
|
||||
err = fmt.Errorf("invalid increment: %v", rangeAndIncr[1])
|
||||
return
|
||||
}
|
||||
if incr <= 0 {
|
||||
err = fmt.Errorf("invalid increment: %v", rangeAndIncr[1])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// cronField
|
||||
if incr == 1 {
|
||||
cronField |= ^(math.MaxUint64 << uint(end+1)) & (math.MaxUint64 << uint(start))
|
||||
} else {
|
||||
for i := start; i <= end; i += incr {
|
||||
cronField |= 1 << uint(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (e *CronExpr) matchDay(t time.Time) bool {
|
||||
// day-of-month blank
|
||||
if e.dom == 0xfffffffe {
|
||||
return 1<<uint(t.Weekday())&e.dow != 0
|
||||
}
|
||||
|
||||
// day-of-week blank
|
||||
if e.dow == 0x7f {
|
||||
return 1<<uint(t.Day())&e.dom != 0
|
||||
}
|
||||
|
||||
return 1<<uint(t.Weekday())&e.dow != 0 ||
|
||||
1<<uint(t.Day())&e.dom != 0
|
||||
}
|
||||
|
||||
// goroutine safe
|
||||
func (e *CronExpr) Next(t time.Time) time.Time {
|
||||
// the upcoming second
|
||||
t = t.Truncate(time.Second).Add(time.Second)
|
||||
|
||||
year := t.Year()
|
||||
initFlag := false
|
||||
|
||||
retry:
|
||||
// Year
|
||||
if t.Year() > year+1 {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
// Month
|
||||
for 1<<uint(t.Month())&e.month == 0 {
|
||||
if !initFlag {
|
||||
initFlag = true
|
||||
t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
|
||||
t = t.AddDate(0, 1, 0)
|
||||
if t.Month() == time.January {
|
||||
goto retry
|
||||
}
|
||||
}
|
||||
|
||||
// Day
|
||||
for !e.matchDay(t) {
|
||||
if !initFlag {
|
||||
initFlag = true
|
||||
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
|
||||
t = t.AddDate(0, 0, 1)
|
||||
if t.Day() == 1 {
|
||||
goto retry
|
||||
}
|
||||
}
|
||||
|
||||
// Hours
|
||||
for 1<<uint(t.Hour())&e.hour == 0 {
|
||||
if !initFlag {
|
||||
initFlag = true
|
||||
t = t.Truncate(time.Hour)
|
||||
}
|
||||
|
||||
t = t.Add(time.Hour)
|
||||
if t.Hour() == 0 {
|
||||
goto retry
|
||||
}
|
||||
}
|
||||
|
||||
// Minutes
|
||||
for 1<<uint(t.Minute())&e.min == 0 {
|
||||
if !initFlag {
|
||||
initFlag = true
|
||||
t = t.Truncate(time.Minute)
|
||||
}
|
||||
|
||||
t = t.Add(time.Minute)
|
||||
if t.Minute() == 0 {
|
||||
goto retry
|
||||
}
|
||||
}
|
||||
|
||||
// Seconds
|
||||
for 1<<uint(t.Second())&e.sec == 0 {
|
||||
if !initFlag {
|
||||
initFlag = true
|
||||
}
|
||||
|
||||
t = t.Add(time.Second)
|
||||
if t.Second() == 0 {
|
||||
goto retry
|
||||
}
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
67
util/timer/example_test.go
Normal file
67
util/timer/example_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package timer_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/name5566/leaf/timer"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleTimer() {
|
||||
d := timer.NewDispatcher(10)
|
||||
|
||||
// timer 1
|
||||
d.AfterFunc(1, func() {
|
||||
fmt.Println("My name is Leaf")
|
||||
})
|
||||
|
||||
// timer 2
|
||||
t := d.AfterFunc(1, func() {
|
||||
fmt.Println("will not print")
|
||||
})
|
||||
t.Stop()
|
||||
|
||||
// dispatch
|
||||
(<-d.ChanTimer).Cb()
|
||||
|
||||
// Output:
|
||||
// My name is Leaf
|
||||
}
|
||||
|
||||
func ExampleCronExpr() {
|
||||
cronExpr, err := timer.NewCronExpr("0 * * * *")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(cronExpr.Next(time.Date(
|
||||
2000, 1, 1,
|
||||
20, 10, 5,
|
||||
0, time.UTC,
|
||||
)))
|
||||
|
||||
// Output:
|
||||
// 2000-01-01 21:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleCron() {
|
||||
d := timer.NewDispatcher(10)
|
||||
|
||||
// cron expr
|
||||
cronExpr, err := timer.NewCronExpr("* * * * * *")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// cron
|
||||
var c *timer.Cron
|
||||
c = d.CronFunc(cronExpr, func() {
|
||||
fmt.Println("My name is Leaf")
|
||||
c.Stop()
|
||||
})
|
||||
|
||||
// dispatch
|
||||
(<-d.ChanTimer).Cb()
|
||||
|
||||
// Output:
|
||||
// My name is Leaf
|
||||
}
|
||||
134
util/timer/timer.go
Normal file
134
util/timer/timer.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package timer
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// one dispatcher per goroutine (goroutine not safe)
|
||||
type Dispatcher struct {
|
||||
ChanTimer chan *Timer
|
||||
}
|
||||
|
||||
func NewDispatcher(l int) *Dispatcher {
|
||||
disp := new(Dispatcher)
|
||||
disp.ChanTimer = make(chan *Timer, l)
|
||||
return disp
|
||||
}
|
||||
|
||||
// Timer
|
||||
type Timer struct {
|
||||
t *time.Timer
|
||||
cb func()
|
||||
cbex func(*Timer)
|
||||
}
|
||||
|
||||
func (t *Timer) Stop() {
|
||||
t.t.Stop()
|
||||
t.cb = nil
|
||||
}
|
||||
|
||||
func (t *Timer) Cb() {
|
||||
/*
|
||||
defer func() {
|
||||
t.cb = nil
|
||||
if r := recover(); r != nil {
|
||||
if conf.LenStackBuf > 0 {
|
||||
buf := make([]byte, conf.LenStackBuf)
|
||||
l := runtime.Stack(buf, false)
|
||||
log.Error("%v: %s", r, buf[:l])
|
||||
} else {
|
||||
log.Error("%v", r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
*/
|
||||
|
||||
if t.cbex!=nil {
|
||||
t.cbex(t)
|
||||
}else{
|
||||
t.cb()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (disp *Dispatcher) AfterFunc(d time.Duration, cb func()) *Timer {
|
||||
t := new(Timer)
|
||||
t.cb = cb
|
||||
t.t = time.AfterFunc(d, func() {
|
||||
disp.ChanTimer <- t
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
func (disp *Dispatcher) AfterFuncEx(d time.Duration, cbex func(timer *Timer)) *Timer {
|
||||
t := new(Timer)
|
||||
t.cbex = cbex
|
||||
t.t = time.AfterFunc(d, func() {
|
||||
disp.ChanTimer <- t
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
// Cron
|
||||
type Cron struct {
|
||||
t *Timer
|
||||
}
|
||||
|
||||
func (c *Cron) Stop() {
|
||||
if c.t != nil {
|
||||
c.t.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func (disp *Dispatcher) CronFunc(cronExpr *CronExpr, _cb func()) *Cron {
|
||||
c := new(Cron)
|
||||
|
||||
now := time.Now()
|
||||
nextTime := cronExpr.Next(now)
|
||||
if nextTime.IsZero() {
|
||||
return c
|
||||
}
|
||||
|
||||
// callback
|
||||
var cb func()
|
||||
cb = func() {
|
||||
defer _cb()
|
||||
|
||||
now := time.Now()
|
||||
nextTime := cronExpr.Next(now)
|
||||
if nextTime.IsZero() {
|
||||
return
|
||||
}
|
||||
c.t = disp.AfterFunc(nextTime.Sub(now), cb)
|
||||
}
|
||||
|
||||
c.t = disp.AfterFunc(nextTime.Sub(now), cb)
|
||||
return c
|
||||
}
|
||||
|
||||
|
||||
func (disp *Dispatcher) CronFuncEx(cronExpr *CronExpr, _cb func(*Cron)) *Cron {
|
||||
c := new(Cron)
|
||||
|
||||
now := time.Now()
|
||||
nextTime := cronExpr.Next(now)
|
||||
if nextTime.IsZero() {
|
||||
return c
|
||||
}
|
||||
|
||||
// callback
|
||||
var cb func()
|
||||
cb = func() {
|
||||
defer _cb(c)
|
||||
|
||||
now := time.Now()
|
||||
nextTime := cronExpr.Next(now)
|
||||
if nextTime.IsZero() {
|
||||
return
|
||||
}
|
||||
c.t = disp.AfterFunc(nextTime.Sub(now), cb)
|
||||
}
|
||||
|
||||
c.t = disp.AfterFunc(nextTime.Sub(now), cb)
|
||||
return c
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
package util
|
||||
package umap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
import "sync"
|
||||
|
||||
type Map struct {
|
||||
sync.RWMutex
|
||||
@@ -1,10 +1,9 @@
|
||||
package util
|
||||
package umap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duanhf2012/origin/util/hash"
|
||||
"github.com/duanhf2012/originnet/util/hash"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -16,7 +15,6 @@ type MapEx struct {
|
||||
m []map[interface{}]interface{}
|
||||
l []sync.RWMutex
|
||||
hashMapNum int
|
||||
rangeIdx uint32
|
||||
}
|
||||
|
||||
func (m *MapEx) Init(hashMapNum int) {
|
||||
@@ -37,19 +35,6 @@ func NewMapEx() *MapEx {
|
||||
return &mapEx
|
||||
}
|
||||
|
||||
|
||||
func (m *MapEx) NextRLockRange(f func(key interface{}, value interface{})) {
|
||||
i := atomic.AddUint32(&m.rangeIdx,1)%uint32(m.hashMapNum)
|
||||
|
||||
m.l[i].RLock()
|
||||
for key, val := range m.m[i] {
|
||||
f(key, val)
|
||||
}
|
||||
|
||||
m.l[i].RUnlock()
|
||||
}
|
||||
|
||||
|
||||
func (m *MapEx) ClearMap() {
|
||||
for i := 0; i < DEFAULT_SAFE_MAP_MAX_HASH_NUM; i++ {
|
||||
m.l[i].Lock()
|
||||
@@ -64,7 +49,7 @@ func (m *MapEx) GetHashCode(key interface{}) int {
|
||||
|
||||
func (m *MapEx) GetArrayIdByKey(key interface{}) int {
|
||||
if m.hashMapNum ==0 {
|
||||
return -1
|
||||
return -1
|
||||
}
|
||||
idx := m.GetHashCode(key) % m.hashMapNum
|
||||
if idx > m.hashMapNum {
|
||||
@@ -211,15 +196,9 @@ func (m *MapEx) LockSet(key interface{}, f func(value interface{}) interface{})
|
||||
ret, ok := val[key]
|
||||
|
||||
if ok == false {
|
||||
ret := f(nil)
|
||||
if ret != nil {
|
||||
val[key] =ret
|
||||
}
|
||||
val[key] = f(nil)
|
||||
} else {
|
||||
ret := f(ret)
|
||||
if ret != nil {
|
||||
val[key] =ret
|
||||
}
|
||||
val[key] = f(ret)
|
||||
}
|
||||
|
||||
m.l[idx].Unlock()
|
||||
@@ -1,16 +1,3 @@
|
||||
// Copyright 2014 mqant Author. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package uuid
|
||||
|
||||
import (
|
||||
@@ -118,4 +105,4 @@ func randBytes(x []byte) {
|
||||
x[length] = byte(mrand.Int31n(256))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user