Kill mysql4 specific code from DatabaseMysql
[lhc/web/wiklou.git] / includes / db / LoadMonitor.php
1 <?php
2 /**
3 * Database load monitoring
4 *
5 * @file
6 * @ingroup Database
7 */
8
9 /**
10 * An interface for database load monitoring
11 *
12 * @ingroup Database
13 */
14 interface LoadMonitor {
15 /**
16 * Construct a new LoadMonitor with a given LoadBalancer parent
17 *
18 * @param LoadBalancer $parent
19 */
20 function __construct( $parent );
21
22 /**
23 * Perform pre-connection load ratio adjustment.
24 * @param $loads array
25 * @param $group String: the selected query group
26 * @param $wiki String
27 */
28 function scaleLoads( &$loads, $group = false, $wiki = false );
29
30 /**
31 * Perform post-connection backoff.
32 *
33 * If the connection is in overload, this should return a backoff factor
34 * which will be used to control polling time. The number of threads
35 * connected is a good measure.
36 *
37 * If there is no overload, zero can be returned.
38 *
39 * A threshold thread count is given, the concrete class may compare this
40 * to the running thread count. The threshold may be false, which indicates
41 * that the sysadmin has not configured this feature.
42 *
43 * @param $conn DatabaseBase
44 * @param $threshold Float
45 */
46 function postConnectionBackoff( $conn, $threshold );
47
48 /**
49 * Return an estimate of replication lag for each server
50 *
51 * @param $serverIndexes
52 * @param $wiki
53 *
54 * @return array
55 */
56 function getLagTimes( $serverIndexes, $wiki );
57 }
58
59 class LoadMonitor_Null implements LoadMonitor {
60 function __construct( $parent ) {
61 }
62
63 function scaleLoads( &$loads, $group = false, $wiki = false ) {
64 }
65
66 function postConnectionBackoff( $conn, $threshold ) {
67 }
68
69 function getLagTimes( $serverIndexes, $wiki ) {
70 return array_fill_keys( $serverIndexes, 0 );
71 }
72 }
73
74
75 /**
76 * Basic MySQL load monitor with no external dependencies
77 * Uses memcached to cache the replication lag for a short time
78 *
79 * @ingroup Database
80 */
81 class LoadMonitor_MySQL implements LoadMonitor {
82
83 /**
84 * @var LoadBalancer
85 */
86 var $parent;
87
88 /**
89 * @param LoadBalancer $parent
90 */
91 function __construct( $parent ) {
92 $this->parent = $parent;
93 }
94
95 /**
96 * @param $loads
97 * @param $group bool
98 * @param $wiki bool
99 */
100 function scaleLoads( &$loads, $group = false, $wiki = false ) {
101 }
102
103 /**
104 * @param $serverIndexes
105 * @param $wiki
106 * @return array
107 */
108 function getLagTimes( $serverIndexes, $wiki ) {
109 if ( count( $serverIndexes ) == 1 && reset( $serverIndexes ) == 0 ) {
110 // Single server only, just return zero without caching
111 return array( 0 => 0 );
112 }
113
114 wfProfileIn( __METHOD__ );
115 $expiry = 5;
116 $requestRate = 10;
117
118 global $wgMemc;
119 if ( empty( $wgMemc ) )
120 $wgMemc = wfGetMainCache();
121
122 $masterName = $this->parent->getServerName( 0 );
123 $memcKey = wfMemcKey( 'lag_times', $masterName );
124 $times = $wgMemc->get( $memcKey );
125 if ( $times ) {
126 # Randomly recache with probability rising over $expiry
127 $elapsed = time() - $times['timestamp'];
128 $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
129 if ( mt_rand( 0, $chance ) != 0 ) {
130 unset( $times['timestamp'] );
131 wfProfileOut( __METHOD__ );
132 return $times;
133 }
134 wfIncrStats( 'lag_cache_miss_expired' );
135 } else {
136 wfIncrStats( 'lag_cache_miss_absent' );
137 }
138
139 # Cache key missing or expired
140
141 $times = array();
142 foreach ( $serverIndexes as $i ) {
143 if ($i == 0) { # Master
144 $times[$i] = 0;
145 } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
146 $times[$i] = $conn->getLag();
147 } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
148 $times[$i] = $conn->getLag();
149 }
150 }
151
152 # Add a timestamp key so we know when it was cached
153 $times['timestamp'] = time();
154 $wgMemc->set( $memcKey, $times, $expiry );
155
156 # But don't give the timestamp to the caller
157 unset($times['timestamp']);
158 $lagTimes = $times;
159
160 wfProfileOut( __METHOD__ );
161 return $lagTimes;
162 }
163
164 /**
165 * @param $conn DatabaseBase
166 * @param $threshold
167 * @return int
168 */
169 function postConnectionBackoff( $conn, $threshold ) {
170 if ( !$threshold ) {
171 return 0;
172 }
173 $status = $conn->getMysqlStatus("Thread%");
174 if ( $status['Threads_running'] > $threshold ) {
175 $server = $conn->getProperty( 'mServer' );
176 wfLogDBError( "LB backoff from $server - Threads_running = {$status['Threads_running']}\n" );
177 return $status['Threads_connected'];
178 } else {
179 return 0;
180 }
181 }
182 }
183