recalc.php 22.3 KB
Newer Older
Scott committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	File: qa-include/qa-app-recalc.php
	Description: Managing database recalculations (clean-up operations) and status messages


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

/*
	A full list of redundant (non-normal) information in the database that can be recalculated:

	Recalculated in doreindexcontent:
	================================
	^titlewords (all): index of words in titles of posts
	^contentwords (all): index of words in content of posts
	^tagwords (all): index of words in tags of posts (a tag can contain multiple words)
	^posttags (all): index tags of posts
	^words (all): list of words used for indexes
	^options (title=cache_*): cached values for various things (e.g. counting questions)

	Recalculated in dorecountposts:
	==============================
	^posts (upvotes, downvotes, netvotes, hotness, acount, amaxvotes, flagcount): number of votes, hotness, answers, answer votes, flags

	Recalculated in dorecalcpoints:
	===============================
	^userpoints (all except bonus): points calculation for all users
	^options (title=cache_userpointscount):

	Recalculated in dorecalccategories:
	===================================
	^posts (categoryid): assign to answers and comments based on their antecedent question
	^posts (catidpath1, catidpath2, catidpath3): hierarchical path to category ids (requires QA_CATEGORY_DEPTH=4)
	^categories (qcount): number of (visible) questions in each category
	^categories (backpath): full (backwards) path of slugs to that category

	Recalculated in dorebuildupdates:
	=================================
	^sharedevents (all): per-entity event streams (see big comment in qa-db-favorites.php)
	^userevents (all): per-subscriber event streams

	[but these are not entirely redundant since they can contain historical information no longer in ^posts]
*/

Scott committed
59 60 61 62 63
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
	header('Location: ../');
	exit;
}

Scott committed
64 65 66 67 68 69 70 71 72
require_once QA_INCLUDE_DIR . 'db/recalc.php';
require_once QA_INCLUDE_DIR . 'db/post-create.php';
require_once QA_INCLUDE_DIR . 'db/points.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'db/admin.php';
require_once QA_INCLUDE_DIR . 'db/users.php';
require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR . 'app/post-create.php';
require_once QA_INCLUDE_DIR . 'app/post-update.php';
Scott committed
73 74 75 76 77


/**
 * Advance the recalculation operation represented by $state by a single step.
 * $state can also be the name of a recalculation operation on its own.
Scott committed
78 79
 * @param $state
 * @return bool
Scott committed
80 81 82
 */
