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 }
func (w *Worker) start() { workWait.Add(1) defer func() { for _, db := range w.dbmap { db.Close() } if w.getbuff != 0 { C.free(unsafe.Pointer(w.getbuff)) } log.Info("server|close|work|%d", w.id) workWait.Done() }() for req := range workChan { switch req := req.(type) { case bdbSetReq: if req.sec == 0 { w.bdbSet(&req) } else { w.bdbSetEx(&req) } case bdbGetReq: w.bdbGet(&req) case bdbIncrByReq: w.bdbIncrBy(&req) } } }
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 } }
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 } } }
func (pool *Pool) cleanConn() { log.Info("cleanConn") for pool.total > 0 { var conn *redisConn select { case conn = <-pool.connCh: case conn = <-pool.badCh: } conn.conn.Close() pool.total-- } log.Debug("cleanConn|ok") }
func main() { flag.Parse() gomax := int(float64(runtime.NumCPU()) * 1.5) runtime.GOMAXPROCS(gomax) signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) log.InitFromFile(*logconf) log.Info("version:%v", util.GetVersion()) log.Info("start...") Init() go myweb.Start(config.SConfig.Http, config.SConfig.Https) log.Info("Welcome to mysvrs") <-signalChan log.Info("bye") os.Exit(0) }
func (pool *Pool) processWorker(conn *redisConn, reqs []*redisReq) { var err = processRequest(conn, reqs) if err != nil { log.Info("process|processRequest|%v", err) if strings.HasPrefix(err.Error(), "ERR slavewrite,") { pool.processSlaveWrite(conn, err.Error()) } else { pool.badCh <- conn } } else { conn.pingTime = time.Now().Add(pingInterval).Unix() pool.connCh <- conn } reqsPool.Put(reqs) }
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 }
func Start(config BdbConfig) *DbEnv { args := make([]string, 0, 20) if config.AckAll && config.RepMgr { args = append(args, "-a") } if config.Bulk { args = append(args, "-b") } if config.Master { args = append(args, "-M") } else if !config.RepMgr { args = append(args, "-C") } if config.HomeDir == "" { log.Fatal("bdb|homedir_missing") } args = append(args, "-h", config.HomeDir) _, err := os.Stat(config.HomeDir) if err != nil && os.IsNotExist(err) { os.Mkdir(config.HomeDir, os.ModePerm) } if config.LocalAddr == "" { log.Fatal("bdb|localaddr_missing") } if config.RepMgr && config.Master { args = append(args, "-L", config.LocalAddr) } else { args = append(args, "-l", config.LocalAddr) } if config.DisableElection { args = append(args, "-p", "0") } else if config.Priority != 0 { args = append(args, "-p", strconv.FormatInt(int64(config.Priority), 10)) } if config.RepMgr && config.RemotePeer != "" { if len(config.RemoteAddr) != 0 { log.Fatal("bdb|conflict_RemoteAddr_RemotePeer") } args = append(args, "-R", config.RemotePeer) } else { for _, remote := range config.RemoteAddr { args = append(args, "-r", remote) } } if config.Verbose { args = append(args, "-v") } dbenv := new(DbEnv) dbenv.waitStop.Add(1) dbenv.waitExit.Add(1) dbenv.waitReady.Add(1) go func() { argv := make([]*C.char, len(args)+1) for i, arg := range args { argv[i+1] = C.CString(arg) } argv[0] = C.CString("bdbd") if config.RepMgr { log.Info("start_repmgr|%v", args) C.start_mgr(C.int(len(argv)), &argv[0], C.int(config.Flush), unsafe.Pointer(dbenv)) } else { log.Info("start_base|%v", args) C.start_base(C.int(len(argv)), &argv[0], C.int(config.Flush), unsafe.Pointer(dbenv)) } for _, arg := range argv { C.free(unsafe.Pointer(arg)) } dbenv.waitExit.Done() }() dbenv.waitReady.Wait() return dbenv }
//export Info func Info(msg *C.char) { log.Info(C.GoString(msg)) }
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") }