* fixed tableName handling for internal purposes (bug if using sharedDB as i need...
[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 function getLagTimes( $serverIndexes, $wiki );
52 }
53
54
55 /**
56 * Basic MySQL load monitor with no external dependencies
57 * Uses memcached to cache the replication lag for a short time
58 *
59 * @ingroup Database
60 */
61 class LoadMonitor_MySQL implements LoadMonitor {
62
63 /**
64 * @var LoadBalancer
65 */
66 var $parent;
67
68 /**
69 * @param LoadBalancer $parent
70 */
71 function __construct( $parent ) {
72 $this->parent = $parent;
73 }
74
75 function scaleLoads( &$loads, $group = false, $wiki = false ) {
76 }
77
78 function getLagTimes( $serverIndexes, $wiki ) {
79 wfProfileIn( __METHOD__ );
80 $expiry = 5;
81 $requestRate = 10;
82
83 global $wgMemc;
84 if ( empty( $wgMemc ) )
85 $wgMemc = wfGetMainCache();
86
87 $masterName = $this->parent->getServerName( 0 );
88 $memcKey = wfMemcKey( 'lag_times', $masterName );
89 $times = $wgMemc->get( $memcKey );
90 if ( $times ) {
91 # Randomly recache with probability rising over $expiry
92 $elapsed = time() - $times['timestamp'];
93 $chance = max( 0, ( $expiry - $elapsed ) * $requestRate );
94 if ( mt_rand( 0, $chance ) != 0 ) {
95 unset( $times['timestamp'] );
96 wfProfileOut( __METHOD__ );
97 return $times;
98 }
99 wfIncrStats( 'lag_cache_miss_expired' );
100 } else {
101 wfIncrStats( 'lag_cache_miss_absent' );
102 }
103
104 # Cache key missing or expired
105
106 $times = array();
107 foreach ( $serverIndexes as $i ) {
108 if ($i == 0) { # Master
109 $times[$i] = 0;
110 } elseif ( false !== ( $conn = $this->parent->getAnyOpenConnection( $i ) ) ) {
111 $times[$i] = $conn->getLag();
112 } elseif ( false !== ( $conn = $this->parent->openConnection( $i, $wiki ) ) ) {
113 $times[$i] = $conn->getLag();
114 }
115 }
116
117 # Add a timestamp key so we know when it was cached
118 $times['timestamp'] = time();
119 $wgMemc->set( $memcKey, $times, $expiry );
120
121 # But don't give the timestamp to the caller
122 unset($times['timestamp']);
123 $lagTimes = $times;
124
125 wfProfileOut( __METHOD__ );
126 return $lagTimes;
127 }
128
129 /**
130 * @param $conn DatabaseBase
131 * @param $threshold
132 * @return int
133 */
134 function postConnectionBackoff( $conn, $threshold ) {
135 if ( !$threshold ) {
136 return 0;
137 }
138 $status = $conn->getStatus("Thread%");
139 if ( $status['Threads_running'] > $threshold ) {
140 return $status['Threads_connected'];
141 } else {
142 return 0;
143 }
144 }
145 }
146