func (s *Server) waitOnline() { for { info, err := s.topo.GetProxyInfo(s.info.Id) if err != nil { log.PanicErrorf(err, "get proxy info failed") } switch info.State { case models.PROXY_STATE_MARK_OFFLINE: s.handleMarkOffline() case models.PROXY_STATE_ONLINE: s.info.State = info.State log.Infof("we are online: %s", s.info.Id) _, err := s.topo.WatchNode(path.Join(models.GetProxyPath(s.topo.ProductName), s.info.Id), s.evtbus) if err != nil { log.PanicErrorf(err, "watch node failed") } return } select { case e := <-s.evtbus: switch e.(type) { case *killEvent: s.handleMarkOffline() } default: //otherwise ignore it } log.Warnf("wait to be online: %s", s.info.Id) time.Sleep(3 * time.Second) } }
func (s *Server) processAction(e interface{}) { if strings.Index(getEventPath(e), models.GetProxyPath(s.topo.ProductName)) == 0 { info, err := s.topo.GetProxyInfo(s.info.Id) if err != nil { log.PanicErrorf(err, "get proxy info failed: %s", s.info.Id) } switch info.State { case models.PROXY_STATE_MARK_OFFLINE: log.Infof("mark offline, proxy got offline event: %s", s.info.Id) s.markOffline() case models.PROXY_STATE_ONLINE: s.rewatchProxy() default: log.Panicf("unknown proxy state %v", info) } return } //re-watch nodes := s.rewatchNodes() seqs, err := models.ExtraSeqList(nodes) if err != nil { log.PanicErrorf(err, "get seq list failed") } if len(seqs) == 0 || !s.topo.IsChildrenChangedEvent(e) { return } //get last pos index := -1 for i, seq := range seqs { if s.lastActionSeq < seq { index = i //break //only handle latest action } } if index < 0 { return } actions := seqs[index:] for _, seq := range actions { exist, err := s.topo.Exist(path.Join(s.topo.GetActionResponsePath(seq), s.info.Id)) if err != nil { log.PanicErrorf(err, "get action failed") } if exist { continue } if s.checkAndDoTopoChange(seq) { s.responseAction(int64(seq)) } } s.lastActionSeq = seqs[len(seqs)-1] }
func LoadCodisEnv(cfg *cfg.Cfg) Env { if cfg == nil { log.Panicf("config is nil") } productName, err := cfg.ReadString("product", "test") if err != nil { log.PanicErrorf(err, "read product name failed") } zkAddr, err := cfg.ReadString("zk", "localhost:2181") if err != nil { log.PanicErrorf(err, "read zk address failed") } hostname, _ := os.Hostname() dashboardAddr, err := cfg.ReadString("dashboard_addr", hostname+":18087") if err != nil { log.PanicErrorf(err, "read dashboard address failed") } provider, err := cfg.ReadString("coordinator", "zookeeper") if err != nil { log.PanicErrorf(err, "read coordinator failed") } return &CodisEnv{ zkAddr: zkAddr, dashboardAddr: dashboardAddr, productName: productName, provider: provider, } }
func (s *Server) register() { if _, err := s.topo.CreateProxyInfo(&s.info); err != nil { log.PanicErrorf(err, "create proxy node failed") } if _, err := s.topo.CreateProxyFenceNode(&s.info); err != nil { log.PanicErrorf(err, "create fence node failed") } }
func (s *Server) processAction(e interface{}) { if strings.Index(getEventPath(e), models.GetProxyPath(s.topo.ProductName)) == 0 { info, err := s.topo.GetProxyInfo(s.info.Id) if err != nil { log.PanicErrorf(err, "get proxy info failed: %s", s.info.Id) } if info.State == models.PROXY_STATE_MARK_OFFLINE { s.handleMarkOffline() } return } //re-watch nodes, err := s.topo.WatchChildren(models.GetWatchActionPath(s.topo.ProductName), s.evtbus) if err != nil { log.PanicErrorf(err, "rewatch children failed") } seqs, err := models.ExtraSeqList(nodes) if err != nil { log.PanicErrorf(err, "get seq list failed") } if len(seqs) == 0 || !s.topo.IsChildrenChangedEvent(e) { return } //get last pos index := -1 for i, seq := range seqs { if s.lastActionSeq < seq { index = i break } } if index < 0 { return } actions := seqs[index:] for _, seq := range actions { exist, err := s.topo.Exist(path.Join(s.topo.GetActionResponsePath(seq), s.info.Id)) if err != nil { log.PanicErrorf(err, "get action failed") } if exist { continue } if s.checkAndDoTopoChange(seq) { s.responseAction(int64(seq)) } } s.lastActionSeq = seqs[len(seqs)-1] }
func (s *Server) register() { if _, err := s.topo.CreateProxyInfo(&s.info); err != nil { log.PanicErrorf(err, "create proxy node failed") } if _, err := s.topo.CreateProxyFenceNode(&s.info); err != nil && err != zk.ErrNodeExists { log.PanicErrorf(err, "create fence node failed") } log.Warn("********** Attention **********") log.Warn("You should use `kill {pid}` rather than `kill -9 {pid}` to stop me,") log.Warn("or the node resisted on zk will not be cleaned when I'm quiting and you must remove it manually") log.Warn("*******************************") }
func New(addr string, debugVarAddr string, conf *Config) *Server { log.Infof("create proxy with config: %+v", conf) proxyHost := strings.Split(addr, ":")[0] debugHost := strings.Split(debugVarAddr, ":")[0] hostname, err := os.Hostname() if err != nil { log.PanicErrorf(err, "get host name failed") } if proxyHost == "0.0.0.0" || strings.HasPrefix(proxyHost, "127.0.0.") || proxyHost == "" { proxyHost = hostname } if debugHost == "0.0.0.0" || strings.HasPrefix(debugHost, "127.0.0.") || debugHost == "" { debugHost = hostname } s := &Server{conf: conf, lastActionSeq: -1, groups: make(map[int]int)} s.topo = NewTopo(conf.productName, conf.zkAddr, conf.fact, conf.provider, conf.zkSessionTimeout) s.info.Id = conf.proxyId s.info.State = models.PROXY_STATE_OFFLINE s.info.Addr = proxyHost + ":" + strings.Split(addr, ":")[1] s.info.DebugVarAddr = debugHost + ":" + strings.Split(debugVarAddr, ":")[1] s.info.Pid = os.Getpid() s.info.StartAt = time.Now().String() s.kill = make(chan interface{}) log.Infof("proxy info = %+v", s.info) if l, err := net.Listen(conf.proto, addr); err != nil { log.PanicErrorf(err, "open listener failed") } else { s.listener = l } s.router = router.NewWithAuth(conf.passwd) s.evtbus = make(chan interface{}, 1024) s.sessionPool = &sync.Pool{ New: func() interface{} { return nil }, } s.register() s.wait.Add(1) go func() { defer s.wait.Done() s.serve() }() return s }
func (s *Server) checkAndDoTopoChange(seq int) bool { act, err := s.topo.GetActionWithSeq(int64(seq)) if err != nil { //todo: error is not "not exist" log.PanicErrorf(err, "action failed, seq = %d", seq) } if !needResponse(act.Receivers, s.info) { //no need to response return false } log.Warnf("action %v receivers %v", seq, act.Receivers) switch act.Type { case models.ACTION_TYPE_SLOT_MIGRATE, models.ACTION_TYPE_SLOT_CHANGED, models.ACTION_TYPE_SLOT_PREMIGRATE: slot := &models.Slot{} s.getActionObject(seq, slot) s.fillSlot(slot.Id) case models.ACTION_TYPE_SERVER_GROUP_CHANGED: serverGroup := &models.ServerGroup{} s.getActionObject(seq, serverGroup) s.onGroupChange(serverGroup.Id) case models.ACTION_TYPE_SERVER_GROUP_REMOVE: //do not care case models.ACTION_TYPE_MULTI_SLOT_CHANGED: param := &models.SlotMultiSetParam{} s.getActionObject(seq, param) s.onSlotRangeChange(param) default: log.Panicf("unknown action %+v", act) } return true }
func (top *Topology) InitZkConn() { var err error top.zkConn, err = top.fact(top.zkAddr) if err != nil { log.PanicErrorf(err, "init failed") } }
func LoadConf(configFile string) (*Config, error) { c, err := utils.InitConfigFromFile(configFile) if err != nil { log.PanicErrorf(err, "load config '%s' failed", configFile) } conf := &Config{} conf.productName, _ = c.ReadString("product", "test") if len(conf.productName) == 0 { log.Panicf("invalid config: product entry is missing in %s", configFile) } conf.zkAddr, _ = c.ReadString("zk", "") if len(conf.zkAddr) == 0 { log.Panicf("invalid config: need zk entry is missing in %s", configFile) } conf.zkAddr = strings.TrimSpace(conf.zkAddr) conf.proxyId, _ = c.ReadString("proxy_id", "") if len(conf.proxyId) == 0 { log.Panicf("invalid config: need proxy_id entry is missing in %s", configFile) } conf.netTimeout, _ = c.ReadInt("net_timeout", 5) conf.proto, _ = c.ReadString("proto", "tcp") conf.provider, _ = c.ReadString("coordinator", "zookeeper") return conf, nil }
func (s *Server) rewatchNodes() []string { nodes, err := s.topo.WatchChildren(models.GetWatchActionPath(s.topo.ProductName), s.evtbus) if err != nil { log.PanicErrorf(err, "watch children failed") } return nodes }
func (s *Server) waitOnline() bool { for { info, err := s.topo.GetProxyInfo(s.info.Id) if err != nil { log.PanicErrorf(err, "get proxy info failed: %s", s.info.Id) } switch info.State { case models.PROXY_STATE_MARK_OFFLINE: log.Infof("mark offline, proxy got offline event: %s", s.info.Id) s.markOffline() return false case models.PROXY_STATE_ONLINE: s.info.State = info.State log.Infof("we are online: %s", s.info.Id) s.rewatchProxy() return true } select { case <-s.kill: log.Infof("mark offline, proxy is killed: %s", s.info.Id) s.markOffline() return false default: } log.Infof("wait to be online: %s", s.info.Id) time.Sleep(3 * time.Second) } }
func GetExecutorPath() string { filedirectory := filepath.Dir(os.Args[0]) execPath, err := filepath.Abs(filedirectory) if err != nil { log.PanicErrorf(err, "get executor path failed") } return execPath }
func (s *Server) getActionObject(seq int, target interface{}) { act := &models.Action{Target: target} err := s.topo.GetActionWithSeqObject(int64(seq), act) if err != nil { log.PanicErrorf(err, "get action object failed, seq = %d", seq) } log.Infof("action %+v", act) }
func (s *Server) RegisterAndWait() { _, err := s.topo.CreateProxyInfo(&s.info) if err != nil { log.PanicErrorf(err, "create proxy node failed") } _, err = s.topo.CreateProxyFenceNode(&s.info) if err != nil { log.WarnErrorf(err, "create fence node failed") } s.registerSignal() s.waitOnline() }
func (c *safeConn) Get(path string) (data []byte, stat zk.Stat, err error) { for i := 0; i <= retryMaxOnOps; i++ { c.builder.lock.RLock() data, stat, err = c.Conn.Get(path) c.builder.lock.RUnlock() if err == nil || !isConnectionError(err) { return } c.builder.resetConnection() } log.PanicErrorf(err, "zk error after retries") return }
func (c *safeConn) Delete(path string, version int32) (err error) { for i := 0; i <= retryMaxOnOps; i++ { c.builder.lock.RLock() err = c.Conn.Delete(path, version) c.builder.lock.RUnlock() if err == nil || !isConnectionError(err) { return } c.builder.resetConnection() } log.PanicErrorf(err, "zk error after retries") return }
func (c *safeConn) Create(path string, value []byte, flags int32, aclv []zk.ACL) (pathCreated string, err error) { for i := 0; i <= retryMaxOnOps; i++ { c.builder.lock.RLock() pathCreated, err = c.Conn.Create(path, value, flags, aclv) c.builder.lock.RUnlock() if err == nil || !isConnectionError(err) { return } c.builder.resetConnection() } log.PanicErrorf(err, "zk error after retries") return }
func (c *safeConn) ExistsW(path string) (exist bool, stat zk.Stat, watch <-chan zk.Event, err error) { for i := 0; i <= retryMaxOnOps; i++ { c.builder.lock.RLock() exist, stat, watch, err = c.Conn.ExistsW(path) c.builder.lock.RUnlock() if err == nil || !isConnectionError(err) { return } c.builder.resetConnection() } log.PanicErrorf(err, "zk error after retries") return }
func (c *safeConn) Children(path string) (children []string, stat zk.Stat, err error) { for i := 0; i <= retryMaxOnOps; i++ { c.builder.lock.RLock() children, stat, err = c.Conn.Children(path) c.builder.lock.RUnlock() if err == nil || !isConnectionError(err) { return } c.builder.resetConnection() } log.PanicErrorf(err, "zk error after retries") return }
func (c *safeConn) SetACL(path string, aclv []zk.ACL, version int32) (stat zk.Stat, err error) { for i := 0; i <= retryMaxOnOps; i++ { c.builder.lock.RLock() stat, err = c.Conn.SetACL(path, aclv, version) c.builder.lock.RUnlock() if err == nil || !isConnectionError(err) { return } c.builder.resetConnection() } log.PanicErrorf(err, "zk error after retries") return }
func (s *Server) fillSlot(i int) { slotInfo, slotGroup, err := s.topo.GetSlotByIndex(i) if err != nil { log.PanicErrorf(err, "get slot by index failed", i) } var from string var addr = groupMaster(*slotGroup) if slotInfo.State.Status == models.SLOT_STATUS_MIGRATE { fromGroup, err := s.topo.GetGroup(slotInfo.State.MigrateStatus.From) if err != nil { log.PanicErrorf(err, "get migrate from failed") } from = groupMaster(*fromGroup) if from == addr { log.Panicf("set slot %04d migrate from %s to %s", i, from, addr) } } s.groups[i] = slotInfo.GroupId s.router.FillSlot(i, addr, from, slotInfo.State.Status == models.SLOT_STATUS_PRE_MIGRATE) }
func LoadConf(configFile string) (*Config, error) { c := cfg.NewCfg(configFile) if err := c.Load(); err != nil { log.PanicErrorf(err, "load config '%s' failed", configFile) } conf := &Config{} conf.productName, _ = c.ReadString("product", "test") if len(conf.productName) == 0 { log.Panicf("invalid config: product entry is missing in %s", configFile) } conf.dashboardAddr, _ = c.ReadString("dashboard_addr", "") if conf.dashboardAddr == "" { log.Panicf("invalid config: dashboard_addr is missing in %s", configFile) } conf.zkAddr, _ = c.ReadString("zk", "") if len(conf.zkAddr) == 0 { log.Panicf("invalid config: need zk entry is missing in %s", configFile) } conf.zkAddr = strings.TrimSpace(conf.zkAddr) conf.passwd, _ = c.ReadString("password", "") conf.proxyId, _ = c.ReadString("proxy_id", "") if len(conf.proxyId) == 0 { log.Panicf("invalid config: need proxy_id entry is missing in %s", configFile) } conf.proto, _ = c.ReadString("proto", "tcp") conf.provider, _ = c.ReadString("coordinator", "zookeeper") loadConfInt := func(entry string, defval int) int { v, _ := c.ReadInt(entry, defval) if v < 0 { log.Panicf("invalid config: read %s = %d", entry, v) } return v } conf.pingPeriod = loadConfInt("backend_ping_period", 5) conf.maxTimeout = loadConfInt("session_max_timeout", 1800) conf.maxBufSize = loadConfInt("session_max_bufsize", 131072) conf.maxPipeline = loadConfInt("session_max_pipeline", 1024) conf.zkSessionTimeout = loadConfInt("zk_session_timeout", 30000) if conf.zkSessionTimeout <= 100 { conf.zkSessionTimeout *= 1000 log.Warn("zkSessionTimeout is to small, it is ms not second") } return conf, nil }
func LoadCodisEnv(cfg *cfg.Cfg) Env { if cfg == nil { log.Panicf("config is nil") } productName, err := cfg.ReadString("product", "test") if err != nil { log.PanicErrorf(err, "config: 'product' not found") } zkAddr, err := cfg.ReadString("zk", "localhost:2181") if err != nil { log.PanicErrorf(err, "config: 'zk' not found") } hostname, _ := os.Hostname() dashboardAddr, err := cfg.ReadString("dashboard_addr", hostname+":18087") if err != nil { log.PanicErrorf(err, "config: 'dashboard_addr' not found") } provider, err := cfg.ReadString("coordinator", "zookeeper") if err != nil { log.PanicErrorf(err, "config: 'coordinator' not found") } passwd, _ := cfg.ReadString("password", "") return &CodisEnv{ zkAddr: zkAddr, passwd: passwd, dashboardAddr: dashboardAddr, productName: productName, provider: provider, } }
func LoadConf(configFile string) (*Config, error) { c, err := utils.InitConfigFromFile(configFile) if err != nil { log.PanicErrorf(err, "load config '%s' failed", configFile) } conf := &Config{} conf.productName, _ = c.ReadString("product", "test") if len(conf.productName) == 0 { log.Panicf("invalid config: product entry is missing in %s", configFile) } conf.zkAddr, _ = c.ReadString("zk", "") if len(conf.zkAddr) == 0 { log.Panicf("invalid config: need zk entry is missing in %s", configFile) } conf.zkAddr = strings.TrimSpace(conf.zkAddr) conf.passwd, _ = c.ReadString("requirepass", "") conf.proxyId, _ = c.ReadString("proxy_id", "") if len(conf.proxyId) == 0 { log.Panicf("invalid config: need proxy_id entry is missing in %s", configFile) } conf.proto, _ = c.ReadString("proto", "tcp") conf.provider, _ = c.ReadString("coordinator", "zookeeper") loadConfInt := func(entry string, defInt int) int { v, _ := c.ReadInt(entry, defInt) if v < 0 { log.Panicf("invalid config: read %s = %d", entry, v) } return v } conf.pingPeriod = loadConfInt("backend_ping_period", 5) conf.maxTimeout = loadConfInt("session_max_timeout", 1800) conf.maxBufSize = loadConfInt("session_max_bufsize", 1024*32) conf.maxPipeline = loadConfInt("session_max_pipeline", 128) return conf, nil }
func main() { c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt) signal.Notify(c, syscall.SIGTERM) go func() { <-c if createdDashboardNode { releaseDashboardNode() } log.Panicf("ctrl-c or SIGTERM found, exit") }() args, err := docopt.Parse(usage, nil, true, utils.Version, true) if err != nil { fmt.Println(err) os.Exit(1) } // set output log file if s, ok := args["-L"].(string); ok && s != "" { f, err := os.OpenFile(s, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) if err != nil { log.PanicErrorf(err, "open log file failed: %s", s) } else { defer f.Close() log.StdLog = log.New(f, "") } } log.SetLevel(log.LEVEL_INFO) log.SetFlags(log.Flags() | log.Lshortfile) // set log level if s, ok := args["--log-level"].(string); ok && s != "" { setLogLevel(s) } // set config file var configFile string if args["-c"] != nil { configFile = args["-c"].(string) } else { configFile = "config.ini" } config := cfg.NewCfg(configFile) if err := config.Load(); err != nil { log.PanicErrorf(err, "load config file error") } // load global vars globalEnv = LoadCodisEnv(config) cmd := args["<command>"].(string) cmdArgs := args["<args>"].([]string) go http.ListenAndServe(":10086", nil) err = runCommand(cmd, cmdArgs) if err != nil { log.PanicErrorf(err, "run sub-command failed") } }
func (s *Server) fillSlot(i int, force bool) { if !s.isValidSlot(i) { return } slot := s.slots[i] if !force && slot.backend.bc != nil { log.Panicf("slot %04d already filled, slot: %+v", i, slot) } slotInfo, slotGroup, err := s.topo.GetSlotByIndex(i) if err != nil { log.PanicErrorf(err, "get slot by index failed", i) } var from string var addr = group.NewGroup(*slotGroup).Master() if slotInfo.State.Status == models.SLOT_STATUS_MIGRATE { fromGroup, err := s.topo.GetGroup(slotInfo.State.MigrateStatus.From) if err != nil { log.PanicErrorf(err, "get migrate from failed") } from = group.NewGroup(*fromGroup).Master() if from == addr { log.Panicf("set slot %04d migrate from %s to %s", i, from, addr) } } slot.blockAndWait() s.putBackendConn(slot.backend.bc) s.putBackendConn(slot.migrate.bc) slot.reset() slot.Info, slot.Group = slotInfo, slotGroup if len(addr) != 0 { xx := strings.Split(addr, ":") if len(xx) >= 1 { slot.backend.host = []byte(xx[0]) } if len(xx) >= 2 { slot.backend.port = []byte(xx[1]) } slot.backend.addr = addr slot.backend.bc = s.getBackendConn(addr) } if len(from) != 0 { slot.migrate.from = from slot.migrate.bc = s.getBackendConn(from) } if slotInfo.State.Status != models.SLOT_STATUS_PRE_MIGRATE { slot.unblock() } if slot.migrate.bc != nil { log.Infof("fill slot %04d, force %v, backend.addr = %s, migrate.from = %s", i, force, slot.backend.addr, slot.migrate.from) } else { log.Infof("fill slot %04d, force %v, backend.addr = %s", i, force, slot.backend.addr) } }
func NewServer(addr string, debugVarAddr string, conf *Config) (*Server, error) { log.Infof("start proxy with config: %+v", conf) s := &Server{ evtbus: make(chan interface{}, 1000), conf: conf, topo: topology.NewTopo(conf.productName, conf.zkAddr, conf.fact, conf.provider), pool: make(map[string]*SharedBackendConn), lastActionSeq: -1, } for i := 0; i < MaxSlotNum; i++ { s.slots[i] = &Slot{Id: i} } proxyHost := strings.Split(addr, ":")[0] debugHost := strings.Split(debugVarAddr, ":")[0] hostname, err := os.Hostname() if err != nil { log.PanicErrorf(err, "get host name failed") } if proxyHost == "0.0.0.0" || strings.HasPrefix(proxyHost, "127.0.0.") { proxyHost = hostname } if debugHost == "0.0.0.0" || strings.HasPrefix(debugHost, "127.0.0.") { debugHost = hostname } s.info.Id = conf.proxyId s.info.State = models.PROXY_STATE_OFFLINE s.info.Addr = proxyHost + ":" + strings.Split(addr, ":")[1] s.info.DebugVarAddr = debugHost + ":" + strings.Split(debugVarAddr, ":")[1] s.info.Pid = os.Getpid() s.info.StartAt = time.Now().String() log.Infof("proxy info = %+v", s.info) if l, err := net.Listen(conf.proto, addr); err != nil { return nil, errors.Trace(err) } else { s.Listener = l } stats.Publish("evtbus", stats.StringFunc(func() string { return strconv.Itoa(len(s.evtbus)) })) stats.PublishJSONFunc("router", func() string { var m = make(map[string]interface{}) m["ops"] = cmdstats.requests.Get() m["cmds"] = getAllOpStats() m["info"] = s.info m["build"] = map[string]interface{}{ "version": utils.Version, "compile": utils.Compile, } b, _ := json.Marshal(m) return string(b) }) s.RegisterAndWait() _, err = s.topo.WatchChildren(models.GetWatchActionPath(conf.productName), s.evtbus) if err != nil { log.PanicErrorf(err, "watch children failed") } for i := 0; i < MaxSlotNum; i++ { s.fillSlot(i, false) } go s.handleTopoEvent() log.Info("proxy start ok") return s, nil }
func (s *Server) rewatchProxy() { _, err := s.topo.WatchNode(path.Join(models.GetProxyPath(s.topo.ProductName), s.info.Id), s.evtbus) if err != nil { log.PanicErrorf(err, "watch node failed") } }
func main() { fmt.Print(banner) args, err := docopt.Parse(usage, nil, true, "codis proxy v0.1", true) if err != nil { fmt.Println(err) os.Exit(1) } // set config file if args["-c"] != nil { configFile = args["-c"].(string) } var maxFileFrag = 10 var maxFragSize int64 = bytesize.GB * 1 if s, ok := args["--log-filesize"].(string); ok && s != "" { v, err := bytesize.Parse(s) if err != nil { log.PanicErrorf(err, "invalid max log file size = %s", s) } maxFragSize = v } // set output log file if s, ok := args["-L"].(string); ok && s != "" { f, err := log.NewRollingFile(s, maxFileFrag, maxFragSize) if err != nil { log.PanicErrorf(err, "open rolling log file failed: %s", s) } else { defer f.Close() log.StdLog = log.New(f, "") } } log.SetLevel(log.LEVEL_INFO) // set log level if s, ok := args["--log-level"].(string); ok && s != "" { setLogLevel(s) } // set cpu if args["--cpu"] != nil { cpus, err = strconv.Atoi(args["--cpu"].(string)) if err != nil { log.PanicErrorf(err, "parse cpu number failed") } } // set addr if args["--addr"] != nil { addr = args["--addr"].(string) } // set http addr if args["--http-addr"] != nil { httpAddr = args["--http-addr"].(string) } checkUlimit(1024) runtime.GOMAXPROCS(cpus) http.HandleFunc("/setloglevel", handleSetLogLevel) go http.ListenAndServe(httpAddr, nil) log.Info("running on ", addr) conf, err := router.LoadConf(configFile) if err != nil { log.PanicErrorf(err, "load config failed") } s, err := router.NewServer(addr, httpAddr, conf) if err != nil { log.PanicErrorf(err, "create new server failed") } if err := s.Serve(); err != nil { log.PanicErrorf(err, "serve failed") } panic("exit") }