Changed the way SQL queries are logged by profiling
[lhc/web/wiklou.git] / includes / LinkCache.php
1 <?
2 # Cache for article titles and ids linked from one source
3
4 # These are used in incrementalSetup()
5 define ('LINKCACHE_GOOD', 0);
6 define ('LINKCACHE_BAD', 1);
7 define ('LINKCACHE_IMAGE', 2);
8
9 class LinkCache {
10
11 /* private */ var $mGoodLinks, $mBadLinks, $mActive;
12 /* private */ var $mImageLinks;
13 /* private */ var $mPreFilled, $mOldGoodLinks, $mOldBadLinks;
14
15 /* private */ function getKey( $title ) {
16 global $wgDBname;
17 return "$wgDBname:lc:title:$title";
18 }
19
20 function LinkCache()
21 {
22 $this->mActive = true;
23 $this->mPreFilled = false;
24 $this->mGoodLinks = array();
25 $this->mBadLinks = array();
26 $this->mImageLinks = array();
27 $this->mOldGoodLinks = array();
28 $this->mOldBadLinks = array();
29 }
30
31 function getGoodLinkID( $title )
32 {
33 if ( array_key_exists( $title, $this->mGoodLinks ) ) {
34 return $this->mGoodLinks[$title];
35 } else {
36 return 0;
37 }
38 }
39
40 function isBadLink( $title )
41 {
42 return in_array( $title, $this->mBadLinks );
43 }
44
45 function addGoodLink( $id, $title )
46 {
47 if ( $this->mActive ) {
48 $this->mGoodLinks[$title] = $id;
49 }
50 }
51
52 function addBadLink( $title )
53 {
54 if ( $this->mActive && ( ! $this->isBadLink( $title ) ) ) {
55 array_push( $this->mBadLinks, $title );
56 }
57 }
58
59 function addImageLink( $title )
60 {
61 if ( $this->mActive ) { $this->mImageLinks[$title] = 1; }
62 }
63
64 function addImageLinkObj( $nt )
65 {
66 if ( $this->mActive ) { $this->mImageLinks[$nt->getDBkey()] = 1; }
67 }
68
69 function clearBadLink( $title )
70 {
71 $index = array_search( $title, $this->mBadLinks );
72 if ( isset( $index ) ) {
73 unset( $this->mBadLinks[$index] );
74 }
75 $this->clearLink( $title );
76 }
77
78 function clearLink( $title )
79 {
80 global $wgMemc, $wgLinkCacheMemcached;
81 if( $wgLinkCacheMemcached )
82 $wgMemc->delete( $this->getKey( $title ) );
83 }
84
85 function suspend() { $this->mActive = false; }
86 function resume() { $this->mActive = true; }
87 function getGoodLinks() { return $this->mGoodLinks; }
88 function getBadLinks() { return $this->mBadLinks; }
89 function getImageLinks() { return $this->mImageLinks; }
90
91 function addLink( $title )
92 {
93 $nt = Title::newFromDBkey( $title );
94 if( $nt ) {
95 return $this->addLinkObj( $nt );
96 } else {
97 return 0;
98 }
99 }
100
101 function addLinkObj( &$nt )
102 {
103 $title = $nt->getPrefixedDBkey();
104 if ( $this->isBadLink( $title ) ) { return 0; }
105 $id = $this->getGoodLinkID( $title );
106 if ( 0 != $id ) { return $id; }
107
108 global $wgMemc;
109 $fname = "LinkCache::addLinkObj";
110 wfProfileIn( $fname );
111
112 $ns = $nt->getNamespace();
113 $t = $nt->getDBkey();
114
115 if ( "" == $title ) {
116 wfProfileOut( $fname );
117 return 0;
118 }
119
120 $id = FALSE;
121 if( $wgLinkCacheMemcached )
122 $id = $wgMemc->get( $key = $this->getKey( $title ) );
123
124 if( $id === FALSE ) {
125 $sql = "SELECT cur_id FROM cur WHERE cur_namespace=" .
126 "{$ns} AND cur_title='" . wfStrencode( $t ) . "'";
127 $res = wfQuery( $sql, DB_READ, "LinkCache::addLink" );
128
129 if ( 0 == wfNumRows( $res ) ) {
130 $id = 0;
131 } else {
132 $s = wfFetchObject( $res );
133 $id = $s->cur_id;
134 }
135 if( $wgLinkCacheMemcached )
136 $wgMemc->add( $key, $id, time()+3600 );
137 }
138 if ( 0 == $id ) { $this->addBadLink( $title ); }
139 else { $this->addGoodLink( $id, $title ); }
140 wfProfileOut( $fname );
141 return $id;
142 }
143
144 function preFill( &$fromtitle )
145 {
146 global $wgEnablePersistentLC;
147
148 $fname = "LinkCache::preFill";
149 wfProfileIn( $fname );
150 # Note -- $fromtitle is a Title *object*
151 $dbkeyfrom = wfStrencode( $fromtitle->getPrefixedDBKey() );
152
153 if ( $wgEnablePersistentLC ) {
154 $res = wfQuery("SELECT lcc_cacheobj FROM linkscc WHERE lcc_title = '{$dbkeyfrom}'",
155 DB_READ);
156 $row = wfFetchObject( $res );
157 if( $row != FALSE){
158 $cacheobj = gzuncompress( $row->lcc_cacheobj );
159 $cc = unserialize( $cacheobj );
160 $this->mGoodLinks = $cc->mGoodLinks;
161 $this->mBadLinks = $cc->mBadLinks;
162 $this->mPreFilled = true;
163 wfProfileOut( $fname );
164 return;
165 }
166 }
167
168
169 $sql = "SELECT cur_id,cur_namespace,cur_title
170 FROM cur,links
171 WHERE cur_id=l_to AND l_from='{$dbkeyfrom}'";
172 $res = wfQuery( $sql, DB_READ, $fname );
173 while( $s = wfFetchObject( $res ) ) {
174 $this->addGoodLink( $s->cur_id,
175 Title::makeName( $s->cur_namespace, $s->cur_title )
176 );
177 }
178
179 $this->suspend();
180 $id = $fromtitle->getArticleID();
181 $this->resume();
182
183 $sql = "SELECT bl_to
184 FROM brokenlinks
185 WHERE bl_from='{$id}'";
186 $res = wfQuery( $sql, DB_READ, "LinkCache::preFill" );
187 while( $s = wfFetchObject( $res ) ) {
188 $this->addBadLink( $s->bl_to );
189 }
190
191 $this->mOldBadLinks = $this->mBadLinks;
192 $this->mOldGoodLinks = $this->mGoodLinks;
193 $this->mPreFilled = true;
194
195 if ( $wgEnablePersistentLC ) {
196 // put fetched link data into cache
197 $serCachegz = wfStrencode( gzcompress( serialize( $this ), 3) );
198 wfQuery("REPLACE INTO linkscc VALUES({$id}, '{$dbkeyfrom}', '{$serCachegz}')",
199 DB_WRITE);
200 }
201
202 wfProfileOut( $fname );
203 }
204
205 function getGoodAdditions()
206 {
207 return array_diff( $this->mGoodLinks, $this->mOldGoodLinks );
208 }
209
210 function getBadAdditions()
211 {
212 return array_values( array_diff( $this->mBadLinks, $this->mOldBadLinks ) );
213 }
214
215 function getImageAdditions()
216 {
217 return array_diff_assoc( $this->mImageLinks, $this->mOldImageLinks );
218 }
219
220 function getGoodDeletions()
221 {
222 return array_diff( $this->mOldGoodLinks, $this->mGoodLinks );
223 }
224
225 function getBadDeletions()
226 {
227 return array_values( array_diff( $this->mOldBadLinks, $this->mBadLinks ) );
228 }
229
230 function getImageDeletions()
231 {
232 return array_diff_assoc( $this->mOldImageLinks, $this->mImageLinks );
233 }
234
235 # Parameters: $which is one of the LINKCACHE_xxx constants, $del and $add are
236 # the incremental update arrays which will be filled. Returns whether or not it's
237 # worth doing the incremental version. For example, if [[List of mathematical topics]]
238 # was blanked, it would take a long, long time to do incrementally.
239 function incrementalSetup( $which, &$del, &$add )
240 {
241 if ( ! $this->mPreFilled ) {
242 return false;
243 }
244
245 switch ( $which ) {
246 case LINKCACHE_GOOD:
247 $old =& $this->mOldGoodLinks;
248 $cur =& $this->mGoodLinks;
249 $del = $this->getGoodDeletions();
250 $add = $this->getGoodAdditions();
251 break;
252 case LINKCACHE_BAD:
253 $old =& $this->mOldBadLinks;
254 $cur =& $this->mBadLinks;
255 $del = $this->getBadDeletions();
256 $add = $this->getBadAdditions();
257 break;
258 default: # LINKCACHE_IMAGE
259 return false;
260 }
261
262 return true;
263 }
264
265 # Clears cache but leaves old preFill copies alone
266 function clear()
267 {
268 $this->mGoodLinks = array();
269 $this->mBadLinks = array();
270 $this->mImageLinks = array();
271 }
272
273 }
274 ?>