コード例 #1
0
ファイル: conn.go プロジェクト: sunbin728/bdbd
func (c *Conn) processRequest() error {
	req, err := c.readRequest()
	if err != nil {
		log.Error("processRequest|readRequest|%s", err.Error())
		return err
	}
	cmd := strings.ToLower(string(req[0]))
	if def, ok := cmdMap[cmd]; ok {
		args := req[1:]
		if len(args) < def.minArgs || len(args) > def.maxArgs {
			c.wb.WriteString(fmt.Sprintf("-ERR wrong number of arguments for '%s' command\r\n", cmd))
		} else {
			err = def.fun(c, args)
			if err != nil {
				log.Error("processRequest|func|%s", err.Error())
				return err
			}
		}
	} else {
		c.wb.WriteString(fmt.Sprintf("-ERR unknown command '%s'\r\n", cmd))
	}
	if err = c.wb.Flush(); err != nil {
		log.Error("processRequest|Flush|%s", err.Error())
		return err
	} else {
		return nil
	}
}
コード例 #2
0
ファイル: redis.go プロジェクト: shitfSign/redis-4
func makeConn(addr, pwd string) (conn *redisConn, err error) {
	log.Info("makeConn|%v|%v", addr, pwd)
	conn = nil
	const dataTimeout = 5 * time.Second
	const connTimeout = 2 * time.Second
	var c redis.Conn
	if c, err = redis.DialTimeout("tcp", addr, connTimeout, dataTimeout, dataTimeout); err != nil {
		log.Error("makeConn|DialTimeout|%v", err)
		return
	}
	if pwd != "" {
		if _, err = c.Do("AUTH", pwd); err != nil {
			log.Error("makeConn|auth|%v", err)
			c.Close()
			return
		}
	}
	if _, err = c.Do("get", "__test"); err != nil {
		log.Error("makeConn|get|%v", err)
		c.Close()
		return
	}
	log.Info("makeConn|ok|%v", addr)
	var now = time.Now().Unix()
	conn = &redisConn{c, addr, seed, now + pingInterval, now}
	seed++
	return
}
コード例 #3
0
ファイル: conn.go プロジェクト: sunbin728/bdbd
func (c *Conn) readRequest() ([][]byte, error) {
	count, err := c.readCount('*')
	if err != nil {
		log.Error("readRequest|readCount|%s", err.Error())
		return nil, err
	}
	if count <= 0 {
		log.Error("readRequest|invalid_count|%v", count)
		return nil, ErrRequest
	}
	var r = make([][]byte, count)
	var i int64
	for i = 0; i < count; i++ {
		length, err := c.readCount('$')
		if err != nil {
			log.Error("readRequest|readCount|%s", err.Error())
			return nil, err
		}
		buff := make([]byte, length+2)
		_, err = io.ReadFull(c.rb, buff)
		if err != nil {
			log.Error("readRequest|ReadFull|%s", err.Error())
			return nil, err
		}
		if buff[length+1] != '\n' || buff[length] != '\r' {
			log.Error("readRequest|invalid_crlf|%v", buff)
			return nil, ErrRequest
		}
		r[i] = buff[0:length]
	}
	return r, nil
}
コード例 #4
0
ファイル: bdb.go プロジェクト: sunbin728/bdbd
func (db *Db) Close() {
	ret := C.db_close(db.db)
	if ret == 0 {
		return
	} else if ret == C.EINVAL {
		log.Error("Close|db_close|EINVAL")
		return
	}
	go func() {
		for {
			ret := C.db_close(db.db)
			if ret == 0 {
				break
			} else if ret == C.EINVAL {
				log.Error("Close|db_close|EINVAL")
				break
			} else if ret == C.DB_LOCK_DEADLOCK {
				log.Error("Close|db_close|DB_LOCK_DEADLOCK")
			} else if ret == C.DB_LOCK_NOTGRANTED {
				log.Error("Close|db_close|DB_LOCK_NOTGRANTED")
			} else {
				log.Error("Close|db_close|unknown|%v", ret)
				break
			}
			time.Sleep(time.Millisecond)
		}
	}()
}
コード例 #5
0
ファイル: config.go プロジェクト: sunbin728/mysvrs
func Init(configFile string) {
	tomlstr, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Error("read file error: %s", err)
	}
	if _, err := toml.Decode(string(tomlstr), &SConfig); err != nil {
		log.Error("toml.Decode error: %s", err)
	}
	log.Debug("%#v", SConfig)
}
コード例 #6
0
ファイル: conn.go プロジェクト: sunbin728/bdbd
func (c *Conn) readLine() ([]byte, error) {
	line, err := c.rb.ReadSlice('\n')
	if err != nil {
		log.Error("readLine|ReadSlice|%s", err.Error())
		return nil, err
	}
	if len(line) <= 2 {
		log.Error("readLine|empty")
		return nil, ErrRequest
	}
	if line[len(line)-2] != '\r' {
		log.Error("readLine|invalid")
		return nil, ErrRequest
	}
	return line[:len(line)-2], nil
}
コード例 #7
0
ファイル: util.go プロジェクト: sunbin728/mysvrs
func NumToUint64(arg interface{}) (uint64, error) {
	switch v := arg.(type) {
	case uint64:
		return v, nil
	case int:
		return uint64(v), nil
	case int64:
		return uint64(v), nil
	case uint:
		return uint64(v), nil
	case int32:
		return uint64(v), nil
	case uint32:
		return uint64(v), nil
	case int16:
		return uint64(v), nil
	case uint16:
		return uint64(v), nil
	case int8:
		return uint64(v), nil
	case uint8:
		return uint64(v), nil
	case float64:
		return uint64(v), nil
	case float32:
		return uint64(v), nil
	default:
		log.Error("ToInt64|unknown_type|%T,%v\n", arg, arg)
		return 0, errors.DataError
	}
}
コード例 #8
0
ファイル: util.go プロジェクト: sunbin728/mysvrs
//转换数字字符串
func StrToInt64(instr string) (int64, error) {
	tmp, err := strconv.ParseInt(instr, 10, 64)
	if err != nil {
		log.Error("StrToInt64|Invalid_String|%v|%v", err, instr)
		return 0, errors.DataError
	}
	return tmp, nil
}
コード例 #9
0
ファイル: mywebserver.go プロジェクト: sunbin728/mysvrs
// 主处理:根据FORM表单信息关键字method判断业务功能
func Start(httpaddr string, httpsaddr string) {
	http.HandleFunc("/mysvrs", mysvrshandler)
	http.HandleFunc("/ver", verhandler)
	http.HandleFunc("/now", nowhandler)

	err := http.ListenAndServe(httpaddr, nil)
	if err != nil {
		log.Error("Start err: %s", err)
	}
}
コード例 #10
0
ファイル: mywebserver.go プロジェクト: sunbin728/mysvrs
func Init() {
	visitfile, err := os.Open("visitcount.conf")
	if err != nil {
		log.Error("Init error: %s", err)
	}
	var buf []byte = make([]byte, 10)
	length, _ := visitfile.Read(buf)
	visitfile.Close()
	log.Debug("visitcount: %v, %s, %d", buf, string(buf[:length-1]), length)
	go refreshVisitCount()
}
コード例 #11
0
ファイル: conn.go プロジェクト: sunbin728/bdbd
func readNumber(buff []byte) (int64, error) {
	if len(buff) == 0 {
		log.Error("readNumber|empty")
		return 0, ErrRequest
	}
	var sign int64 = 1
	var r int64 = 0
	for i, c := range buff {
		if i == 0 && c == '-' {
			sign = -1
		} else if c < '0' || c > '9' {
			log.Error("readNumber|invalid|%v", int(c))
			return 0, ErrRequest
		} else {
			r *= 10
			r += int64(c - '0')
		}
	}
	return r * sign, nil
}
コード例 #12
0
ファイル: conn.go プロジェクト: sunbin728/bdbd
func (c *Conn) readCount(tag byte) (int64, error) {
	line, err := c.readLine()
	if err != nil {
		log.Error("readCount|readLine|%s", err.Error())
		return 0, err
	}
	if len(line) < 2 {
		log.Error("readCount|invalid|%v", line)
		return 0, ErrRequest
	}
	if line[0] != tag {
		log.Error("readCount|tag|%c", line[0])
		return 0, ErrRequest
	}
	count, err := readNumber(line[1:])
	if err != nil {
		log.Error("readCount|readNumber|%s", err.Error())
		return 0, ErrRequest
	}
	return count, nil
}
コード例 #13
0
ファイル: conn.go プロジェクト: sunbin728/bdbd
func PrintPanic(err interface{}) {
	if err != nil {
		log.Error("* panic:|%v", err)
	}
	for skip := 2; ; skip++ {
		_, file, line, ok := runtime.Caller(skip)
		if !ok {
			break
		}
		fmt.Printf("*  %v : %v\n", file, line)
	}
}
コード例 #14
0
ファイル: redis.go プロジェクト: shitfSign/redis-4
func (pool *Pool) checkPool() {
	var pos = 0
	for pool.total < pool.max {
		log.Debug("checkPool|%v|%v", pool.max, pool.total)
		// 需要新的连接
		var addrs = pool.addrs
		if pos >= len(addrs) {
			// 兜了一圈了,看看其他消息吧
			// 可能会有newAddr这样的消息需要切换服务器组
			log.Error("checkPool|retry_after")
			return
		}
		if conn, err := makeConn(addrs[pos], pool.pwd); err != nil {
			log.Error("checkPool|makeConn|%v", err)
			pos++
		} else {
			pool.connCh <- conn
			pool.total++
		}
	}
}
コード例 #15
0
ファイル: request.go プロジェクト: sunbin728/bdbd
func (w *Worker) getdb(table string, dbtype int) (*bdb.Db, error) {
	db := w.dbmap[table]
	if db == nil {
		var err error
		db, err = w.dbenv.GetDb(table, dbtype)
		if err != nil {
			log.Error("worker|GetDb|%s", err.Error())
			return nil, err
		}
		w.dbmap[table] = db
	}
	return db, nil
}
コード例 #16
0
ファイル: conn.go プロジェクト: sunbin728/bdbd
func (c *Conn) Start() {
	defer func() {
		c.Close()
		for _, v := range c.dbmap {
			v.Close()
		}
		if err := recover(); err != nil {
			PrintPanic(err)
		}
	}()
	for {
		err := c.processRequest()
		if err != nil {
			log.Error("Start|processRequest|%s", err.Error())
			break
		}
	}
}
コード例 #17
0
ファイル: redis.go プロジェクト: shitfSign/redis-4
func (pool *Pool) processSlaveWrite(conn *redisConn, err string) {
	log.Info("receive|slavewrite")
	// 主从切换了
	if strings.HasSuffix(err, ",unknown") {
		conn.pingTime = time.Now().Add(2 * time.Second).Unix()
		pool.connCh <- conn
	} else {
		params := strings.SplitN(err, ",", 2)
		if len(params) != 2 {
			log.Error("process|slavewrite|format_error|%s", err)
		} else {
			var newip = params[1]
			log.Info("receive|new_master|%v", newip)
			pool.newMasterCh <- newip
		}
		pool.badCh <- conn
	}
}
コード例 #18
0
ファイル: redis.go プロジェクト: shitfSign/redis-4
func (pool *Pool) checkEvent() {
	var timer *time.Timer
	for {
		if timer == nil {
			// 第一次等5秒
			timer = time.NewTimer(5 * time.Second)
		} else {
			// 如果触发事件后就需要立即处理
			// 但是为了防止cleanConn触发的大量badCh事件
			// 所以先等待50毫秒
			timer.Stop()
			timer = time.NewTimer(50 * time.Millisecond)
		}
		select {
		case newMaster := <-pool.newMasterCh:
			log.Info("checkEvent|newMasterCh|%v", newMaster)
			var found = false
			for i := 0; i < len(pool.addrs); i++ {
				if pool.addrs[i] == newMaster {
					log.Info("checkNewMaster|found")
					pool.addrs[0], pool.addrs[i] = pool.addrs[i], pool.addrs[0]
					pool.cleanConn()
					found = true
					break
				}
			}
			if !found {
				log.Error("checkEvent|newMasterCh|not_found|%v", newMaster)
			}
		case newAddr := <-pool.addrCh:
			log.Info("checkEvent|addrCh|%v", newAddr)
			pool.cleanConn()
			pool.poolAddr = newAddr
		case bad := <-pool.badCh:
			log.Info("checkEvent|badCh|%v|%v", bad.id, bad.addr)
			pool.total--
			bad.conn.Close()
		case <-timer.C:
			return
		}
	}
}
コード例 #19
0
ファイル: redis.go プロジェクト: shitfSign/redis-4
func processRequest(conn *redisConn, reqs []*redisReq) (err error) {
	var slaveError error
	log.Debug("processRequest|%v|%v", conn.id, len(reqs))
	for _, req := range reqs {
		conn.conn.Send(req.cmd, req.args...)
	}
	err = conn.conn.Flush()
	if err != nil {
		// 发送请求失败
		for _, req := range reqs {
			req.ch <- redisResp{nil, err}
		}
		return
	}
	for _, req := range reqs {
		var ok bool
		if err != nil {
			// 判断是否处于错误状态
			// 处于错误状态就不用再receive了
			req.ch <- redisResp{nil, err}
		} else {
			var v interface{}
			v, err = conn.conn.Receive()
			req.ch <- redisResp{v, err}
			if err != nil {
				log.Error("processRequest|Receive|%v", err)
				if err, ok = err.(redis.Error); ok {
					// redis.Error表示的是具体某个请求的数据错误
					// 该类型错误不影响后续请求的处理
					if strings.HasPrefix(err.Error(), "ERR slavewrite,") {
						slaveError = err
					}
					err = nil
				}
			}
		}
	}
	if slaveError != nil {
		err = slaveError
	}
	return
}
コード例 #20
0
ファイル: redis.go プロジェクト: shitfSign/redis-4
func (pool *Pool) testConn() {
	// testConn每次只检查一个连接
	var conn *redisConn
	select {
	case conn = <-pool.connCh:
	default:
		// 没有空闲的连接
		// 表示现在比较忙
		// 暂时就不检查了
		return
	}

	var masterAddr = pool.addrs[0]
	if conn.addr != masterAddr {
		if newconn, err := makeConn(masterAddr, pool.pwd); err != nil {
			log.Error("bkWorker|makeConn|%v", err)
		} else {
			// 主服务器已经能够连上了
			conn.conn.Close()
			conn = newconn
		}
	}
	if time.Now().Unix() > conn.pingTime {
		// 超过pingInterval,则ping一下连接
		if _, err := conn.conn.Do("set", "__ping", "1"); err != nil {
			if strings.HasPrefix(err.Error(), "ERR slavewrite,") {
				pool.processSlaveWrite(conn, err.Error())
			} else {
				log.Info("process|ping|%v", err)
				pool.badCh <- conn
			}
		} else {
			log.Debug("bgWorker|ping")
			pool.connCh <- conn
		}
	} else {
		pool.connCh <- conn
	}
	return
}
コード例 #21
0
ファイル: util.go プロジェクト: sunbin728/mysvrs
func AnyToInt64(v interface{}) (int64, error) {
	if v == nil {
		log.Error("AnyToInt64|nil")
		return 0, errors.DataError
	}
	switch v := v.(type) {
	case string:
		if v == "" {
			log.Error("AnyToInt64|empty_string", v)
			return 0, errors.DataError
		} else {
			outdata, err := strconv.ParseInt(v, 10, 64)
			if err != nil {
				log.Error("AnyToInt64|%v|%v", v, err)
				return 0, errors.DataError
			}
			return outdata, nil
		}
	case []string:
		if len(v) == 0 || v[0] == "" {
			log.Error("AnyToInt64|empty_array", v)
			return 0, errors.DataError
		} else {
			outdata, err := strconv.ParseInt(v[0], 10, 64)
			if err != nil {
				log.Error("AnyToInt64|%v|%v", v, err)
				return 0, errors.DataError
			}
			return outdata, nil
		}
	case []interface{}:
		if len(v) == 0 {
			log.Error("AnyToInt64|empty_array", v)
			return 0, errors.DataError
		} else {
			return AnyToInt64(v[0])
		}
	default:
		return NumToInt64(v)
	}
}
コード例 #22
0
ファイル: main.go プロジェクト: sunbin728/bdbd
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU() * 4)

	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)

	// master
	//go run main.go -h db1 -M -l 127.0.0.1:2345 -r 127.0.0.1:2346
	// slave
	//go run main.go -h db2 -C -l 127.0.0.1:2346 -r 127.0.0.1:2345

	configFile := "bdbd.conf"
	if len(os.Args) > 1 {
		configFile = os.Args[1]
	}
	configstr, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Println("ERROR: read config file failed:", err)
		os.Exit(1)
	}
	var config struct {
		Bdb    bdb.BdbConfig        `toml:"bdb"`
		Logger []mylog.LoggerDefine `toml:"logger"`
		Server struct {
			Listen string
		} `toml:"server"`
	}
	config.Bdb.Flush = 1
	_, err = toml.Decode(string(configstr), &config)
	if err != nil {
		log.Println("ERROR: decode config failed:", err)
		os.Exit(1)
	}

	mylog.Init(config.Logger)

	mylog.Info("bdb|starting")
	dbenv := bdb.Start(config.Bdb)
	mylog.Info("bdb|started")

	/*
		db, err := dbenv.GetDb("test")
		if err != nil {
			mylog.Fatal("dberr:%s", err.Error())
		}
		for i := 0; i < 1000000; i++ {
			if i%1000 == 0 {
				mylog.Info("%d", i)
			}
			k := fmt.Sprintf("k_%v", i)
			db.Set([]byte(k), []byte(k))
		}
		db.Close()
		dbenv.Exit()
		mylog.Fatal("end")
	*/

	go func() {
		addr, err := net.ResolveTCPAddr("tcp", config.Server.Listen)
		if err != nil {
			mylog.Fatal("ResolveTCPAddr|%s", err.Error())
		}
		listener, err := net.ListenTCP("tcp", addr)
		if err != nil {
			mylog.Fatal("Server|ListenTCP|%s", err.Error())
		}
		for {
			client, err := listener.AcceptTCP()
			if err != nil {
				mylog.Error("Server|%s", err.Error())
			}
			client.SetKeepAlive(true)
			conn := server.NewConn(client, dbenv)
			go conn.Start()
		}
	}()

	server.Start(dbenv)
	mylog.Info("start")
	<-signalChan
	server.Exit()
	dbenv.Exit()
	mylog.Info("bye")
}
コード例 #23
0
ファイル: bdb.go プロジェクト: sunbin728/bdbd
//export Error
func Error(msg *C.char) {
	log.Error(C.GoString(msg))
}
コード例 #24
0
ファイル: request.go プロジェクト: sunbin728/bdbd
func (w *Worker) bdbSetEx(req *bdbSetReq) {
	var err error
	if w.expiredb == nil {
		w.expiredb, err = w.dbenv.GetDb("__expire", bdb.DBTYPE_BTREE)
		if err != nil {
			log.Error("worker|GetDb|%s", err.Error())
			req.resp <- bdbSetResp{err}
			return
		}
	}
	if w.expireindex == nil {
		w.expireindex, err = w.dbenv.GetDb("__expire.index", bdb.DBTYPE_BTREE)
		if err != nil {
			log.Error("worker|GetDb|%s", err.Error())
			req.resp <- bdbSetResp{err}
			return
		}
	}

	txn, err := w.dbenv.Begin(bdb.DB_READ_UNCOMMITTED)
	if err != nil {
		req.resp <- bdbSetResp{err}
		return
	}
	defer func() {
		if txn != nil {
			txn.Abort()
		}
	}()
	w.seq++
	err = bdb.SetExpire(w.expiredb, w.expireindex, txn, req.key, req.sec, w.seq, w.id)
	if err != nil {
		if err == bdb.ErrRepDead {
			w.expiredb.Close()
			w.expiredb = nil
			w.expireindex.Close()
			w.expireindex = nil
		}
		log.Error("worker|SetExpire|%s", err.Error())
		req.resp <- bdbSetResp{err}
		return
	}

	table, name := bdb.SplitKey(req.key)
	db, err := w.getdb(table, bdb.DBTYPE_BTREE)
	if err != nil {
		w.checkerr(err, db)
		req.resp <- bdbSetResp{err}
		return
	}
	var flags uint32 = 0
	if req.nooverwrite {
		flags = flags | bdb.DB_NOOVERWRITE
	}
	err = db.Set(txn, name, req.value, flags)
	if err != nil {
		w.checkerr(err, db)
		req.resp <- bdbSetResp{err}
		return
	}

	txn.Commit()
	txn = nil
	req.resp <- bdbSetResp{nil}
}