* standardised file headers
[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 function __construct( $parent );
19
20 /**
21 * Perform pre-connection load ratio adjustment.
22 * @param $loads Array
23 * @param $group String: the selected query group
24 * @param $wiki String
25 */
26 function scaleLoads( &$loads, $group = false, $wiki = false );
27
28 /**
29 * Perform post-connection backoff.
30 *
31 * If the connection is in overload, this should return a backoff factor
32 * which will be used to control polling time. The number of threads
33 * connected is a good measure.
34 *
35 * If there is no overload, zero can be returned.
36 *
37 * A threshold thread count is given, the concrete class may compare this
38 * to the running thread count. The threshold may be false, which indicates
39 * that the sysadmin has not configured this feature.
40 *
41 * @param $conn DatabaseBase
42 * @param $threshold Float
43 */
44 function postConnectionBackoff( $conn, $threshold );
45
46 /**
47 * Return an estimate of replication lag for each server
48 */
49 function getLagTimes( $serverIndexes, $wiki );
50 }
51
52
53 /**
54 * Basic MySQL load monitor with no external dependencies
55 * Uses memcached to cache the replication lag for a short time
56 *
57 * @ingroup Database
58 */
59 class LoadMonitor_MySQL implements LoadMonitor {
60 var $parent; // LoadBalancer
61
62 function __construct( $parent ) {
63 $this->parent = $parent;
64 }
65
66 function scaleLoads( &$loads, $group = false, $wiki = false ) {
67 }
68
69 function getLagTimes( $serverIndexes, $wiki ) {
70 wfProfileIn( __METHOD__ );
71 $expiry = 5;
72 $requestRate = 10;
73
74 global $wgMemc;
75 if ( empty( $wgMemc ) )
76 $wgMemc = wfGetMainCache();
77
78 $masterName = $this->parent->getServerName( 0 );
79 $memcKey = wfMemcKey( 'lag_times', $masterName );
80 $times = $wgMemc->get( $memcKey );
81 if ( $times ) {
82 # Randomly recache with probability rising over $expiry
83 $elapsed = time() - $times['timestamp'];
84 $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
85 if ( mt_rand( 0, $chance ) != 0 ) {
86 unset( $times['timestamp'] );
87 wfProfileOut( __METHOD__ );
88 return $times;
89 }
90 wfIncrStats( 'lag_cache_miss_expired' );
91 } else {
92 wfIncrStats( 'lag_cache_miss_absent' );
93 }
94
95 # Cache key missing or expired
96
97 $times = array();
98 foreach ( $serverIndexes as $i ) {
99 if ($i == 0) { # Master
100 $times[$i] = 0;
101 } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
102 $times[$i] = $conn->getLag();
103 } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
104 $times[$i] = $conn->getLag();
105 }
106 }
107
108 # Add a timestamp key so we know when it was cached
109 $times['timestamp'] = time();
110 $wgMemc->set( $memcKey, $times, $expiry );
111
112 # But don't give the timestamp to the caller
113 unset($times['timestamp']);
114 $lagTimes = $times;
115
116 wfProfileOut( __METHOD__ );
117 return $lagTimes;
118 }
119
120 function postConnectionBackoff( $conn, $threshold ) {
121 if ( !$threshold ) {
122 return 0;
123 }
124 $status = $conn->getStatus("Thread%");
125 if ( $status['Threads_running'] > $threshold ) {
126 return $status['Threads_connected'];
127 } else {
128 return 0;
129 }
130 }
131 }
132