Your IP : 3.147.44.195
<?php
/**
* Bitrix Framework
* @package bitrix
* @subpackage main
* @copyright 2001-2012 Bitrix
*/
namespace Bitrix\Main\Data;
use Bitrix\Main;
use Bitrix\Main\Config;
/**
* Connection pool is a connections holder
*/
class ConnectionPool
{
/**
* @var Connection[]
*/
protected $connections = [];
protected $connectionParameters = [];
protected $slavePossible = true;
protected $ignoreDml = 0;
protected $masterOnly = 0;
protected $slaveConnection = null;
const DEFAULT_CONNECTION_NAME = "default";
/**
* Creates connection pool object
*/
public function __construct()
{
}
/**
* @param string $name
* @param array $parameters
* @return Connection
* @throws Config\ConfigurationException
*/
protected function createConnection($name, $parameters)
{
$className = $parameters['className'];
if (!class_exists($className))
{
throw new Config\ConfigurationException(sprintf(
"Class '%s' for '%s' connection was not found", $className, $name
));
}
$connection = new $className($parameters);
$this->connections[$name] = $connection;
return $connection;
}
/**
* Returns database connection by its name. Creates new connection if necessary.
*
* @param string $name Connection name.
* @return Connection|Main\DB\Connection|null
*/
public function getConnection($name = "")
{
if ($name === "")
{
$name = self::DEFAULT_CONNECTION_NAME;
}
if (!isset($this->connections[$name]))
{
$connParameters = $this->getConnectionParameters($name);
if (!empty($connParameters) && is_array($connParameters))
{
$this->createConnection($name, $connParameters);
}
}
if (isset($this->connections[$name]))
{
return $this->connections[$name];
}
return null;
}
/**
* Searches connection parameters (type, host, db, login and password) by connection name
*
* @param string $name Connection name
* @return array|null
* @throws \Bitrix\Main\ArgumentTypeException
* @throws \Bitrix\Main\ArgumentNullException
*/
protected function getConnectionParameters($name)
{
if (!is_string($name))
{
throw new Main\ArgumentTypeException("name", "string");
}
if ($name === "")
{
throw new Main\ArgumentNullException("name");
}
$params = null;
if (isset($this->connectionParameters[$name]) && !empty($this->connectionParameters[$name]))
{
$params = $this->connectionParameters[$name];
}
else
{
$configParams = Config\Configuration::getValue('connections');
if (isset($configParams[$name]) && !empty($configParams[$name]))
{
$params = $configParams[$name];
}
}
if ($params !== null && $name === static::DEFAULT_CONNECTION_NAME && !isset($params["include_after_connected"]))
{
$params["include_after_connected"] = \Bitrix\Main\Loader::getPersonal("php_interface/after_connect_d7.php");
}
return $params;
}
/**
* Sets named connection paramters.
*
* @param string $name Name of the connection.
* @param array $parameters Parameters values.
* @return void
*/
public function setConnectionParameters($name, $parameters)
{
$this->connectionParameters[$name] = $parameters;
if(isset($this->connections[$name]))
{
unset($this->connections[$name]);
}
}
/**
* Returns a slave connection or null if the query should go to the master.
*
* @param string $sql A SQL string. Only SELECT will go to a slave.
* @return Main\DB\Connection|null
*/
public function getSlaveConnection($sql)
{
if($this->masterOnly > 0)
{
//We requested to process all queries
//by master connection
}
elseif($this->slavePossible)
{
$isSelect = preg_match('/^\s*(select|show)/i', $sql) && !preg_match('/get_lock/i', $sql);
if(!$isSelect && $this->ignoreDml <= 0)
{
$this->slavePossible = false;
}
if($isSelect)
{
if($this->slaveConnection === null)
{
$this->useMasterOnly(true);
$this->slaveConnection = $this->createSlaveConnection();
$this->useMasterOnly(false);
}
if(is_object($this->slaveConnection))
{
return $this->slaveConnection;
}
}
}
return null;
}
/**
* In the master-only mode all queries will go to the master.
*
* @param bool $mode True starts the mode and false ends.
* @return void
*/
public function useMasterOnly($mode)
{
if($mode)
{
$this->masterOnly++;
}
else
{
$this->masterOnly--;
}
}
/**
* In the ignore DML mode a data modification command will not stop next queries going to a slave.
*
* @param bool $mode Ignore subsequent DML or not.
* @return void
*/
public function ignoreDml($mode)
{
if($mode)
{
$this->ignoreDml++;
}
else
{
$this->ignoreDml--;
}
}
/**
* Creates a new slave connection.
*
* @return bool|Main\DB\Connection
*/
protected function createSlaveConnection()
{
if(!Main\Loader::includeModule('cluster'))
{
return false;
}
$found = \CClusterSlave::GetRandomNode();
if($found !== false)
{
$node = \CClusterDBNode::GetByID($found["ID"]);
if(is_array($node) && $node["ACTIVE"] == "Y" && ($node["STATUS"] == "ONLINE" || $node["STATUS"] == "READY"))
{
$parameters = [
'host' => $node["DB_HOST"],
'database' => $node["DB_NAME"],
'login' => $node["DB_LOGIN"],
'password' => $node["DB_PASSWORD"],
];
$connection = $this->cloneConnection(self::DEFAULT_CONNECTION_NAME, "node".$node["ID"], $parameters);
if($connection instanceof Main\DB\Connection)
{
$connection->setNodeId($node["ID"]);
}
return $connection;
}
}
return false;
}
/**
* Creates a new connection based on the supplied one.
*
* @param string $name Copy source.
* @param string $newName Copy target.
* @param array $parameters Parameters to be passed to createConnection method.
* @throws Config\ConfigurationException
* @return Connection
*/
public function cloneConnection($name, $newName, array $parameters=array())
{
$defParameters = $this->getConnectionParameters($name);
if (empty($defParameters) || !is_array($defParameters))
{
throw new Config\ConfigurationException(sprintf("Database connection '%s' is not found", $name));
}
$parameters = array_merge($defParameters, $parameters);
$connection = $this->createConnection($newName, $parameters);
return $connection;
}
/**
* Returns the state of queries balancing (is a slave still can be used).
*
* @return bool
*/
public function isSlavePossible()
{
return $this->slavePossible;
}
/**
* Returns the state of queries balancing (is the master only can be used).
*
* @return bool
*/
public function isMasterOnly()
{
return ($this->masterOnly > 0);
}
/**
* Disconnects all *database* connections.
*/
public function disconnect()
{
foreach ($this->connections as $connection)
{
if ($connection instanceof Main\DB\Connection)
{
$connection->disconnect();
}
}
}
}