/** * @brief 获取一个db连接 * * @param $key 选择的key * @param $getNew 是否生成新连接 * @param $replace 指出是否用新生成连接覆盖保存的连接 * * @return */ public function getDB($key = NULL, $getNew = false, $replace = true) { if ($this->db !== NULL && !$getNew) { return $this->db; } $db = new Bd_DB(Bd_Db_DBMan::$ENABLE_PROFILING); if (Bd_Db_DBMan::$CONN_TIMEOUT > 0) { $db->setConnectTimeOut(Bd_Db_DBMan::$CONN_TIMEOUT); } // 尝试的次数 $try_count = 0; while (true) { if (count($this->validHosts) == 0 || ($index = $this->hostSelector->select($this, $key)) === false) { return false; } // return the same host if ($this->currentHostIndex === $index) { return $this->db; } // do connect $host = $this->allHosts[$index]; $ret = $db->connect($host[0], $this->userConf['uname'], $this->userConf['passwd'], $this->dbname, $host[1], Bd_Db_DBMan::$CONN_FLAGS); // got it if ($ret) { break; } // record failed host $this->_recordFailedHost($index); // try count exceeded if (++$try_count == Bd_Db_DBMan::$MAX_TRY_COUNT) { return false; } } if ($this->db == NULL || $replace) { $this->currentHostIndex = $index; $this->db = $db; } return $db; }
/** * @brief 获取db对象 * * @param $clusterName 集群名称 * @param $key 负载均衡key * @param $getNew 是否重新连接 * * @return */ public static function getConn($clusterName, $key = NULL, $getNew = false) { $hookBeforeInit = Bd_Conf::getConf('/db/hook_before_init'); if ($hookBeforeInit === false) { //cannot find hookBeforeInit in conf file self::$_error['errno'] = LOAD_CONF_ERROR; self::$_error['error'] = 'Can not read hookBeforeInit, please check db/global.conf'; Bd_Log::warning(self::$_error['error'], self::$_error['errno']); return false; } if ($hookBeforeInit != NULL) { //user sets hookBeforeInit if (is_callable($hookBeforeInit)) { $clusterName = call_user_func($hookBeforeInit, $clusterName); } else { //warnning self::$_error['errno'] = SET_HOOK_ERROR; self::$_error['error'] = 'Hook(beforinit):' . $before . 'is not callable'; Bd_Log::warning(self::$_error['error'], self::$_error['errno']); } } $conf =& self::$_conf; $hosts =& self::$_hosts; $dbData =& self::$_dbData; $lastDb =& self::$_lastDb; //(1) alreay save a connection (2)user do not need to recreate if (!empty($lastDb[$clusterName]) && !$getNew) { Bd_Log::trace('Return an existing connection', 0, array('db_cluster' => $clusterName)); return $lastDb[$clusterName]; } if (self::_init($clusterName) === false) { return false; } //create a new db object $db = new Bd_DB(Bd_Db_ConnMgr::$ENABLE_PROFILING); //add hook if ('' !== ($before = $conf['hook_before_query'])) { if (!$db->addHook(Bd_Db::HK_BEFORE_QUERY, $clusterName . '-before', $before)) { self::$_error['errno'] = SET_HOOK_ERROR; self::$_error['error'] = 'Hook(befor query):' . $before . ' is not callable'; Bd_Log::warning(self::$_error['error'], self::$_error['errno']); } } if ('' !== ($after = $conf['hook_after_query'])) { if (!$db->addHook(Bd_Db::HK_AFTER_QUERY, $clusterName . '-after', $after)) { self::$_error['errno'] = SET_HOOK_ERROR; self::$_error['error'] = 'Hook(after query):' . $after . ' is not callable'; Bd_Log::warning(self::$_error['error'], self::$_error['errno']); } } if ('' !== ($onFail = $conf['hook_on_fail'])) { if (!$db->onFail($onFail)) { self::$_error['errno'] = SET_HOOK_ERROR; self::$_error['error'] = 'Hook(on fail):' . $onFail . ' is not callable'; Bd_Log::warning(self::$_error['error'], self::$_error['errno']); } } //try to connect host until there is not host or connecting successfully while (true) { //balancer could not select a valid host to connect if (count($hosts['valid_hosts']) === 0 || ($index = $dbData['host_selector']->select($hosts, $key)) === false) { self::$_error['errno'] = ALL_CONNECT_ERROR; self::$_error['error'] = 'No host could be connected in the cluster'; Bd_Log::warning(self::$_error['error'], self::$_error['errno'], array('db_cluster' => $clusterName)); $hookOnConnFail = $conf['hook_on_connect_fail']; if ($hookOnConnFail != NULL) { if (is_callable($hookOnConnFail)) { call_user_func($hookOnConnFail); } else { //warnning self::$_error['errno'] = SET_HOOK_ERROR; self::$_error['error'] = 'Hook(on connect fail):' . $hookOnConnFail . 'is not callable'; Bd_Log::warning(self::$_error['error'], self::$_error['errno']); } } return false; } //log parameters $logPara = array('db_cluster' => $clusterName, 'db_host' => $hosts['valid_hosts'][$index]['ip'], 'db_port' => $hosts['valid_hosts'][$index]['port'], 'default_db' => $conf['default_db']); for ($i = 1; $i <= $conf['retry_times']; $i++) { $timeout = $conf['connect_timeout_s']; if ($timeout > 0) { $db->setConnectTimeOut($timeout); } $r_timeout = $conf['read_timeout_s']; if ($r_timeout > 0) { $db->setOption(MYSQL_OPT_READ_TIMEOUT, $r_timeout); } $w_timeout = $conf['write_timeout_s']; if ($w_timeout > 0) { $db->setOption(MYSQL_OPT_WRITE_TIMEOUT, $w_timeout); } Bd_Log::debug("retry times: {$i}"); $start = microtime(true) * 1000; //connect $ret = $db->connect($hosts['valid_hosts'][$index]['ip'], $conf['username'], $conf['password'], $conf['default_db'], $hosts['valid_hosts'][$index]['port'], $conf['connect_flag']); $end = microtime(true) * 1000; if ($ret) { if (empty($conf['charset']) || $db->charset($conf['charset'])) { $logPara['time_ms'] = $end - $start; Bd_Log::trace('Connect to Mysql successfully', 0, $logPara); $lastDb[$clusterName] = $db; return $lastDb[$clusterName]; } else { Bd_Log::debug('Set charset failed'); } } } //connect failed self::$_error['errno'] = CONNECT_ERROR; self::$_error['error'] = 'Connect to Mysql failed'; Bd_Log::warning(self::$_error['error'], self::$_error['errno'], $logPara); self::_recordFailedHost($index); } return false; }