public function testAllInOne()
 {
     // ²âÊÔ´òÓ¡µ½ÆÁÄ»
     BigpipeLog::debug('[%s:%u][%s][debug]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::trace('[%s:%u][%s][trace]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::notice('[%s:%u][%s][notice]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::monitor('[%s:%u][%s][monitor]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::warning('[%s:%u][%s][warning]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::fatal('[%s:%u][%s][fatal]', __FILE__, __LINE__, __FUNCTION__);
     // ²âÊÔ²»Êä³ö´òÓ¡ÐÅÏ¢log configure
     $conf = new BigpipeLogConf();
     $conf->severity = BigpipeLogSeverity::FATAL;
     $conf->disable_ostream = true;
     $fatal_log = sprintf('[%s:%u][%s][fatal message]', __FILE__, __LINE__, __FUNCTION__);
     $warning_Log = sprintf('[%s:%u][%s][warning]', __FILE__, __LINE__, __FUNCTION__);
     $this->assertTrue(BigpipeLog::init($conf));
     BigpipeLog::fatal('%s', $fatal_log);
     $msg = BigpipeLog::get_last_error_message();
     BigpipeLog::warning('%s', $warning_Log);
     $this->assertEquals($msg, BigpipeLog::get_last_error_message());
     $new_fatal_log = sprintf('[%s:%u][%s][fatal new message]', __FILE__, __LINE__, __FUNCTION__);
     $this->assertTrue($msg == BigpipeLog::get_last_error_message());
     // ²âÊÔclose
     BigpipeLog::close();
 }
 /**
  * 从传入的configure array读取剩余配置
  * @param array $conf_arr: 含meta agent配置的array
  * @return true on success or false on failure
  */
 private function _load_other($conf_arr)
 {
     try {
         $obj = new ReflectionClass($this);
         foreach ($conf_arr as $key => $val) {
             if (true === is_array($val)) {
                 BigpipeLog::debug('[%s:%u][%s][skip configure node][name:%s]', __FILE__, __LINE__, __FUNCTION__, $key);
                 continue;
             }
             if (false === $obj->hasProperty($key)) {
                 continue;
             }
             BigpipeLog::debug('[%s:%u][%s][an element is configured][key:%s][val:%s]', __FILE__, __LINE__, __FUNCTION__, $key, $val);
             $fld = $obj->getProperty($key);
             $fld->setValue($this, $val);
         }
     } catch (Exception $e) {
         BigpipeLog::warning('[%s:%u][%s][fail to load configure][error message:%s]', __FILE__, __LINE__, __FUNCTION__, $e->getMessage());
         return false;
     }
     // todo
     // 根据checksum level修改check frame标志现在在publish和subscirbe中
     // 以后应该移到这里
     return true;
 }
 /**
  * 更新meta信息, 记录重试次数
  * @return boolean
  */
 private function _failover()
 {
     if ($this->_fo_count >= $this->_max_fo_cnt) {
         // 重置failover
         BigpipeLog::fatal("[_failover][can not do more][max_cnt:%d]", $this->_max_fo_cnt);
         $this->_fo_sleep_time = 0;
         $this->_fo_count = 0;
         return false;
     }
     if (0 == $this->_fo_sleep_time) {
         // php中只有微秒级的usleep和秒级的sleep
         // 目前只有当start时才会进入这个分支。
         // 这时我们会跳过failover
         $this->_fo_sleep_time = BigpipeCommonDefine::INIT_FO_SLEEP_TIME * 1000;
     } else {
         usleep($this->_fo_sleep_time);
     }
     // usleep($this->_fo_sleep_time);
     $this->_fo_count++;
     $this->_fo_sleep_time *= 2;
     // increase failover sleep time
     if ($this->_fo_sleep_time > BigpipeCommonDefine::MAX_FO_SLEEP_TIME) {
         // failover sleep time不能无限制增长
         $this->_fo_sleep_time = BigpipeCommonDefine::MAX_FO_SLEEP_TIME;
     }
     // 通过meta跟新stripe
     $broker = $this->_update_meta();
     if (false === $broker) {
         BigpipeLog::fatal("[_failover][can not update meta from meta agent]");
         return false;
     }
     // 连接broker
     $pub_dest = array("socket_address" => $broker['ip'], "socket_port" => $broker['port'], "socket_timeout" => $this->_conn_timeo);
     $this->_stomp_adapter->set_destination($pub_dest);
     $this->_stomp_adapter->role = BStompRoleType::PUBLISHER;
     $this->_stomp_adapter->topic_name = $broker['stripe'];
     $this->_stomp_adapter->session_id = $this->_session_id;
     // 发布时session不变
     if ($this->_stomp_adapter->connect()) {
         BigpipeLog::debug("[Success][connected on broker][ip:%s][port:%u]", $broker['ip'], $broker['port']);
         BigpipeLog::debug('[session message id][%u]', $this->_stomp_adapter->session_message_id);
         $this->_broker = $broker;
         return true;
     }
     return false;
     // 连接失败
 }
 /**
  * Create a connection between server and php client<p>
  * Or close the existing connection and re-connect it.
  * @param no parameter
  * @return true on success or false on failure.
  */
 public function create_connection()
 {
     if ($this->is_connected()) {
         $this->close();
         // 防止重复创建connection
     }
     $agents = $this->_destinations;
     $num = count($agents);
     if (0 == $num) {
         BigpipeLog::warning("[no destination]");
         return false;
     }
     $try = $this->_max_try_time;
     $curr_agent = rand() % $num;
     $idx = $curr_agent;
     // 从curr_agent开始尝试连接meta agent
     while ($try-- > 0) {
         $agent = $agents[$idx];
         // $stub_sock用于测试时传入mocked c_socket
         $socket = true === isset($this->unittest) ? $this->stub_sock : new c_socket();
         $agent['socket_timeout'] = $this->_conn_timeo;
         // c_socket内部使用socket_timeout作为read/write timeout
         $socket->set_vars_from_array($agent);
         //<<< 调试信息
         BigpipeLog::debug('[connect to][%s:%u]', $agent['socket_address'], $agent['socket_port']);
         // 连接agent
         if ($socket->connect($this->_conn_timeo)) {
             $this->_socket = $socket;
             $this->_target = $agent;
             // 记录连接对象
             break;
         } else {
             // 换地址重试
             if (!array_key_exists($idx + 1, $agents)) {
                 // next idx will be out of range
                 // reset $idx and try from the first agent
                 $idx = 0;
             } else {
                 $idx++;
             }
         }
         // end of connect
     }
     // end of try
     return $this->is_connected();
 }
 /**
  * 更新meta信息, 记录重试次数
  * @return boolean
  */
 private function _failover()
 {
     // failover时, 订阅、发布状态无效,重置状态
     if (true == $this->_is_subscribed) {
         $this->_unsubscribe();
         // 先尝试取消订阅, 但是不用考虑错误 (因为failover中有错误是常态)
         $this->_is_subscribed = false;
     }
     if ($this->_fo_count > $this->_max_fo_cnt) {
         // 重置failover
         BigpipeLog::fatal("[%s:%u][%s][can not do more]", __FILE__, __LINE__, __FUNCTION__);
         $this->_fo_sleep_time = 0;
         $this->_fo_count = 0;
         return false;
     }
     if (0 == $this->_fo_sleep_time) {
         // 第一次flush subscribe时,我们往往不希望等待,
         // 因此这时跳过sleep过程
         // php中只有微秒级的usleep和秒级的sleep
         $this->_fo_sleep_time = BigpipeCommonDefine::INIT_FO_SLEEP_TIME * 1000;
     } else {
         usleep($this->_fo_sleep_time);
     }
     $this->_fo_count++;
     $this->_fo_sleep_time *= 2;
     // increase failover sleep time
     if ($this->_fo_sleep_time > BigpipeCommonDefine::MAX_FO_SLEEP_TIME) {
         // failover sleep time不能无限制增长
         $this->_fo_sleep_time = BigpipeCommonDefine::MAX_FO_SLEEP_TIME;
     }
     // 通过meta跟新stripe
     if (false === $this->_update_meta()) {
         BigpipeLog::fatal("[%s:%u][%s][can not update meta from meta agent]", __FILE__, __LINE__, __FUNCTION__);
         return false;
     }
     // 随机选择并连接一个broker
     $is_ok = false;
     do {
         $broker = $this->_random_select_broker();
         if (false === $broker) {
             // 无新broker可选, failover失败
             BigpipeLog::fatal("[%s:%u][%s][no broker to subcribe]", __FILE__, __LINE__, __FUNCTION__);
             break;
         }
         // try to connect to broker
         $sub_dest = array("socket_address" => $broker->ip, "socket_port" => $broker->port, "socket_timeout" => $this->_conn_timeo);
         $this->_stomp_adapter->set_destination($sub_dest);
         $this->_stomp_adapter->role = BStompRoleType::SUBSCRIBER;
         $this->_stomp_adapter->topic_name = $this->_stripe['stripe_name'];
         $this->_stomp_adapter->session_id = BigpipeUtilities::get_pipelet_name($this->_pipe_name, $this->_pipelet_id) . '_' . BigpipeUtilities::get_uid();
         if ($this->_stomp_adapter->connect()) {
             BigpipeLog::debug("[%s:%u][%s][Success][connected on broker][ip:%s][port:%u]", __FILE__, __LINE__, __FUNCTION__, $broker->ip, $broker->port);
             BigpipeLog::debug('[%s:%u][%s][session message id][smid:%s]', __FILE__, __LINE__, __FUNCTION__, $this->_stomp_adapter->session_message_id);
             $is_ok = true;
             break;
             // 跳出连接
         }
     } while (true);
     return $is_ok;
 }