Esempio n. 1
0
 /**
  * Connects the socket by iterating through all the servers in the pool
  * and trying to find one that:
  * 1. is not marked down after consecutive failures
  * 2. can really be connected to
  *
  * @return bool  false: any IP in the pool failed to connect before returning
  *               true: no failures
  */
 public function open()
 {
     // Check if we want order randomization
     if ($this->randomize_) {
         // warning: don't use shuffle here because it leads to uneven
         // load distribution
         $n = count($this->servers_);
         $s = $this->servers_;
         for ($i = 1; $i < $n; $i++) {
             $j = mt_rand(0, $i);
             $tmp = $s[$i];
             $s[$i] = $s[$j];
             $s[$j] = $tmp;
         }
         $this->servers_ = $s;
     }
     // Count servers to identify the "last" one
     $numServers = count($this->servers_);
     $has_conn_errors = false;
     $fail_reason = array();
     // reasons of conn failures
     for ($i = 0; $i < $numServers; ++$i) {
         // host port is stored as an array
         list($host, $port) = $this->servers_[$i];
         $failtimeKey = TSocketPool::getAPCFailtimeKey($host, $port);
         // Cache miss? Assume it's OK
         $lastFailtime = $this->apcFetch($failtimeKey);
         $this->apcLog("TSocketPool: host {$host}:{$port} last fail time: " . $lastFailtime);
         if ($lastFailtime === FALSE) {
             $lastFailtime = 0;
         }
         $retryIntervalPassed = FALSE;
         // Cache hit...make sure enough the retry interval has elapsed
         if ($lastFailtime > 0) {
             $elapsed = time() - $lastFailtime;
             if ($elapsed > $this->retryInterval_) {
                 $retryIntervalPassed = TRUE;
                 if ($this->debug_) {
                     call_user_func($this->debugHandler_, 'TSocketPool: retryInterval ' . '(' . $this->retryInterval_ . ') ' . 'has passed for host ' . $host . ':' . $port);
                 }
             }
         }
         // Only connect if not in the middle of a fail interval, OR if this
         // is the LAST server we are trying, just hammer away on it
         $isLastServer = FALSE;
         if ($this->alwaysTryLast_) {
             $isLastServer = $i == $numServers - 1;
         }
         if ($lastFailtime === 0 || $isLastServer || $lastFailtime > 0 && $retryIntervalPassed) {
             // Set underlying TSocket params to this one
             // fsockopen requires IPv6 addresses be bracet enclosed
             $this->host_ = $host;
             $this->port_ = $port;
             // Try up to numRetries_ connections per server
             for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) {
                 try {
                     // Use the underlying TSocket open function
                     parent::open();
                     // Only clear the failure counts if required to do so
                     if ($lastFailtime > 0) {
                         $this->apcStore($failtimeKey, 0);
                     }
                     // Successful connection, return now
                     return !$has_conn_errors;
                 } catch (TException $tx) {
                     // Connection failed
                     // keep the reason for the last try
                     $errstr = $this->getErrStr();
                     $errno = $this->getErrNo();
                     if ($errstr !== null || $errno !== null) {
                         $fail_reason[$i] = '(' . $errstr . '[' . $errno . '])';
                     } else {
                         $fail_reason[$i] = '(?)';
                     }
                 }
             }
             // For transient errors (like Resource temporarily unavailable),
             // we might want not to cache the failure.
             if ($this->alwaysRetryForTransientFailure_ && $this->isTransientConnectFailure($this->getErrNo())) {
                 continue;
             }
             $has_conn_errors = $this->recordFailure($host, $port, $this->maxConsecutiveFailures_, $this->retryInterval_, $this->debug_ ? $this->debugHandler_ : null);
         } else {
             $fail_reason[$i] = '(cached-down)';
         }
     }
     // Holy shit we failed them all. The system is totally ill!
     $error = 'TSocketPool: All hosts in pool are down. ';
     $hosts = array();
     foreach ($this->servers_ as $i => $server) {
         // array(host, port) (reasons, if exist)
         list($host, $port) = $server;
         if (ip_is_valid($host)) {
             $host = IPAddress($host)->forURL();
         }
         $h = $host . ':' . $port;
         if (isset($fail_reason[$i])) {
             $h .= $fail_reason[$i];
         }
         $hosts[] = $h;
     }
     $hostlist = implode(',', $hosts);
     $error .= '(' . $hostlist . ')';
     if ($this->debug_) {
         call_user_func($this->debugHandler_, $error);
     }
     throw new TTransportException($error);
 }