function qa_recalc_perform_step(&$state)
{
Scott committed
83
	$continue = false;
Scott committed
84

Scott committed
85
	@list($operation, $length, $next, $done) = explode("\t", $state);
Scott committed
86 87 88 89 90 91 92

	switch ($operation) {
		case 'doreindexcontent':
			qa_recalc_transition($state, 'doreindexcontent_pagereindex');
			break;

		case 'doreindexcontent_pagereindex':
Scott committed
93
			$pages = qa_db_pages_get_for_reindexing($next, 10);
Scott committed
94 95

			if (count($pages)) {
Scott committed
96
				require_once QA_INCLUDE_DIR . 'app/format.php';
Scott committed
97

Scott committed
98
				$lastpageid = max(array_keys($pages));
Scott committed
99

Scott committed
100
				foreach ($pages as $pageid => $page) {
Scott committed
101
					if (!($page['flags'] & QA_PAGE_FLAGS_EXTERNAL)) {
Scott committed
102
						$searchmodules = qa_load_modules_with('search', 'unindex_page');
Scott committed
103 104 105
						foreach ($searchmodules as $searchmodule)
							$searchmodule->unindex_page($pageid);

Scott committed
106
						$searchmodules = qa_load_modules_with('search', 'index_page');
Scott committed
107
						if (count($searchmodules)) {
Scott committed
108
							$indextext = qa_viewer_text($page['content'], 'html');
Scott committed
109 110

							foreach ($searchmodules as $searchmodule)
Scott committed
111
								$searchmodule->index_page($pageid, $page['tags'], $page['heading'], $page['content'], 'html', $indextext);
Scott committed
112
						}
Scott committed
113
					}
Scott committed
114
				}
Scott committed
115

Scott committed
116 117 118
				$next = 1 + $lastpageid;
				$done += count($pages);
				$continue = true;
Scott committed
119

Scott committed
120 121 122
			} else
				qa_recalc_transition($state, 'doreindexcontent_postcount');
			break;
Scott committed
123

Scott committed
124 125 126 127
		case 'doreindexcontent_postcount':
			qa_db_qcount_update();
			qa_db_acount_update();
			qa_db_ccount_update();
Scott committed
128

Scott committed
129 130
			qa_recalc_transition($state, 'doreindexcontent_postreindex');
			break;
Scott committed
131

Scott committed
132
		case 'doreindexcontent_postreindex':
Scott committed
133
			$posts = qa_db_posts_get_for_reindexing($next, 10);
Scott committed
134

Scott committed
135
			if (count($posts)) {
Scott committed
136
				require_once QA_INCLUDE_DIR . 'app/format.php';
Scott committed
137

Scott committed
138
				$lastpostid = max(array_keys($posts));
Scott committed
139

Scott committed
140 141
				qa_db_prepare_for_reindexing($next, $lastpostid);
				qa_suspend_update_counts();
Scott committed
142

Scott committed
143 144 145 146
				foreach ($posts as $postid => $post) {
					qa_post_unindex($postid);
					qa_post_index($postid, $post['type'], $post['questionid'], $post['parentid'], $post['title'], $post['content'],
						$post['format'], qa_viewer_text($post['content'], $post['format']), $post['tags'], $post['categoryid']);
Scott committed
147 148
				}

Scott committed
149 150 151
				$next = 1 + $lastpostid;
				$done += count($posts);
				$continue = true;
Scott committed
152

Scott committed
153 154 155 156 157
			} else {
				qa_db_truncate_indexes($next);
				qa_recalc_transition($state, 'doreindexposts_wordcount');
			}
			break;
Scott committed
158

Scott committed
159
		case 'doreindexposts_wordcount':
Scott committed
160
			$wordids = qa_db_words_prepare_for_recounting($next, 1000);
Scott committed
161

Scott committed
162
			if (count($wordids)) {
Scott committed
163
				$lastwordid = max($wordids);
Scott committed
164

Scott committed
165
				qa_db_words_recount($next, $lastwordid);
Scott committed
166

Scott committed
167 168 169
				$next = 1 + $lastwordid;
				$done += count($wordids);
				$continue = true;
Scott committed
170

Scott committed
171 172 173 174 175
			} else {
				qa_db_tagcount_update(); // this is quick so just do it here
				qa_recalc_transition($state, 'doreindexposts_complete');
			}
			break;
Scott committed
176

Scott committed
177 178 179
		case 'dorecountposts':
			qa_recalc_transition($state, 'dorecountposts_postcount');
			break;
Scott committed
180

Scott committed
181 182 183 184 185 186
		case 'dorecountposts_postcount':
			qa_db_qcount_update();
			qa_db_acount_update();
			qa_db_ccount_update();
			qa_db_unaqcount_update();
			qa_db_unselqcount_update();
Scott committed
187

Scott committed
188 189
			qa_recalc_transition($state, 'dorecountposts_votecount');
			break;
Scott committed
190

Scott committed
191
		case 'dorecountposts_votecount':
Scott committed
192
			$postids = qa_db_posts_get_for_recounting($next, 1000);
Scott committed
193

Scott committed
194
			if (count($postids)) {
Scott committed
195
				$lastpostid = max($postids);
Scott committed
196

Scott committed
197
				qa_db_posts_votes_recount($next, $lastpostid);
Scott committed
198

Scott committed
199 200 201
				$next = 1 + $lastpostid;
				$done += count($postids);
				$continue = true;
Scott committed
202

Scott committed
203 204 205
			} else
				qa_recalc_transition($state, 'dorecountposts_acount');
			break;
Scott committed
206

Scott committed
207
		case 'dorecountposts_acount':
Scott committed
208
			$postids = qa_db_posts_get_for_recounting($next, 1000);
Scott committed
209

Scott committed
210
			if (count($postids)) {
Scott committed
211
				$lastpostid = max($postids);
Scott committed
212

Scott committed
213
				qa_db_posts_answers_recount($next, $lastpostid);
Scott committed
214

Scott committed
215 216 217
				$next = 1 + $lastpostid;
				$done += count($postids);
				$continue = true;
Scott committed
218

Scott committed
219 220 221 222 223
			} else {
				qa_db_unupaqcount_update();
				qa_recalc_transition($state, 'dorecountposts_complete');
			}
			break;
Scott committed
224

Scott committed
225 226 227
		case 'dorecalcpoints':
			qa_recalc_transition($state, 'dorecalcpoints_usercount');
			break;
Scott committed
228

Scott committed
229 230 231 232 233
		case 'dorecalcpoints_usercount':
			qa_db_userpointscount_update(); // for progress update - not necessarily accurate
			qa_db_uapprovecount_update(); // needs to be somewhere and this is the most appropriate place
			qa_recalc_transition($state, 'dorecalcpoints_recalc');
			break;
Scott committed
234

Scott committed
235
		case 'dorecalcpoints_recalc':
Scott committed
236 237 238 239
			$recalccount = 10;
			$userids = qa_db_users_get_for_recalc_points($next, $recalccount + 1); // get one extra so we know where to start from next
			$gotcount = count($userids);
			$recalccount = min($recalccount, $gotcount); // can't recalc more than we got
Scott committed
240

Scott committed
241 242
			if ($recalccount > 0) {
				$lastuserid = $userids[$recalccount - 1];
Scott committed
243
				qa_db_users_recalc_points($next, $lastuserid);
Scott committed
244
				$done += $recalccount;
Scott committed
245

Scott committed
246
			} else
Scott committed
247
				$lastuserid = $next; // for truncation
Scott committed
248

Scott committed
249 250 251
			if ($gotcount > $recalccount) { // more left to do
				$next = $userids[$recalccount]; // start next round at first one not recalculated
				$continue = true;
Scott committed
252

Scott committed
253 254 255 256 257 258
			} else {
				qa_db_truncate_userpoints($lastuserid);
				qa_db_userpointscount_update(); // quick so just do it here
				qa_recalc_transition($state, 'dorecalcpoints_complete');
			}
			break;
Scott committed
259

Scott committed
260 261 262
		case 'dorefillevents':
			qa_recalc_transition($state, 'dorefillevents_qcount');
			break;
Scott committed
263

Scott committed
264 265 266 267
		case 'dorefillevents_qcount':
			qa_db_qcount_update();
			qa_recalc_transition($state, 'dorefillevents_refill');
			break;
Scott committed
268

Scott committed
269
		case 'dorefillevents_refill':
Scott committed
270
			$questionids = qa_db_qs_get_for_event_refilling($next, 1);
Scott committed
271

Scott committed
272
			if (count($questionids)) {
Scott committed
273 274 275
				require_once QA_INCLUDE_DIR . 'app/events.php';
				require_once QA_INCLUDE_DIR . 'app/updates.php';
				require_once QA_INCLUDE_DIR . 'util/sort.php';
Scott committed
276

Scott committed
277
				$lastquestionid = max($questionids);
Scott committed
278

Scott committed
279 280
				foreach ($questionids as $questionid) {
					// Retrieve all posts relating to this question
Scott committed
281

Scott committed
282
					list($question, $childposts, $achildposts) = qa_db_select_with_pending(
Scott committed
283 284 285 286
						qa_db_full_post_selectspec(null, $questionid),
						qa_db_full_child_posts_selectspec(null, $questionid),
						qa_db_full_a_child_posts_selectspec(null, $questionid)
					);
Scott committed
287

Scott committed
288
					// Merge all posts while preserving keys as postids
Scott committed
289

Scott committed
290
					$posts = array($questionid => $question);
Scott committed
291

Scott committed
292
					foreach ($childposts as $postid => $post)
Scott committed
293
						$posts[$postid] = $post;
Scott committed
294

Scott committed
295
					foreach ($achildposts as $postid => $post)
Scott committed
296
						$posts[$postid] = $post;
Scott committed
297

Scott committed
298
					// Creation and editing of each post
Scott committed
299

Scott committed
300
					foreach ($posts as $postid => $post) {
Scott committed
301
						$followonq = ($post['basetype'] == 'Q') && ($postid != $questionid);
Scott committed
302

Scott committed
303
						if ($followonq)
Scott committed
304
							$updatetype = QA_UPDATE_FOLLOWS;
Scott committed
305
						elseif ($post['basetype'] == 'C' && @$posts[$post['parentid']]['basetype'] == 'Q')
Scott committed
306
							$updatetype = QA_UPDATE_C_FOR_Q;
Scott committed
307
						elseif ($post['basetype'] == 'C' && @$posts[$post['parentid']]['basetype'] == 'A')
Scott committed
308
							$updatetype = QA_UPDATE_C_FOR_A;
Scott committed
309
						else
Scott committed
310
							$updatetype = null;
Scott committed
311

Scott committed
312
						qa_create_event_for_q_user($questionid, $postid, $updatetype, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']);
Scott committed
313

Scott committed
314 315
						if (isset($post['updated']) && !$followonq)
							qa_create_event_for_q_user($questionid, $postid, $post['updatetype'], $post['lastuserid'], $post['userid'], $post['updated']);
Scott committed
316 317
					}

Scott committed
318
					// Tags and categories of question
Scott committed
319

Scott committed
320 321
					qa_create_event_for_tags($question['tags'], $questionid, null, $question['userid'], $question['created']);
					qa_create_event_for_category($question['categoryid'], $questionid, null, $question['userid'], $question['created']);
Scott committed
322

Scott committed
323
					// Collect comment threads
Scott committed
324

Scott committed
325
					$parentidcomments = array();
Scott committed
326

Scott committed
327
					foreach ($posts as $postid => $post)
Scott committed
328 329
						if ($post['basetype'] == 'C')
							$parentidcomments[$post['parentid']][$postid] = $post;
Scott committed
330

Scott committed
331
					// For each comment thread, notify all previous comment authors of each comment in the thread (could get slow)
Scott committed
332

Scott committed
333
					foreach ($parentidcomments as $parentid => $comments) {
Scott committed
334
						$keyuserids = array();
Scott committed
335

Scott committed
336
						qa_sort_by($comments, 'created');
Scott committed
337

Scott committed
338
						foreach ($comments as $comment) {
Scott committed
339 340
							foreach ($keyuserids as $keyuserid => $dummy) {
								if ($keyuserid != $comment['userid'] && $keyuserid != @$posts[$parentid]['userid']) {
Scott committed
341
									qa_db_event_create_not_entity($keyuserid, $questionid, $comment['postid'], QA_UPDATE_FOLLOWS, $comment['userid'], $comment['created']);
Scott committed
342 343
								}
							}
Scott committed
344

Scott committed
345
							if (isset($comment['userid']))
Scott committed
346
								$keyuserids[$comment['userid']] = true;
Scott committed
347 348
						}
					}
Scott committed
349 350
				}

Scott committed
351 352 353
				$next = 1 + $lastquestionid;
				$done += count($questionids);
				$continue = true;
Scott committed
354

Scott committed
355 356 357
			} else
				qa_recalc_transition($state, 'dorefillevents_complete');
			break;
Scott committed
358

Scott committed
359 360 361
		case 'dorecalccategories':
			qa_recalc_transition($state, 'dorecalccategories_postcount');
			break;
Scott committed
362

Scott committed
363 364 365
		case 'dorecalccategories_postcount':
			qa_db_acount_update();
			qa_db_ccount_update();
Scott committed
366

Scott committed
367 368
			qa_recalc_transition($state, 'dorecalccategories_postupdate');
			break;
Scott committed
369

Scott committed
370
		case 'dorecalccategories_postupdate':
Scott committed
371
			$postids = qa_db_posts_get_for_recategorizing($next, 100);
Scott committed
372

Scott committed
373
			if (count($postids)) {
Scott committed
374
				$lastpostid = max($postids);
Scott committed
375

Scott committed
376 377
				qa_db_posts_recalc_categoryid($next, $lastpostid);
				qa_db_posts_calc_category_path($next, $lastpostid);
Scott committed
378

Scott committed
379 380 381
				$next = 1 + $lastpostid;
				$done += count($postids);
				$continue = true;
Scott committed
382

Scott committed
383 384 385 386
			} else {
				qa_recalc_transition($state, 'dorecalccategories_recount');
			}
			break;
Scott committed
387

Scott committed
388
		case 'dorecalccategories_recount':
Scott committed
389
			$categoryids = qa_db_categories_get_for_recalcs($next, 10);
Scott committed
390

Scott committed
391
			if (count($categoryids)) {
Scott committed
392
				$lastcategoryid = max($categoryids);
Scott committed
393

Scott committed
394 395
				foreach ($categoryids as $categoryid)
					qa_db_ifcategory_qcount_update($categoryid);
Scott committed
396

Scott committed
397 398 399
				$next = 1 + $lastcategoryid;
				$done += count($categoryids);
				$continue = true;
Scott committed
400

Scott committed
401 402 403 404
			} else {
				qa_recalc_transition($state, 'dorecalccategories_backpaths');
			}
			break;
Scott committed
405

Scott committed
406
		case 'dorecalccategories_backpaths':
Scott committed
407
			$categoryids = qa_db_categories_get_for_recalcs($next, 10);
Scott committed
408

Scott committed
409
			if (count($categoryids)) {
Scott committed
410
				$lastcategoryid = max($categoryids);
Scott committed
411

Scott committed
412
				qa_db_categories_recalc_backpaths($next, $lastcategoryid);
Scott committed
413

Scott committed
414 415 416
				$next = 1 + $lastcategoryid;
				$done += count($categoryids);
				$continue = true;
Scott committed
417

Scott committed
418 419 420 421
			} else {
				qa_recalc_transition($state, 'dorecalccategories_complete');
			}
			break;
Scott committed
422

Scott committed
423 424 425
		case 'dodeletehidden':
			qa_recalc_transition($state, 'dodeletehidden_comments');
			break;
Scott committed
426

Scott committed
427
		case 'dodeletehidden_comments':
Scott committed
428
			$posts = qa_db_posts_get_for_deleting('C', $next, 1);
Scott committed
429

Scott committed
430
			if (count($posts)) {
Scott committed
431
				require_once QA_INCLUDE_DIR . 'app/posts.php';
Scott committed
432

Scott committed
433
				$postid = $posts[0];
Scott committed
434

Scott committed
435
				qa_post_delete($postid);
Scott committed
436

Scott committed
437
				$next = 1 + $postid;
Scott committed
438
				$done++;
Scott committed
439
				$continue = true;
Scott committed
440

Scott committed
441 442 443
			} else
				qa_recalc_transition($state, 'dodeletehidden_answers');
			break;
Scott committed
444

Scott committed
445
		case 'dodeletehidden_answers':
Scott committed
446
			$posts = qa_db_posts_get_for_deleting('A', $next, 1);
Scott committed
447

Scott committed
448
			if (count($posts)) {
Scott committed
449
				require_once QA_INCLUDE_DIR . 'app/posts.php';
Scott committed
450

Scott committed
451
				$postid = $posts[0];
Scott committed
452

Scott committed
453
				qa_post_delete($postid);
Scott committed
454

Scott committed
455
				$next = 1 + $postid;
Scott committed
456
				$done++;
Scott committed
457
				$continue = true;
Scott committed
458

Scott committed
459 460 461
			} else
				qa_recalc_transition($state, 'dodeletehidden_questions');
			break;
Scott committed
462

Scott committed
463
		case 'dodeletehidden_questions':
Scott committed
464
			$posts = qa_db_posts_get_for_deleting('Q', $next, 1);
Scott committed
465

Scott committed
466
			if (count($posts)) {
Scott committed
467
				require_once QA_INCLUDE_DIR . 'app/posts.php';
Scott committed
468

Scott committed
469
				$postid = $posts[0];
Scott committed
470

Scott committed
471
				qa_post_delete($postid);
Scott committed
472

Scott committed
473
				$next = 1 + $postid;
Scott committed
474
				$done++;
Scott committed
475
				$continue = true;
Scott committed
476

Scott committed
477 478 479
			} else
				qa_recalc_transition($state, 'dodeletehidden_complete');
			break;
Scott committed
480

Scott committed
481 482 483
		case 'doblobstodisk':
			qa_recalc_transition($state, 'doblobstodisk_move');
			break;
Scott committed
484

Scott committed
485
		case 'doblobstodisk_move':
Scott committed
486
			$blob = qa_db_get_next_blob_in_db($next);
Scott committed
487

Scott committed
488
			if (isset($blob)) {
Scott committed
489 490
				require_once QA_INCLUDE_DIR . 'app/blobs.php';
				require_once QA_INCLUDE_DIR . 'db/blobs.php';
Scott committed
491

Scott committed
492 493
				if (qa_write_blob_file($blob['blobid'], $blob['content'], $blob['format']))
					qa_db_blob_set_content($blob['blobid'], null);
Scott committed
494

Scott committed
495
				$next = 1 + $blob['blobid'];
Scott committed
496
				$done++;
Scott committed
497
				$continue = true;
Scott committed
498

Scott committed
499 500 501
			} else
				qa_recalc_transition($state, 'doblobstodisk_complete');
			break;
Scott committed
502

Scott committed
503 504 505
		case 'doblobstodb':
			qa_recalc_transition($state, 'doblobstodb_move');
			break;
Scott committed
506

Scott committed
507
		case 'doblobstodb_move':
Scott committed
508
			$blob = qa_db_get_next_blob_on_disk($next);
Scott committed
509

Scott committed
510
			if (isset($blob)) {
Scott committed
511 512
				require_once QA_INCLUDE_DIR . 'app/blobs.php';
				require_once QA_INCLUDE_DIR . 'db/blobs.php';
Scott committed
513

Scott committed
514
				$content = qa_read_blob_file($blob['blobid'], $blob['format']);
Scott committed
515 516
				qa_db_blob_set_content($blob['blobid'], $content);
				qa_delete_blob_file($blob['blobid'], $blob['format']);
Scott committed
517

Scott committed
518
				$next = 1 + $blob['blobid'];
Scott committed
519
				$done++;
Scott committed
520
				$continue = true;
521

Scott committed
522 523 524
			} else
				qa_recalc_transition($state, 'doblobstodb_complete');
			break;
525

Scott committed
526 527 528
		case 'docachetrim':
			qa_recalc_transition($state, 'docachetrim_process');
			break;
Scott committed
529 530 531 532
		case 'docacheclear':
			qa_recalc_transition($state, 'docacheclear_process');
			break;

Scott committed
533
		case 'docachetrim_process':
Scott committed
534 535 536
		case 'docacheclear_process':
			$cacheDriver = Q2A_Storage_CacheFactory::getCacheDriver();
			$cacheStats = $cacheDriver->getStats();
Scott committed
537
			$limit = min($cacheStats['files'], 20);
Scott committed
538

Scott committed
539 540
			if ($cacheStats['files'] > 0 && $next <= $length) {
				$deleted = $cacheDriver->clear($limit, $next, ($operation === 'docachetrim_process'));
Scott committed
541
				$done += $deleted;
Scott committed
542
				$next += $limit - $deleted; // skip files that weren't deleted on next iteration
Scott committed
543 544 545 546 547 548
				$continue = true;
			} else {
				qa_recalc_transition($state, 'docacheclear_complete');
			}
			break;

Scott committed
549
		default:
Scott committed
550
			$state = '';
Scott committed
551 552
			break;
	}
553

Scott committed
554
	if ($continue)
Scott committed
555
		$state = $operation . "\t" . $length . "\t" . $next . "\t" . $done;
556

Scott committed
557
	return $continue && $done < $length;
Scott committed
558 559 560 561 562
}


/**
 * Change the $state to represent the beginning of a new $operation
Scott committed
563 564
 * @param $state
 * @param $operation
Scott committed
565 566 567
 */
function qa_recalc_transition(&$state, $operation)
{
Scott committed
568 569 570
	$length = qa_recalc_stage_length($operation);
	$next = (QA_FINAL_EXTERNAL_USERS && ($operation == 'dorecalcpoints_recalc')) ? '' : 0;
	$done = 0;
Scott committed
571

Scott committed
572
	$state = $operation . "\t" . $length . "\t" . $next . "\t" . $done;
Scott committed
573 574 575 576 577
}


/**
 * Return how many steps there will be in recalculation $operation
Scott committed
578 579
 * @param $operation
 * @return int
Scott committed
580 581 582 583 584
 */
function qa_recalc_stage_length($operation)
{
	switch ($operation) {
		case 'doreindexcontent_pagereindex':
Scott committed
585
			$length = qa_db_count_pages();
Scott committed
586 587 588
			break;

		case 'doreindexcontent_postreindex':
Scott committed
589
			$length = qa_opt('cache_qcount') + qa_opt('cache_acount') + qa_opt('cache_ccount');
Scott committed
590 591 592
			break;

		case 'doreindexposts_wordcount':
Scott committed
593
			$length = qa_db_count_words();
Scott committed
594 595 596
			break;

		case 'dorecalcpoints_recalc':
Scott committed
597
			$length = qa_opt('cache_userpointscount');
Scott committed
598 599 600 601 602
			break;

		case 'dorecountposts_votecount':
		case 'dorecountposts_acount':
		case 'dorecalccategories_postupdate':
Scott committed
603
			$length = qa_db_count_posts();
Scott committed
604 605 606
			break;

		case 'dorefillevents_refill':
Scott committed
607
			$length = qa_opt('cache_qcount') + qa_db_count_posts('Q_HIDDEN');
Scott committed
608 609 610 611
			break;

		case 'dorecalccategories_recount':
		case 'dorecalccategories_backpaths':
Scott committed
612
			$length = qa_db_count_categories();
Scott committed
613 614 615
			break;

		case 'dodeletehidden_comments':
Scott committed
616
			$length = count(qa_db_posts_get_for_deleting('C'));
Scott committed
617 618 619
			break;

		case 'dodeletehidden_answers':
Scott committed
620
			$length = count(qa_db_posts_get_for_deleting('A'));
Scott committed
621 622 623
			break;

		case 'dodeletehidden_questions':
Scott committed
624
			$length = count(qa_db_posts_get_for_deleting('Q'));
Scott committed
625 626 627
			break;

		case 'doblobstodisk_move':
Scott committed
628
			$length = qa_db_count_blobs_in_db();
Scott committed
629 630 631
			break;

		case 'doblobstodb_move':
Scott committed
632
			$length = qa_db_count_blobs_on_disk();
Scott committed
633 634
			break;

Scott committed
635 636 637 638 639 640 641
		case 'docachetrim_process':
		case 'docacheclear_process':
			$cacheDriver = Q2A_Storage_CacheFactory::getCacheDriver();
			$cacheStats = $cacheDriver->getStats();
			$length = $cacheStats['files'];
			break;

Scott committed
642
		default:
Scott committed
643
			$length = 0;
Scott committed
644
			break;
Scott committed
645 646
	}

Scott committed
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
	return $length;
}


/**
 * Return the translated language ID string replacing the progress and total in it.
 * @access private
 * @param string $langId Language string ID that contains 2 placeholders (^1 and ^2)
 * @param int $progress Amount of processed elements
 * @param int $total Total amount of elements
 *
 * @return string Returns the language string ID with their placeholders replaced with
 * the formatted progress and total numbers
 */
function qa_recalc_progress_lang($langId, $progress, $total)
{
	return strtr(qa_lang($langId), array(
		'^1' => qa_format_number($progress),
Scott committed
665
		'^2' => qa_format_number($total),
Scott committed
666 667 668 669 670 671
	));
}


/**
 * Return a string which gives a user-viewable version of $state
Scott committed
672 673
 * @param $state
 * @return string
Scott committed
674 675 676 677 678 679 680
 */
function qa_recalc_get_message($state)
{
	require_once QA_INCLUDE_DIR . 'app/format.php';

	@list($operation, $length, $next, $done) = explode("\t", $state);

Scott committed
681 682
	$done = (int)$done;
	$length = (int)$length;
Scott committed
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781

	switch ($operation) {
		case 'doreindexcontent_postcount':
		case 'dorecountposts_postcount':
		case 'dorecalccategories_postcount':
		case 'dorefillevents_qcount':
			$message = qa_lang('admin/recalc_posts_count');
			break;

		case 'doreindexcontent_pagereindex':
			$message = qa_recalc_progress_lang('admin/reindex_pages_reindexed', $done, $length);
			break;

		case 'doreindexcontent_postreindex':
			$message = qa_recalc_progress_lang('admin/reindex_posts_reindexed', $done, $length);
			break;

		case 'doreindexposts_complete':
			$message = qa_lang('admin/reindex_posts_complete');
			break;

		case 'doreindexposts_wordcount':
			$message = qa_recalc_progress_lang('admin/reindex_posts_wordcounted', $done, $length);
			break;

		case 'dorecountposts_votecount':
			$message = qa_recalc_progress_lang('admin/recount_posts_votes_recounted', $done, $length);
			break;

		case 'dorecountposts_acount':
			$message = qa_recalc_progress_lang('admin/recount_posts_as_recounted', $done, $length);
			break;

		case 'dorecountposts_complete':
			$message = qa_lang('admin/recount_posts_complete');
			break;

		case 'dorecalcpoints_usercount':
			$message = qa_lang('admin/recalc_points_usercount');
			break;

		case 'dorecalcpoints_recalc':
			$message = qa_recalc_progress_lang('admin/recalc_points_recalced', $done, $length);
			break;

		case 'dorecalcpoints_complete':
			$message = qa_lang('admin/recalc_points_complete');
			break;

		case 'dorefillevents_refill':
			$message = qa_recalc_progress_lang('admin/refill_events_refilled', $done, $length);
			break;

		case 'dorefillevents_complete':
			$message = qa_lang('admin/refill_events_complete');
			break;

		case 'dorecalccategories_postupdate':
			$message = qa_recalc_progress_lang('admin/recalc_categories_updated', $done, $length);
			break;

		case 'dorecalccategories_recount':
			$message = qa_recalc_progress_lang('admin/recalc_categories_recounting', $done, $length);
			break;

		case 'dorecalccategories_backpaths':
			$message = qa_recalc_progress_lang('admin/recalc_categories_backpaths', $done, $length);
			break;

		case 'dorecalccategories_complete':
			$message = qa_lang('admin/recalc_categories_complete');
			break;

		case 'dodeletehidden_comments':
			$message = qa_recalc_progress_lang('admin/hidden_comments_deleted', $done, $length);
			break;

		case 'dodeletehidden_answers':
			$message = qa_recalc_progress_lang('admin/hidden_answers_deleted', $done, $length);
			break;

		case 'dodeletehidden_questions':
			$message = qa_recalc_progress_lang('admin/hidden_questions_deleted', $done, $length);
			break;

		case 'dodeletehidden_complete':
			$message = qa_lang('admin/delete_hidden_complete');
			break;

		case 'doblobstodisk_move':
		case 'doblobstodb_move':
			$message = qa_recalc_progress_lang('admin/blobs_move_moved', $done, $length);
			break;

		case 'doblobstodisk_complete':
		case 'doblobstodb_complete':
			$message = qa_lang('admin/blobs_move_complete');
			break;

Scott committed
782 783 784 785 786 787 788 789 790
		case 'docachetrim_process':
		case 'docacheclear_process':
			$message = qa_recalc_progress_lang('admin/caching_delete_progress', $done, $length);
			break;

		case 'docacheclear_complete':
			$message = qa_lang('admin/caching_delete_complete');
			break;

Scott committed
791 792 793 794
		default:
			$message = '';
			break;
	}
Scott committed
795

Scott committed
796 797
	return $message;
}