Index: trunk/phase3/includes/SpecialAllpages.php |
— | — | @@ -11,36 +11,28 @@ |
12 | 12 | function wfSpecialAllpages( $par=NULL, $specialPage ) { |
13 | 13 | global $indexMaxperpage, $toplevelMaxperpage, $wgRequest, $wgOut, $wgContLang; |
14 | 14 | # Config |
15 | | - $indexMaxperpage = 480; |
| 15 | + $indexMaxperpage = 960; |
16 | 16 | $toplevelMaxperpage = 50; |
17 | 17 | # GET values |
18 | 18 | $from = $wgRequest->getVal( 'from' ); |
19 | 19 | $namespace = $wgRequest->getInt( 'namespace' ); |
20 | | - $invert = $wgRequest->getBool( 'invert' ); |
21 | 20 | |
22 | 21 | $namespaces = $wgContLang->getNamespaces(); |
23 | 22 | |
24 | 23 | if( !in_array($namespace, array_keys($namespaces)) ) |
25 | 24 | $namespace = 0; |
26 | 25 | |
27 | | - if ($invert) { |
28 | | - $wgOut->setPagetitle( $namespace > 0 ? |
29 | | - wfMsg( 'allnotinnamespace', $namespaces[$namespace] ) : |
30 | | - wfMsg( 'allnonarticles' ) |
31 | | - ); |
32 | | - } else { |
33 | | - $wgOut->setPagetitle( $namespace > 0 ? |
34 | | - wfMsg( 'allinnamespace', $namespaces[$namespace] ) : |
35 | | - wfMsg( 'allarticles' ) |
36 | | - ); |
37 | | - } |
| 26 | + $wgOut->setPagetitle( $namespace > 0 ? |
| 27 | + wfMsg( 'allinnamespace', $namespaces[$namespace] ) : |
| 28 | + wfMsg( 'allarticles' ) |
| 29 | + ); |
38 | 30 | |
39 | 31 | if ( isset($par) ) { |
40 | | - indexShowChunk( $namespace, $par, $invert, $specialPage->including() ); |
| 32 | + indexShowChunk( $namespace, $par, $specialPage->including() ); |
41 | 33 | } elseif ( isset($from) ) { |
42 | | - indexShowChunk( $namespace, $from, $invert, $specialPage->including() ); |
| 34 | + indexShowChunk( $namespace, $from, $specialPage->including() ); |
43 | 35 | } else { |
44 | | - indexShowToplevel ( $namespace, $invert, $specialPage->including() ); |
| 36 | + indexShowToplevel ( $namespace, $specialPage->including() ); |
45 | 37 | } |
46 | 38 | } |
47 | 39 | |
— | — | @@ -48,9 +40,8 @@ |
49 | 41 | * HTML for the top form |
50 | 42 | * @param integer $namespace A namespace constant (default NS_MAIN). |
51 | 43 | * @param string $from Article name we are starting listing at. |
52 | | - * @param bool $invert true if we want the namespaces inverted (default false) |
53 | 44 | */ |
54 | | -function indexNamespaceForm ( $namespace = NS_MAIN, $from = '', $invert = false ) { |
| 45 | +function indexNamespaceForm ( $namespace = NS_MAIN, $from = '' ) { |
55 | 46 | global $wgContLang, $wgScript; |
56 | 47 | $t = Title::makeTitle( NS_SPECIAL, "Allpages" ); |
57 | 48 | |
— | — | @@ -69,8 +60,6 @@ |
70 | 61 | . htmlspecialchars ( $from ) . '"/>'; |
71 | 62 | $submitbutton = '<input type="submit" value="' . wfMsg( 'allpagessubmit' ) . '" />'; |
72 | 63 | |
73 | | - $invertbox = "<input type='checkbox' name='invert' value='1' id='nsinvert'" . ( $invert ? ' checked="checked"' : '' ) . ' />'; |
74 | | - |
75 | 64 | $out = "<div class='namespaceselector'><form method='get' action='{$wgScript}'>"; |
76 | 65 | $out .= '<input type="hidden" name="title" value="'.$t->getPrefixedText().'" />'; |
77 | 66 | $out .= " |
— | — | @@ -82,8 +71,7 @@ |
83 | 72 | <tr> |
84 | 73 | <td align='right'><label for='nsselectbox'>" . wfMsg('namespace') . "</label></td> |
85 | 74 | <td align='left'> |
86 | | - $namespaceselect $submitbutton $invertbox |
87 | | - <label for='nsinvert'>" . wfMsg('invert') . "</label> |
| 75 | + $namespaceselect $submitbutton |
88 | 76 | </td> |
89 | 77 | </tr> |
90 | 78 | </table> |
— | — | @@ -94,9 +82,8 @@ |
95 | 83 | |
96 | 84 | /** |
97 | 85 | * @param integer $namespace (default NS_MAIN) |
98 | | - * @param bool $invert true if we want the namespaces inverted (default false) |
99 | 86 | */ |
100 | | -function indexShowToplevel ( $namespace = NS_MAIN, $invert = false, $including = false ) { |
| 87 | +function indexShowToplevel ( $namespace = NS_MAIN, $including = false ) { |
101 | 88 | global $wgOut, $indexMaxperpage, $toplevelMaxperpage, $wgContLang, $wgRequest, $wgUser; |
102 | 89 | $sk = $wgUser->getSkin(); |
103 | 90 | $fname = "indexShowToplevel"; |
— | — | @@ -106,89 +93,81 @@ |
107 | 94 | |
108 | 95 | $dbr =& wfGetDB( DB_SLAVE ); |
109 | 96 | $page = $dbr->tableName( 'page' ); |
110 | | - $fromwhere = "FROM $page WHERE page_namespace" . |
111 | | - ($invert ? '!' : '') . "=$namespace"; |
| 97 | + $fromwhere = "FROM $page WHERE page_namespace=$namespace"; |
112 | 98 | $order_arr = array ( 'ORDER BY' => 'page_title' ); |
113 | 99 | $order_str = 'ORDER BY page_title'; |
114 | 100 | $out = ""; |
115 | 101 | $where = array( 'page_namespace' => $namespace ); |
116 | 102 | |
117 | | - $count = $dbr->selectField( 'page', 'COUNT(*)', $where, $fname ); |
118 | | - $sections = ceil( $count / $indexMaxperpage ); |
| 103 | + global $wgMemc, $wgDBname; |
| 104 | + $key = "$wgDBname:allpages:ns:$namespace"; |
| 105 | + $lines = $wgMemc->get( $key ); |
119 | 106 | |
120 | | - if ( $sections < 3 ) { |
121 | | - # If there are only two or less sections, don't even display them. |
122 | | - # Instead, display the first section directly. |
123 | | - indexShowChunk( $namespace, '', $invert, $including ); |
124 | | - return; |
125 | | - } |
126 | | - |
127 | | - # We want to display $toplevelMaxperpage lines starting at $offset. |
128 | | - # NOTICE: $offset starts at 0 |
129 | | - $offset = intval ( $wgRequest->getVal( 'offset' ) ); |
130 | | - if ( $offset < 0 ) { $offset = 0; } |
131 | | - if ( $offset >= $sections ) { $offset = $sections - 1; } |
132 | | - |
133 | | - # Where to stop? Notice that this can take the value of $sections, but $offset can't, because if |
134 | | - # we're displaying only the very last section, we still need two DB queries to find the titles |
135 | | - $stopat = ( $offset + $toplevelMaxperpage < $sections ) |
136 | | - ? $offset + $toplevelMaxperpage : $sections ; |
137 | | - |
138 | | - # This array is going to hold the page_titles in order. |
139 | | - $lines = array(); |
140 | | - |
141 | | - # If we are going to show n rows, we need n+1 queries to find the relevant titles. |
142 | | - for ( $i = $offset; $i <= $stopat; ++$i ) { |
143 | | - if ( $i == $sections ) # if we're displaying the last section, we need to |
144 | | - $from = $count-1; # find the last page_title in the DB |
145 | | - else if ( $i > $offset ) |
146 | | - $from = $i * $indexMaxperpage - 1; |
147 | | - else |
148 | | - $from = $i * $indexMaxperpage; |
149 | | - $limit = ( $i == $offset || $i == $stopat ) ? 1 : 2; |
150 | | - $sql = "SELECT page_title $fromwhere $order_str " . $dbr->limitResult ( $limit, $from ); |
151 | | - $res = $dbr->query( $sql, $fname ); |
152 | | - if ( $s = $dbr->fetchObject( $res ) ) { |
153 | | - array_push ( $lines, $s->page_title ); |
| 107 | + if( !is_array( $lines ) ) { |
| 108 | + $firstTitle = $dbr->selectField( 'page', 'page_title', $where, $fname, array( 'LIMIT' => 1 ) ); |
| 109 | + $lastTitle = $firstTitle; |
| 110 | + |
| 111 | + # This array is going to hold the page_titles in order. |
| 112 | + $lines = array( $firstTitle ); |
| 113 | + |
| 114 | + # If we are going to show n rows, we need n+1 queries to find the relevant titles. |
| 115 | + $done = false; |
| 116 | + for( $i = 0; !$done; ++$i ) { |
| 117 | + // Fetch the last title of this chunk and the first of the next |
| 118 | + $chunk = is_null( $lastTitle ) |
| 119 | + ? '1=1' |
| 120 | + : 'page_title >= ' . $dbr->addQuotes( $lastTitle ); |
| 121 | + $sql = "SELECT page_title $fromwhere AND $chunk $order_str " . |
| 122 | + $dbr->limitResult( 2, $indexMaxperpage - 1 ); |
| 123 | + $res = $dbr->query( $sql, $fname ); |
154 | 124 | if ( $s = $dbr->fetchObject( $res ) ) { |
155 | | - array_push ( $lines, $s->page_title ); |
| 125 | + array_push( $lines, $s->page_title ); |
| 126 | + } else { |
| 127 | + // Final chunk, but ended prematurely. Go back and find the end. |
| 128 | + $endTitle = $dbr->selectField( 'page', 'MAX(page_title)', |
| 129 | + array( |
| 130 | + 'page_namespace' => $namespace, |
| 131 | + $chunk |
| 132 | + ), $fname ); |
| 133 | + array_push( $lines, $endTitle ); |
| 134 | + $done = true; |
156 | 135 | } |
| 136 | + if( $s = $dbr->fetchObject( $res ) ) { |
| 137 | + array_push( $lines, $s->page_title ); |
| 138 | + $lastTitle = $s->page_title; |
| 139 | + } else { |
| 140 | + // This was a final chunk and ended exactly at the limit. |
| 141 | + // Rare but convenient! |
| 142 | + $done = true; |
| 143 | + } |
| 144 | + $dbr->freeResult( $res ); |
157 | 145 | } |
158 | | - $dbr->freeResult( $res ); |
| 146 | + $wgMemc->add( $key, $lines, 3600 ); |
159 | 147 | } |
| 148 | + |
| 149 | + // If there are only two or less sections, don't even display them. |
| 150 | + // Instead, display the first section directly. |
| 151 | + if( count( $lines ) <= 2 ) { |
| 152 | + indexShowChunk( $namespace, '', false, $including ); |
| 153 | + return; |
| 154 | + } |
160 | 155 | |
161 | 156 | # At this point, $lines should contain an even number of elements. |
162 | 157 | $out .= "<table style='background: inherit;'>"; |
163 | 158 | while ( count ( $lines ) > 0 ) { |
164 | 159 | $inpoint = array_shift ( $lines ); |
165 | 160 | $outpoint = array_shift ( $lines ); |
166 | | - $out .= indexShowline ( $inpoint, $outpoint, $namespace, $invert ); |
| 161 | + $out .= indexShowline ( $inpoint, $outpoint, $namespace, false ); |
167 | 162 | } |
168 | 163 | $out .= '</table>'; |
169 | 164 | |
170 | | - $nsForm = indexNamespaceForm ( $namespace, '', $invert ); |
| 165 | + $nsForm = indexNamespaceForm ( $namespace, '', false ); |
171 | 166 | |
172 | 167 | # Is there more? |
173 | 168 | if ( $including ) { |
174 | 169 | $out2 = ''; |
175 | 170 | } else { |
176 | 171 | $morelinks = ''; |
177 | | - if ( $offset > 0 ) { |
178 | | - $morelinks = $sk->makeKnownLink ( |
179 | | - $wgContLang->specialPage ( 'Allpages' ), |
180 | | - wfMsg ( 'allpagesprev' ), |
181 | | - ( $offset > $toplevelMaxperpage ) ? 'offset='.($offset-$toplevelMaxperpage) : '' |
182 | | - ); |
183 | | - } |
184 | | - if ( $stopat < $sections-1 ) { |
185 | | - if ( $morelinks != '' ) { $morelinks .= " | "; } |
186 | | - $morelinks .= $sk->makeKnownLink ( |
187 | | - $wgContLang->specialPage ( 'Allpages' ), |
188 | | - wfMsg ( 'allpagesnext' ), |
189 | | - 'offset=' . ($offset + $toplevelMaxperpage) |
190 | | - ); |
191 | | - } |
192 | | - |
193 | 172 | if ( $morelinks != '' ) { |
194 | 173 | $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">'; |
195 | 174 | $out2 .= '<tr valign="top"><td align="left">' . $nsForm; |
— | — | @@ -206,16 +185,15 @@ |
207 | 186 | * @todo Document |
208 | 187 | * @param string $from |
209 | 188 | * @param integer $namespace (Default NS_MAIN) |
210 | | - * @param bool $invert true if we want the namespaces inverted (default false) |
211 | 189 | */ |
212 | | -function indexShowline( $inpoint, $outpoint, $namespace = NS_MAIN, $invert ) { |
| 190 | +function indexShowline( $inpoint, $outpoint, $namespace = NS_MAIN ) { |
213 | 191 | global $wgOut, $wgLang, $wgUser; |
214 | 192 | $sk = $wgUser->getSkin(); |
215 | 193 | $dbr =& wfGetDB( DB_SLAVE ); |
216 | 194 | |
217 | 195 | $inpointf = htmlspecialchars( str_replace( '_', ' ', $inpoint ) ); |
218 | 196 | $outpointf = htmlspecialchars( str_replace( '_', ' ', $outpoint ) ); |
219 | | - $queryparams = ($namespace ? "namespace=$namespace" : '') . ($invert ? "&invert=$invert" : ''); |
| 197 | + $queryparams = ($namespace ? "namespace=$namespace" : ''); |
220 | 198 | $special = Title::makeTitle( NS_SPECIAL, 'Allpages/' . $inpoint ); |
221 | 199 | $link = $special->escapeLocalUrl( $queryparams ); |
222 | 200 | |
— | — | @@ -230,9 +208,8 @@ |
231 | 209 | /** |
232 | 210 | * @param integer $namespace (Default NS_MAIN) |
233 | 211 | * @param string $from list all pages from this name (default FALSE) |
234 | | - * @param bool $invert true if we want the namespaces inverted (default false) |
235 | 212 | */ |
236 | | -function indexShowChunk( $namespace = NS_MAIN, $from, $invert = false, $including = false ) { |
| 213 | +function indexShowChunk( $namespace = NS_MAIN, $from, $including = false ) { |
237 | 214 | global $wgOut, $wgUser, $indexMaxperpage, $wgContLang; |
238 | 215 | $sk = $wgUser->getSkin(); |
239 | 216 | $maxPlusOne = $indexMaxperpage + 1; |
— | — | @@ -244,8 +221,8 @@ |
245 | 222 | $fromTitle = Title::newFromURL( $from ); |
246 | 223 | $fromKey = is_null( $fromTitle ) ? '' : $fromTitle->getDBkey(); |
247 | 224 | |
248 | | - $sql = "SELECT page_namespace,page_title FROM $page WHERE page_namespace" . |
249 | | - ($invert ? '!' : '') . "=$namespace" . |
| 225 | + $sql = "SELECT page_namespace,page_title FROM $page" . |
| 226 | + " WHERE page_namespace=$namespace" . |
250 | 227 | " AND page_title >= ". $dbr->addQuotes( $fromKey ) . |
251 | 228 | " ORDER BY page_title LIMIT " . $maxPlusOne; |
252 | 229 | $res = $dbr->query( $sql, 'indexShowChunk' ); |
— | — | @@ -259,10 +236,7 @@ |
260 | 237 | while( ($n < $indexMaxperpage) && ($s = $dbr->fetchObject( $res )) ) { |
261 | 238 | $t = Title::makeTitle( $s->page_namespace, $s->page_title ); |
262 | 239 | if( $t ) { |
263 | | - $ns = $s->page_namespace; |
264 | | - $prefix = $invert ? $namespaces[$ns] : ''; |
265 | | - $prefix .= $invert && $namespaces[$ns] != $wgContLang->getNsText(NS_MAIN) ? ':' : ''; |
266 | | - $link = $sk->makeKnownLinkObj( $t, $t->getText(), false, false, $prefix ); |
| 240 | + $link = $sk->makeKnownLinkObj( $t, htmlspecialchars( $t->getText() ), false, false ); |
267 | 241 | } else { |
268 | 242 | $link = '[[' . htmlspecialchars( $s->page_title ) . ']]'; |
269 | 243 | } |
— | — | @@ -283,7 +257,7 @@ |
284 | 258 | if ( $including ) { |
285 | 259 | $out2 = ''; |
286 | 260 | } else { |
287 | | - $nsForm = indexNamespaceForm ( $namespace, $from, $invert ); |
| 261 | + $nsForm = indexNamespaceForm ( $namespace, $from ); |
288 | 262 | $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">'; |
289 | 263 | $out2 .= '<tr valign="top"><td align="left">' . $nsForm; |
290 | 264 | $out2 .= '</td><td align="right" style="font-size: smaller; margin-bottom: 1em;">' . |
— | — | @@ -291,11 +265,10 @@ |
292 | 266 | wfMsg ( 'allpages' ) ); |
293 | 267 | if ( ($n == $indexMaxperpage) && ($s = $dbr->fetchObject( $res )) ) { |
294 | 268 | $namespaceparam = $namespace ? "&namespace=$namespace" : ""; |
295 | | - $invertparam = $invert ? "&invert=$invert" : ''; |
296 | 269 | $out2 .= " | " . $sk->makeKnownLink( |
297 | 270 | $wgContLang->specialPage( "Allpages" ), |
298 | 271 | wfMsg ( 'nextpage', $s->page_title ), |
299 | | - "from=" . wfUrlEncode ( $s->page_title ) . $namespaceparam . $invertparam ); |
| 272 | + "from=" . wfUrlEncode ( $s->page_title ) . $namespaceparam ); |
300 | 273 | } |
301 | 274 | $out2 .= "</td></tr></table><hr />"; |
302 | 275 | } |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -580,7 +580,10 @@ |
581 | 581 | * (bug 2866) Revert experimental, non-cross-platform sortable table hack |
582 | 582 | * PHP 4.1.2 compatibility fix: define floatval() equivalent if missing |
583 | 583 | * (bug 2901) Number format for Catalan |
| 584 | +* Special:Allpages performance hacks: index memcached caching, removed |
| 585 | + inverse checkbox, use friendlier relative offsets in index build |
584 | 586 | |
| 587 | + |
585 | 588 | === Caveats === |
586 | 589 | |
587 | 590 | Some output, particularly involving user-supplied inline HTML, may not |