Esempio n. 2
0
 public function open()
 {
     if (\hacklib_cast_as_boolean($this->randomize_)) {
         $n = count($this->servers_);
         $s = $this->servers_;
         for ($i = 1; $i < $n; $i++) {
             $j = mt_rand(0, $i);
             $tmp = $s[$i];
             $s[$i] = $s[$j];
             $s[$j] = $tmp;
         }
         $this->servers_ = $s;
     }
     $numServers = count($this->servers_);
     $has_conn_errors = false;
     $fail_reason = array();
     for ($i = 0; $i < $numServers; ++$i) {
         list($host, $port) = $this->servers_[$i];
         $failtimeKey = TSocketPool::getAPCFailtimeKey($host, $port);
         $lastFailtime = (int) $this->apcFetch($failtimeKey);
         $this->apcLog("TSocketPool: host {$host}:{$port} last fail time: " . $lastFailtime);
         $retryIntervalPassed = false;
         if ($lastFailtime > 0) {
             $elapsed = time() - $lastFailtime;
             if ($elapsed > $this->retryInterval_) {
                 $retryIntervalPassed = true;
                 if (\hacklib_cast_as_boolean($this->debug_) && $this->debugHandler_ !== null) {
                     $dh = $this->debugHandler_;
                     $dh('TSocketPool: retryInterval ' . '(' . $this->retryInterval_ . ') ' . 'has passed for host ' . $host . ':' . $port);
                 }
             }
         }
         $isLastServer = false;
         if (\hacklib_cast_as_boolean($this->alwaysTryLast_)) {
             $isLastServer = \hacklib_equals($i, $numServers - 1);
         }
         if ($lastFailtime === 0 || \hacklib_cast_as_boolean($isLastServer) || $lastFailtime > 0 && \hacklib_cast_as_boolean($retryIntervalPassed)) {
             $this->host_ = $host;
             $this->port_ = $port;
             for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) {
                 try {
                     parent::open();
                     if ($lastFailtime > 0) {
                         $this->apcStore($failtimeKey, 0);
                     }
                     return;
                 } catch (TException $tx) {
                     $errstr = $this->getErrStr();
                     $errno = $this->getErrNo();
                     if ($errstr !== null || $errno !== null) {
                         $fail_reason[$i] = '(' . $errstr . '[' . $errno . '])';
                     } else {
                         $fail_reason[$i] = '(?)';
                     }
                 }
             }
             if (\hacklib_cast_as_boolean($this->alwaysRetryForTransientFailure_) && \hacklib_cast_as_boolean($this->isTransientConnectFailure($this->getErrNo()))) {
                 continue;
             }
             $dh = \hacklib_cast_as_boolean($this->debug_) ? $this->debugHandler_ : null;
             $has_conn_errors = $this->recordFailure($host, $port, $this->maxConsecutiveFailures_, $this->retryInterval_, $dh);
         } else {
             $fail_reason[$i] = '(cached-down)';
         }
     }
     $error = 'TSocketPool: All hosts in pool are down. ';
     $hosts = array();
     foreach ($this->servers_ as $i => $server) {
         list($host, $port) = $server;
         $h = $host . ':' . $port;
         if (\hacklib_cast_as_boolean(array_key_exists($i, $fail_reason))) {
             $h .= (string) $fail_reason[$i];
         }
         $hosts[] = $h;
     }
     $hostlist = implode(',', $hosts);
     $error .= '(' . $hostlist . ')';
     if (\hacklib_cast_as_boolean($this->debug_) && $this->debugHandler_ !== null) {
         $dh = $this->debugHandler_;
         $dh($error);
     }
     throw new TTransportException($error);
 }