common/mix.go (223 lines of code) (raw):

package utils import ( "fmt" "go.mongodb.org/mongo-driver/bson/primitive" "math/rand" _ "net/http/pprof" // for profiling "os" "path/filepath" "strconv" "time" "path" "reflect" LOG "github.com/vinllen/log4go" ) func YieldInMs(n int64) { time.Sleep(time.Millisecond * time.Duration(n)) } type ElapsedTask struct { // timer trigger TimeLimit int64 // batch trigger BatchLimit int64 stone int64 triggerTimes int64 } func NewThresholder(timeLimit, batchLimit int64) *ElapsedTask { return &ElapsedTask{TimeLimit: timeLimit, BatchLimit: batchLimit, stone: time.Now().Unix(), triggerTimes: 0} } func (thresholder *ElapsedTask) Reset() { thresholder.stone = time.Now().Unix() thresholder.triggerTimes = 0 } func (thresholder *ElapsedTask) Triiger() bool { thresholder.triggerTimes++ current := time.Now().Unix() if current > (thresholder.stone + thresholder.TimeLimit) { return true } if thresholder.triggerTimes >= thresholder.BatchLimit { return true } return false } type Int64Slice []int64 func (p Int64Slice) Len() int { return len(p) } func (p Int64Slice) Less(i, j int) bool { return p[i] < p[j] } func (p Int64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func TimeStampToInt64(ts primitive.Timestamp) int64 { return int64(ts.T)<<32 + int64(ts.I) } func Int64ToTimestamp(t int64) primitive.Timestamp { return primitive.Timestamp{T: uint32(uint64(t) >> 32), I: uint32(t)} } // Unix() to TimeStamp func TimeToTimestamp(t int64) primitive.Timestamp { return primitive.Timestamp{T: uint32(t), I: 0} } func TimestampToString(ts int64) string { return time.Unix(ts, 0).Format(TimeFormat) } func ExtractMongoTimestamp(ts interface{}) int64 { switch src := ts.(type) { case primitive.Timestamp: return int64(src.T) case int64: return src >> 32 default: return -1 } return 0 } func ExtractMongoTimestampCounter(ts interface{}) int64 { switch src := ts.(type) { case primitive.Timestamp: return int64(src.I) case int64: return src & Int32max default: return -1 } return 0 } func ExtractTimestampForLog(ts interface{}) string { return fmt.Sprintf("%v[%v, %v]", ts, ExtractMongoTimestamp(ts), ExtractMongoTimestampCounter(ts)) } func Int64ToString(v int64) string { return strconv.FormatInt(v, 10) } func ParseIntFromInterface(input interface{}) (int64, error) { switch src := input.(type) { case int: return int64(src), nil case int8: return int64(src), nil case int16: return int64(src), nil case int32: return int64(src), nil case int64: return src, nil case uint: return int64(src), nil case uint8: return int64(src), nil case uint16: return int64(src), nil case uint32: return int64(src), nil case uint64: return int64(src), nil case string: v, err := strconv.Atoi(src) return int64(v), err default: return 0, fmt.Errorf("unknown type[%v] with input[%v]", reflect.TypeOf(src), src) } panic("can't see me!") } // one writer and multi readers type OpsCounter struct { counter [OpsMax + 1]uint64 } const ( OpsMax = 'z' - 'A' ) func (opsCounter *OpsCounter) Add(char byte, v uint64) { if 0 <= char-'A' && char-'A' <= OpsMax { opsCounter.counter[char-'A'] += v } } func (opsCounter *OpsCounter) Map() map[string]uint64 { toMap := make(map[string]uint64) for index, v := range opsCounter.counter { if v != 0 { toMap[fmt.Sprint('A'+index)] = v } } return toMap } func HasDuplicated(slice []string) bool { unique := map[string]int{} for _, s := range slice { currentSize := len(unique) unique[s] = 0 if currentSize+1 != len(unique) { return true } } return false } func MayBeRandom(port int) int { // random a port number if port == 0 { // non-negative nr := rand.Intn(10000) if nr <= 1024 { nr += 1024 } return nr } return port } func Mkdirs(dirs ...string) error { for _, dir := range dirs { if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) { if err = os.Mkdir(dir, 0777); err != nil { return err } } } return nil } func WritePidById(dir, id string) bool { if len(dir) == 0 { dir, _ = os.Getwd() } else if dir[0] != '/' { // relative path baseDir, _ := os.Getwd() dir = path.Join(baseDir, dir) } pidfile := filepath.Join(dir, id) + ".pid" if err := WritePid(pidfile); err != nil { LOG.Critical("Process write pid and lock file failed : %v", err) return false } return true } func Welcome() { welcome := `______________________________ \ \ _ ______ | \ \ / \___-=O'/|O'/__| \ MongoShake, Here we go !! \_______\ / | / ) / / '/-==__ _/__|/__=-| -GM / Alibaba Cloud / * \ | | / / (o) ------------------------------ ` startMsg := "if you have any problem, please visit https://github.com/alibaba/MongoShake/wiki/FAQ" LOG.Warn(fmt.Sprintf("\n%s\n%s\n", welcome, startMsg)) } func Goodbye() { goodbye := ` ##### | ##### Oh we finish ? # _ _ #|# _ _ # # | # | ############ # # | # # # # | | # # | | | | # # | | | | # .-. # | #( O )# | | | | ################. .############### | ## _ _|____| ### |_ __| _ ## # | | # # | | | | | | | | # ###################################### # # ##### ` LOG.Warn(goodbye) }