r23086 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r23085‎ | r23086 | r23087 >
Date:03:11, 19 June 2007
Author:david
Status:old
Tags:
Comment:
New thread schema and new, totally ridiculous algorithm to grab threads out of the DB. Somebody comes up with a smarter way to do this, please tell me. As for the rest, very bootstrappy and not really working.
Modified paths:
  • /branches/liquidthreads/extensions/LqtExtension.php (modified) (history)
  • /branches/liquidthreads/extensions/LqtModel.php (modified) (history)
  • /branches/liquidthreads/maintenance/lqt.sql (modified) (history)

Diff [purge]

Index: branches/liquidthreads/maintenance/lqt.sql
@@ -1,30 +1,13 @@
2 -CREATE TABLE /*$wgDBprefix*/lqt_thread (
 2+CREATE TABLE /*$wgDBprefix*/thread (
33 thread_id int(8) unsigned NOT NULL auto_increment,
4 -
5 - thread_root_post int(8) unsigned NOT NULL,
6 -
7 - -- Article that this thread belongs to.
 4+ thread_root int(8) unsigned NOT NULL,
85 thread_article int(8) unsigned NOT NULL,
9 -
10 - -- Thread this is a subthread (reply) of. NULL if top-level to article.
11 - thread_subthread_of int(8) unsigned NULL,
12 -
13 - -- Summary post:
 6+ thread_path varchar(1000000) NOT NULL,
147 thread_summary_page int(8) unsigned NULL,
15 -
16 - -- Subject line string:
17 - thread_subject varchar(255) binary NULL,
18 -
19 - -- Timestamp
208 thread_touched char(14) binary NOT NULL default '',
219
2210 PRIMARY KEY thread_id (thread_id),
23 - UNIQUE INDEX thread_id (thread_id),
24 - INDEX thread_subthread_of (thread_subthread_of),
25 - INDEX thread_article_touched (thread_article, thread_touched),
26 - INDEX thread_article (thread_article),
27 - INDEX thread_root_post (thread_root_post)
28 -
 11+ UNIQUE INDEX thread_id (thread_id)
2912 ) TYPE=InnoDB;
3013
3114 /*
Index: branches/liquidthreads/extensions/LqtExtension.php
@@ -596,6 +596,9 @@
597597 $this->output->setPageTitle( "Talk:" . $this->title->getText() ); // TODO non-main namespaces.
598598 $this->addJSandCSS();
599599
 600+ lqtCheapTest( );
 601+ return;
 602+
600603 $this->showHeader();
601604
602605 $this->showArchiveWidget();
Index: branches/liquidthreads/extensions/LqtModel.php
@@ -101,247 +101,98 @@
102102
103103 }
104104
105 -class Thread {
 105+class LiveThread {
106106
107 - /* ID references to other objects that are loaded on demand: */
108 - protected $rootPostId;
109 - protected $articleId;
110 - protected $summaryId;
111 - protected $superthreadId;
 107+}
