-
Notifications
You must be signed in to change notification settings - Fork 0
/
EDbConnection.php
171 lines (149 loc) · 5.26 KB
/
EDbConnection.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<?php
/**
* EDbConnection class file
*
* @author 5missions.de <[email protected]>
* @license GPLv2
* @version 1.0
* @link https://github.com/5missions/yii-EDbConnection
*/
/**
* Extends Yii's CDbConnection and provides connection pooling in
* MySQL Multi Master Setups
*
* @category Base
* @package system.db
*/
class EDbConnection extends CDbConnection
{
/**
* @var int $timeout set default 3 seconds connection timeout
*/
public $timeout =3 ;
/**
* Default, if the connected server caused error, then mark this server as
* dead for 10 minutes. After 10 minutes, mark dead cache will automatically expire.
* @todo make this configurable at main.php
*
* @var int $markDeadSeconds
*/
public $markDeadSeconds = 600;
/**
* use cache as global flags storage
* @var string $cacheID
*/
public $cacheID='cache';
/**
* @var array $connectionArray.DSN database connection config array.
* The main server must be set as connection string and at first position of
* the connectionArray
* @example
* 'db'=>array(
* 'connectionString'=>'mysql://...',
* 'connectionArray'=>array() {
* 'mysql://...',
* 'mysql://...''
* )
* )
**/
public $connectionArray = array();
/**
* Overwrites CDbConnection::setActive
* @param string $value Value
*
* @return void
*/
public function setActive($value)
{
Yii::trace('Using custom setActive()','system.db.EDbConnection');
if ($value != $this->getActive()) {
if ($value) {
// if main.php was not altered we will catch that
if (empty($this->connectionArray)
&& isset($this->connectionString)
&& !empty($this->connectionString)
) {
Yii::trace("Configuration was not altered!",'system.db.EDbConnection');
$this->connectionArray[] = $this->connectionString;
}
foreach ($this->connectionArray as $connectionString) {
if (!$this->_isDeadServer($connectionString)) {
Yii::trace(
"Try to connect to: $connectionString",
'system.db.NDbConnection'
);
//PDO::ATTR_TIMEOUT must set before pdo instance create
$this->connectionString = $connectionString;
try {
$this->setAttribute(PDO::ATTR_TIMEOUT,$this->timeout);
$this->open();
// If we have been successful stop trying
Yii::trace(
"Connection successfully established: $connectionString",
'system.db.EDbConnection'
);
break;
} catch (Exception $e) {
Yii::trace(
"Connection failed: $this->connectionString",
'system.db.EDbConnection'
);
$this->_markDeadServer($this->connectionString);
Yii::log($e->getMessage(),CLogger::LEVEL_ERROR,'exception.EDbException');
}
}
}
} else {
$this->close();
}
}
// If none of the MySQL server have responded
if (!$this->getActive()) {
$this->_deleteAllServerFromCache($this->connectionArray);
echo "There are no MySQL Server available!\n<br>";
throw new CDbException('CDbConnection failed to open the DB connection.',1,'none');
}
}
/**
* Detect is this server config already marked as dead for a period time in
* cache.
*
* @param string $connectionString The PDO Connection String
* @return bool
*/
private function _isDeadServer($connectionString)
{
$cache = Yii::app()->{$this->cacheID};
if ($cache && $cache->get('DeadServer::'.$connectionString) == 1) {
return true;
}
return false;
}
/**
* Mark this server config as dead.
* @param string $connectionString The PDO Connection String
* @return void
*/
private function _markDeadServer($connectionString)
{
$cache = Yii::app()->{$this->cacheID};
if ($cache) {
$cache->set('DeadServer::'.$connectionString, 1, $this->markDeadSeconds);
}
}
/**
* Delete all server from cache in case that no server is responding
* to force checks after server came back online
* @param array $connectionsStrings Array with PDO Connection Strings
* @return void
*/
private function _deleteAllServerFromCache($connectionStrings)
{
$cache = Yii::app()->{$this->cacheID};
if ($cache) {
foreach ($connectionStrings as $connectionString) {
$cache->delete('DeadServer::'.$connectionString);
}
}
}
}