MongoClient::getNearestHostProtocol PHP Method

getNearestHostProtocol() private method

Get a Protocol for the nearest candidate server matching the given types and read preference. This implements Member Selection as described here: http://docs.mongodb.org/manual/core/read-preference-mechanics/#replica-set-read-preference-behavior-member-selection
private getNearestHostProtocol ( array $allowedServerTypes, array $readPreference ) : Mongofill\Protocol
$allowedServerTypes array
$readPreference array
return Mongofill\Protocol
    private function getNearestHostProtocol(array $allowedServerTypes, array $readPreference)
    {
        $candidates = [];
        $tagsets = isset($readPreference['tagsets']) ? $readPreference['tagsets'] : [[]];
        foreach ($tagsets as $tagset) {
            foreach ($this->replSetStatus['members'] as $key => $member) {
                $tags = isset($this->replSetConf['members'][$key]['tags']) ? $this->replSetConf['members'][$key]['tags'] : [];
                if (in_array($member['stateStr'], $allowedServerTypes) && array_intersect($tagset, $tags) === $tagset) {
                    $candidates[] = $member;
                }
            }
            if ($candidates) {
                break;
            }
        }
        if (!$candidates) {
            $msg = "No " . implode(' or ', $allowedServerTypes) . " servers available";
            if (isset($readPreference['tagsets'])) {
                $msg .= " matching tagsets " . json_encode($readPreference['tagsets']);
            }
            throw new MongoConnectionException($msg);
        }
        // Connect and ping all candidate servers
        $min_ping = INF;
        foreach ($candidates as $member) {
            $host_key = $member['name'];
            list($host, $port) = explode(':', $host_key);
            $this->connectToHost($host, $port);
            if (!isset($this->hosts[$host_key]['ping'])) {
                $this->pingHost($host, $port);
            }
            if ($this->hosts[$host_key]['ping'] < $min_ping) {
                $min_ping = $this->hosts[$host_key]['ping'];
                $min_ping_host_key = $host_key;
            }
        }
        // If we have a NEAREST read preference, always return the host with the least latency
        if ($readPreference['type'] === static::RP_NEAREST && isset($min_ping_host_key)) {
            return $this->protocols[$min_ping_host_key];
        }
        // Otherwise:
        // Filter candidates to only those within the "nearest group" (default 15ms)
        $candidates = array_values(array_filter($candidates, function ($member) use($min_ping) {
            $host_key = $member['name'];
            return $this->hosts[$host_key]['ping'] - $min_ping < self::RP_DEFAULT_ACCEPTABLE_LATENCY_MS;
        }));
        // Pick a random host from remaining candidates
        $the_chosen_one = $candidates[mt_rand(0, count($candidates) - 1)];
        return $this->protocols[$the_chosen_one['name']];
    }