112108
113 - /* Actual objects loaded on demand from the above when accessors are called: */
114 - protected $rootPost;
115 - protected $article;
116 - protected $summary;
117 - protected $superthread;
118 -
119 - /* Simple strings: */
120 - protected $subject;
121 - protected $touched;
 109+/** Module of factory methods. */
 110+class Threads {
122111
123 - /* Identity */
124 - protected $id;
125 -
126 - function setSuperthread($thread) {
127 - $this->superthreadId = $thread->id();
128 - $this->touch();
129 - }
130 -
131 - function superthread() {
132 - if ( !$this->superthreadId ) return null;
133 - if ( !$this->superthread ) $this->superthread = Thread::newFromId($this->superthreadId);
134 - return $this->superthread;
135 - }
136 -
137 - function topmostThread() {
138 - if ( !$this->superthread() ) return $this;
139 - else return $this->superthread()->topmostThread();
140 - }
141 -
142 - function setArticle($a) {
143 - $this->articleId = $a->getID();
144 - $this->touch();
145 - }
146 -
147 - function article() {
148 - if ( !$this->articleId ) return null;
149 - if ( !$this->article ) $this->article = new Article(Title::newFromID($this->articleId));
150 - return $this->article;
151 - }
152 -
153 - function id() {
154 - return $this->id;
155 - }
156 -
157 - function rootPost() {
158 - if ( !$this->rootPostId ) return null;
159 - if ( !$this->rootPost ) $this->rootPost = new Post( Title::newFromID( $this->rootPostId ) );
160 - return $this->rootPost;
161 - }
162 -
163 - function summary() {
164 - if ( !$this->summaryId ) return null;
165 - if ( !$this->summary ) $this->summary = new Post( Title::newFromID( $this->summaryId ) );
166 - return $this->summary;
167 - }
168 -
169 - function setSummary( $post ) {
170 - $this->summaryId = $post->getID();
171 - $this->updateRecord();
172 - }
173 -
174 - function wikilink() {
175 - return $this->rootPost()->getTitle()->getPrefixedText();
176 - }
177 -
178 - function wikilinkWithoutIncrement() {
179 - $foo = explode( ' ', $this->wikilink() );
180 - array_pop($foo);
181 - return implode( ' ', $foo );
182 - }
183 -
184 - function hasDistinctSubject() {
185 - if( $this->superthread() ) {
186 - return $this->superthread()->subjectWithoutIncrement()
187 - != $this->subjectWithoutIncrement();
 112+ static function threadsWhere( $where_clause, $options = array(), $extra_tables = array() ) {
 113+ $dbr =& wfGetDB( DB_SLAVE );
 114+ if ( is_array($where_clause) ) {
 115+ $where = implode( 'and ', $where_clause );
188116 } else {
189 - return true;
 117+ $where = $where_clause;
190118 }
191 - }
192119
193 - function subject() {
194 - return $this->rootPost()->getTitle()->getText();
195 - return $this->subject;
196 - }
197 -
198 - function subjectWithoutIncrement() {
199 - $foo = explode( ' ', $this->subject() );
200 - array_pop($foo);
201 - return implode( ' ', $foo );
202 - }
203 -
204 - function increment() {
205 - return array_pop( explode(' ', $this->subject()) );
206 - }
207 -
208 - function setSubject($s) {
209 - $this->subject = $s;
210 - $this->touch();
211 - }
 120+ /* Select the client's threads, AND all their children: */
212121
213 - function hasSubthreads() {
214 - // TODO inefficient.
215 - return count( $this->subthreads() ) != 0;
216 - }
 122+ $sql = <<< SQL
 123+SELECT children.* FROM thread, thread children
 124+WHERE $where AND
 125+children.thread_path LIKE CONCAT(thread.thread_path, "%")
 126+SQL;
 127+ $res = $dbr->query($sql);
217128
218 - function subthreads() {
219 - return Thread::threadsWhere( array('thread_subthread_of' => $this->id),
220 - array('ORDER BY' => 'thread_touched') );
221 - }
222 -
223 - function touch() {
224 - $this->touched = wfTimestampNow();
225 - $this->updateRecord();
226 - if ( $this->superthread() ) {
227 - $this->superthread()->touch();
 129+ /*
 130+ God probably kills a kitten whenever this next section of code is run.
 131+ We're creating a tree of objects from the flat list of rows. Please someone
 132+ think of a way to do this in one pass.
 133+ */
 134+
 135+ $tree = array();
 136+ while ( $line = $dbr->fetchObject($res) ) {
 137+ $path = explode('.', $line->thread_path);
 138+ Threads::setDeepArray( $tree, $line, $path );
 139+
228140 }
 141+ function createThreads( $thread ) {
 142+ $subthreads = array();
 143+ foreach( $thread as $key => $val ) {
 144+ if ( $key != 'root' ) {
 145+ $subthreads[] = createThreads( $val );
 146+ }
 147+ }
 148+ return Threads::newLiveThreadFromDBLine( $thread['root'], $subthreads );
 149+ }
 150+ $threads = array();
 151+ foreach( $tree as $root ) {
 152+ $threads[] = createThreads($root);
 153+ }
 154+
 155+ return $threads;
229156 }
230 -
231 - function touched() {
232 - return $this->touched;
233 - }
234 -
235 - protected function updateRecord() {
236 - $dbr =& wfGetDB( DB_MASTER );
237 - $res = $dbr->update( 'lqt_thread',
238 - /* SET */ array( 'thread_root_post' => $this->rootPostId,
239 - 'thread_article' => $this->articleId,
240 - 'thread_subthread_of' => $this->superthreadId,
241 - 'thread_summary_page' => $this->summaryId,
242 - 'thread_subject' => $this->subject,
243 - 'thread_touched' => $this->touched ),
244 - /* WHERE */ array( 'thread_id' => $this->id, ),
245 - __METHOD__);
246 - }
247157
248 - static function newFromDBLine( $line ) {
249 - $t = new Thread();
 158+ /** setDeepArray( $a, $v, array(1,2,3) ) <=> $a[1][2][3]['root'] = $v; */
 159+ private static function setDeepArray( &$a, $v, $p ) {
 160+ if( count($p) == 1 ) {
 161+ $a[$p[0]]["root"] = $v;
 162+ } else {
 163+ if( !array_key_exists( $p[0], $a ) )
 164+ $a[$p[0]] = array();
 165+ Threads::setDeepArray( $a[$p[0]], $v, array_slice($p, 1) );
 166+ }
 167+ }
 168+
 169+ static function newLiveThreadFromDBLine( $line, $children ) {
 170+ $t = new LiveThread();
250171 $t->id = $line->thread_id;
251 - $t->rootPostId = $line->thread_root_post;
 172+ $t->rootId = $line->thread_root;
252173 $t->articleId = $line->thread_article;
253174 $t->summaryId = $line->thread_summary_page;
254 - $t->superthreadId = $line->thread_subthread_of;
 175+ $t->path = $line->thread_path;
255176 $t->touched = $line->thread_touched;
256 - $t->subject = $line->thread_subject;
 177+ $t->replies = $children;
257178 return $t;
258179 }
259180
260 - static function newFromId( $id ) {
261 - $foo = Thread::threadsWhere( array('thread_id' => $id) );
262 - return count($foo) > 0 ? $foo[0] : null;
263 - }
 181+}
264182
265 - static function newThread( $root_post, $article ) {
266 - $dbr =& wfGetDB( DB_MASTER );
267 - $res = $dbr->insert('lqt_thread',
268 - array('thread_article' => $article->getID(),
269 - 'thread_root_post' => $root_post->getID(),
270 - 'thread_touched' => wfTimestampNow()),
271 - __METHOD__);
272 - // TODO we could avoid a query here.
273 - return Thread::newFromId( $dbr->insertId() );
274 - }
275 -
276 - /** List of months in which there are >0 threads, suitable for threadsOfArticleInMonth. */
277 - static function monthsWhereArticleHasThreads( $article ) {
278 - $threads = Thread::allThreadsOfArticle( $article );
279 - $months = array();
280 - foreach( $threads as $t ) {
281 - $m = substr( $t->touched(), 0, 6 );
282 - if ( !array_key_exists( $m, $months ) ) {
283 - if (!in_array( $m, $months )) $months[] = $m;
284 - }
 183+function lqtCheapTest() {
 184+ $threads = Threads::threadsWhere( "thread.thread_id = 1" );
 185+ function cheapShowThread($t) {
 186+ global $wgOut;
 187+ $wgOut->addHTML($t->id);
 188+ $wgOut->addHTML('<dl><dd>');
 189+ foreach( $t->replies as $r ) {
 190+ cheapShowThread($r);
285191 }
286 - return $months;
 192+ $wgOut->addHTML('</dd></dl>');
287193 }
288 -
289 - static function latestNThreadsOfArticle( $article, $n ) {
290 - return Thread::threadsWhere( array('thread_article' => $article->getID(),
291 - 'thread_subthread_of is null'),
292 - array('ORDER BY' => 'thread_touched DESC',
293 - 'LIMIT' => $n) );
 194+ foreach( $threads as $t ) {
 195+ cheapShowThread($t);
294196 }
295 -
296 - static function allThreadsOfArticle( $article ) {
297 - return Thread::threadsWhere( array('thread_article' => $article->getID(),
298 - 'thread_subthread_of is null'),
299 - array('ORDER BY' => 'thread_touched DESC') );
300 - }
301 -
302 - static function threadsOfArticleInMonth( $article, $yyyymm ) {
303 - return Thread::threadsWhere( array('thread_article' => $article->getID(),
304 - 'thread_subthread_of is null',
305 - 'thread_touched >= "'.Date::beginningOfMonth($yyyymm).'"',
306 - 'thread_touched <= "'.Date::endOfMonth($yyyymm).'"'),
307 - array('ORDER BY' => 'thread_touched DESC') );
308 - }
309 -
310 - static function threadsOfArticleInLastNDays( $article, $n ) {
311 - $startdate = Date::now()->nDaysAgo($n)->midnight();
312 - return Thread::threadsWhere( array('thread_article' => $article->getID(),
313 - 'thread_subthread_of is null',
314 - 'thread_touched >= ' . $startdate->text() ),
315 - array('ORDER BY' => 'thread_touched DESC' ) );
316 - }
317 -
318 - static function threadsWhoseRootPostIs( $post ) {
319 - return Thread::threadsWhere( array('thread_root_post' => $post->getID()) );
320 - }
321 -
322 - static function threadsWhere( $where_clause, $options = array(), $extra_tables = array() ) {
323 - $dbr =& wfGetDB( DB_SLAVE );
324 - $res = $dbr->select( array_merge(array('lqt_thread'), $extra_tables),
325 - array('lqt_thread.*'),
326 - $where_clause,
327 - __METHOD__,
328 - $options);
329 - $threads = array();
330 - while ( $line = $dbr->fetchObject($res) ) {
331 - $threads[] = Thread::newFromDBLine( $line );
332 - }
333 - return $threads;
334 - }
335 -
336 - static function walk( $root, $thread_callback, $push_callback, $pop_callback ) {
337 - call_user_func($thread_callback, $root);
338 - $s = $root->subthreads(); if ($s) {
339 - call_user_func($push_callback);
340 - foreach ($s as $t) {
341 - Thread::walk($t, $thread_callback, $push_callback, $pop_callback);
342 - }
343 - call_user_func($pop_callback);
344 - }
345 - }
346197 }
347198
348199 class QueryGroup {

Status & tagging log