fixed pagelinks bug
[lhc/web/wiklou.git] / includes / LinksUpdate.php
1 <?php
2 /**
3 * See deferred.txt
4 * @package MediaWiki
5 */
6
7 /**
8 * @todo document
9 * @package MediaWiki
10 */
11 class LinksUpdate {
12
13 /**#@+
14 * @access private
15 */
16 var $mId, $mTitle;
17 /**#@-*/
18
19 /**
20 * Constructor
21 * Initialize private variables
22 * @param integer $id
23 * @param string $title
24 */
25 function LinksUpdate( $id, $title ) {
26 $this->mId = $id;
27 $this->mTitle = $title;
28 }
29
30 /**
31 * Update link tables with outgoing links from an updated article
32 * Relies on the 'link cache' to be filled out.
33 */
34
35 function doUpdate() {
36 global $wgUseBetterLinksUpdate, $wgLinkCache, $wgDBtransactions;
37 global $wgEnablePersistentLC, $wgUseCategoryMagic;
38
39 $fname = 'LinksUpdate::doUpdate';
40 wfProfileIn( $fname );
41
42 $del = array();
43 $add = array();
44
45 $dbw =& wfGetDB( DB_MASTER );
46 $pagelinks = $dbw->tableName( 'pagelinks' );
47 $imagelinks = $dbw->tableName( 'imagelinks' );
48 $categorylinks = $dbw->tableName( 'categorylinks' );
49
50 #------------------------------------------------------------------------------
51 # Good links
52
53 if ( $wgLinkCache->incrementalSetup( LINKCACHE_PAGE, $del, $add ) ) {
54 # Delete where necessary
55 if ( count( $del ) ) {
56 $batch = new LinkBatch( $del );
57 $set = $batch->constructSet( 'pl', $dbw );
58 if ( $set ) {
59 $sql = "DELETE FROM $pagelinks WHERE pl_from={$this->mId} AND ($set)";
60 $dbw->query( $sql, $fname );
61 }
62 }
63 } else {
64 # Delete everything
65 $dbw->delete( 'pagelinks', array( 'pl_from' => $this->mId ), $fname );
66
67 # Get the addition list
68 $add = $wgLinkCache->getGoodLinks();
69 }
70
71 # Do the insertion
72 if( 0 != count( $add ) ) {
73 $arr = array();
74 foreach( $add as $lt => $target ) {
75 array_push( $arr, array(
76 'pl_from' => $this->mId,
77 'pl_namespace' => $target->getNamespace(),
78 'pl_title' => $target->getDbKey() ) );
79 }
80
81 # The link cache was constructed without FOR UPDATE, so there may be collisions
82 # Ignoring for now, I'm not sure if that causes problems or not, but I'm fairly
83 # sure it's better than without IGNORE
84 $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) );
85 }
86
87 #------------------------------------------------------------------------------
88 # Image links
89 $dbw->delete('imagelinks',array('il_from'=>$this->mId),$fname);
90
91 # Get addition list
92 $add = $wgLinkCache->getImageLinks();
93
94 # Do the insertion
95 $sql = '';
96 $image = NS_IMAGE;
97 if ( 0 != count ( $add ) ) {
98 $arr = array();
99 foreach ($add as $iname => $val ) {
100 $nt = Title::makeTitle( $image, $iname );
101 if( !$nt ) continue;
102 $nt->invalidateCache();
103 array_push( $arr, array(
104 'il_from' => $this->mId,
105 'il_to' => $iname ) );
106 }
107 $dbw->insert('imagelinks', $arr, $fname, array('IGNORE'));
108 }
109
110 #------------------------------------------------------------------------------
111 # Category links
112 if( $wgUseCategoryMagic ) {
113 global $messageMemc, $wgDBname;
114
115 # Get addition list
116 $add = $wgLinkCache->getCategoryLinks();
117
118 # select existing catlinks for this page
119 $res = $dbw->select( 'categorylinks',
120 array( 'cl_to', 'cl_sortkey' ),
121 array( 'cl_from' => $this->mId ),
122 $fname,
123 'FOR UPDATE' );
124
125 $del = array();
126 if( 0 != $dbw->numRows( $res ) ) {
127 while( $row = $dbw->fetchObject( $res ) ) {
128 if( !isset( $add[$row->cl_to] ) || $add[$row->cl_to] != $row->cl_sortkey ) {
129 // in the db, but no longer in the page
130 // or sortkey has changed -> delete
131 $del[] = $row->cl_to;
132 } else {
133 // remove already existing category memberships
134 // from the add array
135 unset( $add[$row->cl_to] );
136 }
137 }
138 }
139
140 // delete any removed categorylinks
141 if( count( $del ) > 0) {
142 // delete old ones
143 $dbw->delete( 'categorylinks',
144 array(
145 'cl_from' => $this->mId,
146 'cl_to' => $del ),
147 $fname );
148 foreach( $del as $cname ){
149 $nt = Title::makeTitle( NS_CATEGORY, $cname );
150 $nt->invalidateCache();
151 // update the timestamp which indicates when the last article
152 // was added or removed to/from this article
153 $key = $wgDBname . ':Category:' . md5( $nt->getDBkey() ) . ':adddeltimestamp';
154 $messageMemc->set( $key , wfTimestamp( TS_MW ), 24*3600 );
155 }
156 }
157
158 // add any new category memberships
159 if( count( $add ) > 0 ) {
160 $arr = array();
161 foreach( $add as $cname => $sortkey ) {
162 $nt = Title::makeTitle( NS_CATEGORY, $cname );
163 $nt->invalidateCache();
164 // update the timestamp which indicates when the last article
165 // was added or removed to/from this article
166 $key = $wgDBname . ':Category:' . md5( $nt->getDBkey() ) . ':adddeltimestamp';
167 $messageMemc->set( $key , wfTimestamp( TS_MW ), 24*3600 );
168 array_push( $arr, array(
169 'cl_from' => $this->mId,
170 'cl_to' => $cname,
171 'cl_sortkey' => $sortkey ) );
172 }
173 // do the actual sql insertion
174 $dbw->insert( 'categorylinks', $arr, $fname, array( 'IGNORE' ) );
175 }
176 }
177
178 wfProfileOut( $fname );
179 }
180
181 /**
182 * Link update which clears the previous entries and inserts new ones
183 * May be slower or faster depending on level of lock contention and write speed of DB
184 * Also useful where link table corruption needs to be repaired, e.g. in refreshLinks.php
185 */
186 function doDumbUpdate() {
187 global $wgLinkCache, $wgDBtransactions, $wgUseCategoryMagic;
188 $fname = 'LinksUpdate::doDumbUpdate';
189 wfProfileIn( $fname );
190
191
192 $dbw =& wfGetDB( DB_MASTER );
193 $pagelinks = $dbw->tableName( 'pagelinks' );
194 $imagelinks = $dbw->tableName( 'imagelinks' );
195 $categorylinks = $dbw->tableName( 'categorylinks' );
196
197 $dbw->delete('pagelinks', array('pl_from'=>$this->mId),$fname);
198
199 $a = $wgLinkCache->getPageLinks();
200 if ( 0 != count( $a ) ) {
201 $arr = array();
202 foreach( $a as $lt => $target ) {
203 array_push( $arr, array(
204 'pl_from' => $this->mId,
205 'pl_namespace' => $target->getNamespace(),
206 'pl_title' => $target->getTitle() ) );
207 }
208 $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) );
209 }
210
211 $dbw->delete('imagelinks', array('il_from'=>$this->mId),$fname);
212
213 $a = $wgLinkCache->getImageLinks();
214 $sql = '';
215 if ( 0 != count ( $a ) ) {
216 $arr = array();
217 foreach( $a as $iname => $val )
218 array_push( $arr, array(
219 'il_from' => $this->mId,
220 'il_to' => $iname ) );
221 $dbw->insert( 'imagelinks', $arr, $fname, array( 'IGNORE' ) );
222 }
223
224 if( $wgUseCategoryMagic ) {
225 $dbw->delete('categorylinks', array('cl_from'=>$this->mId),$fname);
226
227 # Get addition list
228 $add = $wgLinkCache->getCategoryLinks();
229
230 # Do the insertion
231 $sql = '';
232 if ( 0 != count ( $add ) ) {
233 $arr = array();
234 foreach( $add as $cname => $sortkey ) {
235 # FIXME: Change all this to avoid unnecessary duplication
236 $nt = Title::makeTitle( NS_CATEGORY, $cname );
237 if( !$nt ) continue;
238 $nt->invalidateCache();
239 array_push( $arr, array(
240 'cl_from' => $this->mId,
241 'cl_to' => $cname,
242 'cl_sortkey' => $sortkey ) );
243 }
244 $dbw->insert( 'categorylinks', $arr, $fname, array( 'IGNORE' ) );
245 }
246 }
247 wfProfileOut( $fname );
248 }
249 }
250 ?>