Commit 67a1e172 by Qiang Xue

WIP

parent 98d3a8c0
...@@ -282,6 +282,32 @@ class Connection extends Component ...@@ -282,6 +282,32 @@ class Connection extends Component
*/ */
public $enableSavepoint = true; public $enableSavepoint = true;
/** /**
* @var boolean whether to enable read/write splitting by using [[slaves]] to read data.
*/
public $enableSlave = true;
/**
* @var array list of slave connection configurations. When [[enableSlave]] is true, one of these slave
* configurations will be used to create a DB connection to perform read queries.
* @see enableSlave
*/
public $slaves = [];
/**
* @var integer the timeout in seconds for determining whether a slave is dead or not
* @see enableSlave
*/
public $slaveTimeout = 10;
/**
* @var Cache|string the cache object or the ID of the cache application component that is used to store
* the health status of the slaves.
* @see enableSlave
*/
public $slaveCache = 'cache';
/**
* @var integer the retry interval in seconds for dead slaves.
*/
public $slaveRetryInterval = 600;
/**
* @var Transaction the currently active transaction * @var Transaction the currently active transaction
*/ */
private $_transaction; private $_transaction;
...@@ -293,6 +319,11 @@ class Connection extends Component ...@@ -293,6 +319,11 @@ class Connection extends Component
* @var string driver name * @var string driver name
*/ */
private $_driverName; private $_driverName;
/**
* @var Connection the currently active slave
*/
private $_slave = false;
/** /**
* Returns a value indicating whether the DB connection is established. * Returns a value indicating whether the DB connection is established.
...@@ -366,6 +397,11 @@ class Connection extends Component ...@@ -366,6 +397,11 @@ class Connection extends Component
$this->_schema = null; $this->_schema = null;
$this->_transaction = null; $this->_transaction = null;
} }
if ($this->_slave) {
$this->_slave->close();
$this->_slave = null;
}
} }
/** /**
...@@ -623,4 +659,71 @@ class Connection extends Component ...@@ -623,4 +659,71 @@ class Connection extends Component
{ {
$this->_driverName = strtolower($driverName); $this->_driverName = strtolower($driverName);
} }
/**
* Returns the currently active slave.
* If this method is called the first time, it will try to open a slave connection when [[enableSlave]] is true.
* @return Connection the currently active slave. Null is returned if there is slave available.
*/
public function getSlave()
{
if (!$this->enableSlave) {
return null;
}
if ($this->_slave !== false) {
return $this->_slave;
} else {
return $this->_slave = $this->openSlave($this->slaves);
}
}
/**
* Selects a slave and opens the connection.
* @param array $slaves the list of candidate slave configurations
* @return Connection the opened slave connection, or null if no slave is available
* @throws InvalidConfigException if a slave configuration does not have "dsn" setting
*/
protected function openSlave($slaves)
{
if (empty($slaves)) {
return null;
}
shuffle($slaves);
$cache = is_string($this->slaveCache) ? Yii::$app->get($this->slaveCache, false) : $this->slaveCache;
foreach ($slaves as $config) {
if (empty($config['dsn'])) {
throw new InvalidConfigException('One of the slave connections has an empty "dsn".');
}
$key = [__METHOD__, $config['dsn']];
if ($cache instanceof Cache && $cache->get($key)) {
// should not try this dead slave now
continue;
}
if (!isset($config['class'])) {
$config['class'] = get_class($this);
}
/* @var $slave Connection */
$slave = Yii::createObject($config);
if (!isset($slave->attributes[PDO::ATTR_TIMEOUT])) {
$slave->attributes[PDO::ATTR_TIMEOUT] = $this->slaveTimeout;
}
try {
$slave->open();
return $slave;
} catch (\Exception $e) {
Yii::warning("Slave ({$config['dsn']}) not available: " . $e->getMessage(), __METHOD__);
if ($cache instanceof Cache) {
$cache->set($key, 1, $this->slaveRetryInterval);
}
}
}
return null;
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment