r84535 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r84534‎ | r84535 | r84536 >
Date:17:18, 22 March 2011
Author:tparscal
Status:reverted (Comments)
Tags:
Comment:
Step 2 of 2 for implementing expirations.
* Added revision column to page table which is part of the primary key
* Modified ApiQueryArticleFeedback to sum up counts and totals for all valid revisions
* Modified ApiArticleFeedback to automatically subtract totals and counts from previous revision's tally
Modified paths:
  • /trunk/extensions/ArticleFeedback/ArticleFeedback.hooks.php (modified) (history)
  • /trunk/extensions/ArticleFeedback/api/ApiArticleFeedback.php (modified) (history)
  • /trunk/extensions/ArticleFeedback/api/ApiQueryArticleFeedback.php (modified) (history)
  • /trunk/extensions/ArticleFeedback/sql/AddPageRevisionColumn.sql (added) (history)
  • /trunk/extensions/ArticleFeedback/sql/ArticleFeedback.sql (modified) (history)

Diff [purge]

Index: trunk/extensions/ArticleFeedback/api/ApiArticleFeedback.php
@@ -45,7 +45,8 @@
4646 $lastRatings = array();
4747
4848 foreach ( $res as $row ) {
49 - $lastRatings[$row->aa_rating_id] = $row->aa_rating_value;
 49+ $lastRatings[$row->aa_rating_id]['value'] = $row->aa_rating_value;
 50+ $lastRatings[$row->aa_rating_id]['revision'] = $row->aa_revision;
5051 }
5152
5253 $pageId = $params['pageid'];
@@ -54,7 +55,8 @@
5556 foreach( $wgArticleFeedbackRatings as $rating ) {
5657 $lastRating = false;
5758 if ( isset( $lastRatings[$rating] ) ) {
58 - $lastRating = intval( $lastRatings[$rating] );
 59+ $lastRating = intval( $lastRatings[$rating]['value'] );
 60+ $lastRevision = intval( $lastRatings[$rating]['revision'] );
5961 }
6062
6163 $thisRating = false;
@@ -62,7 +64,7 @@
6365 $thisRating = intval( $params["r{$rating}"] );
6466 }
6567
66 - $this->insertPageRating( $pageId, $rating, ( $thisRating - $lastRating ),
 68+ $this->insertPageRating( $pageId, $revisionId, $lastRevision, $rating, ( $thisRating - $lastRating ),
6769 $thisRating, $lastRating
6870 );
6971
@@ -79,32 +81,15 @@
8082 * Inserts (or Updates, where appropriate) the aggregate page rating
8183 *
8284 * @param $pageId Integer: Page Id
 85+ * @param $revisionId Integer: Revision Id
8386 * @param $ratingId Integer: Rating Id
8487 * @param $updateAddition Integer: Difference between user's last rating (if applicable)
8588 * @param $thisRating Integer|Boolean: Value of the Rating
8689 * @param $lastRating Integer|Boolean: Value of the last Rating
8790 */
88 - private function insertPageRating( $pageId, $ratingId, $updateAddition, $thisRating, $lastRating ) {
 91+ private function insertPageRating( $pageId, $revisionId, $lastRevision, $ratingId, $updateAddition, $thisRating, $lastRating ) {
8992 $dbw = wfGetDB( DB_MASTER );
9093
91 - // 0 == No change in rating count
92 - // 1 == No rating last time (or new rating), and now there is
93 - // -1 == Rating last time, but abstained this time
94 - $countChange = 0;
95 - if ( $lastRating === false || $lastRating === 0 ) {
96 - if ( $thisRating === 0 ) {
97 - $countChange = 0;
98 - } else {
99 - $countChange = 1;
100 - }
101 - } else { // Last rating was > 0
102 - if ( $thisRating === 0 ) {
103 - $countChange = -1;
104 - } else {
105 - $countChange = 0;
106 - }
107 - }
108 -
10994 $dbw->insert(
11095 'article_feedback_pages',
11196 array(
@@ -112,23 +97,73 @@
11398 'aap_total' => 0,
11499 'aap_count' => 0,
115100 'aap_rating_id' => $ratingId,
 101+ 'aap_revision' => $revisionId,
116102 ),
117103 __METHOD__,
118104 array( 'IGNORE' )
119105 );
120106
121 - $dbw->update(
122 - 'article_feedback_pages',
123 - array(
124 - 'aap_total = aap_total + ' . $updateAddition,
125 - 'aap_count = aap_count + ' . $countChange,
126 - ),
127 - array(
128 - 'aap_page_id' => $pageId,
129 - 'aap_rating_id' => $ratingId,
130 - ),
131 - __METHOD__
132 - );
 107+ if ( $dbw->affectedRows() ) {
 108+ if ( $lastRating ) {
 109+ $dbw->update(
 110+ 'article_feedback_pages',
 111+ array(
 112+ 'aap_total = aap_total - ' . intval( $lastRating ),
 113+ 'aap_count = aap_count - 1',
 114+ ),
 115+ array(
 116+ 'aap_page_id' => $pageId,
 117+ 'aap_rating_id' => $ratingId,
 118+ 'aap_revision' => $lastRevision
 119+ ),
 120+ __METHOD__
 121+ );
 122+ }
 123+ $dbw->update(
 124+ 'article_feedback_pages',
 125+ array(
 126+ 'aap_total' => $thisRating,
 127+ 'aap_count' => 1,
 128+ ),
 129+ array(
 130+ 'aap_page_id' => $pageId,
 131+ 'aap_rating_id' => $ratingId,
 132+ 'aap_revision' => $revisionId,
 133+ ),
 134+ __METHOD__
 135+ );
 136+ } else {
 137+ // 0 == No change in rating count
 138+ // 1 == No rating last time (or new rating), and now there is
 139+ // -1 == Rating last time, but abstained this time
 140+ $countChange = 0;
 141+ if ( $lastRating === false || $lastRating === 0 ) {
 142+ if ( $thisRating === 0 ) {
 143+ $countChange = 0;
 144+ } else {
 145+ $countChange = 1;
 146+ }
 147+ } else { // Last rating was > 0
 148+ if ( $thisRating === 0 ) {
 149+ $countChange = -1;
 150+ } else {
 151+ $countChange = 0;
 152+ }
 153+ }
 154+ $dbw->update(
 155+ 'article_feedback_pages',
 156+ array(
 157+ 'aap_total = aap_total + ' . $updateAddition,
 158+ 'aap_count = aap_count + ' . $countChange,
 159+ ),
 160+ array(
 161+ 'aap_page_id' => $pageId,
 162+ 'aap_rating_id' => $ratingId,
 163+ 'aap_revision' => $revisionId,
 164+ ),
 165+ __METHOD__
 166+ );
 167+ }
133168 }
134169
135170 /**
@@ -153,12 +188,12 @@
154189 'aa_page_id' => $pageId,
155190 'aa_user_id' => $user->getId(),
156191 'aa_user_text' => $user->getName(),
 192+ 'aa_user_anon_token' => $token,
157193 'aa_revision' => $revisionId,
158194 'aa_timestamp' => $timestamp,
159195 'aa_rating_id' => $ratingId,
160196 'aa_rating_value' => $ratingValue,
161197 'aa_design_bucket' => $bucket,
162 - 'aa_user_anon_token' => $token
163198 ),
164199 __METHOD__,
165200 array( 'IGNORE' )
@@ -176,7 +211,7 @@
177212 'aa_user_text' => $user->getName(),
178213 'aa_revision' => $revisionId,
179214 'aa_rating_id' => $ratingId,
180 - 'aa_user_anon_token' => $token
 215+ 'aa_user_anon_token' => $token,
181216 ),
182217 __METHOD__
183218 );
Index: trunk/extensions/ArticleFeedback/api/ApiQueryArticleFeedback.php
@@ -10,9 +10,13 @@
1111
1212 $result = $this->getResult();
1313
 14+ $revisionLimit = self::getRevisionLimit( $params['pageid'] );
 15+
1416 $this->addTables( array( 'article_feedback_pages', 'article_feedback_ratings' ) );
1517
16 - $this->addFields( array( 'aap_page_id', 'aap_total', 'aap_count', 'aap_rating_id', 'aar_rating' ) );
 18+ $this->addFields( array(
 19+ 'aap_page_id', 'SUM(aap_total) as aap_total', 'SUM(aap_count) as aap_count', 'aap_rating_id', 'aar_rating'
 20+ ) );
1721
1822 $this->addJoinConds( array(
1923 'article_feedback_ratings' => array( 'LEFT JOIN', array(
@@ -23,7 +27,11 @@
2428 ) );
2529
2630 $this->addWhereFld( 'aap_page_id', $params['pageid'] );
 31+ $this->addWhereFld( 'aap_revision > ' . $revisionLimit );
2732
 33+ $this->addOption( 'GROUP BY', 'aap_rating_id' );
 34+ $this->addOption( 'LIMIT', count( $wgArticleFeedbackRatings ) );
 35+
2836 if ( $params['userrating'] ) {
2937 global $wgUser;
3038
@@ -43,7 +51,6 @@
4452 } elseif ( strlen( $params['anontoken'] ) != 32 ) {
4553 $this->dieUsage( 'The anontoken is not 32 characters', 'invalidtoken' );
4654 }
47 -
4855 $leftJoinCondsAF['aa_user_anon_token'] = $params['anontoken'];
4956 } else {
5057 $leftJoinCondsAF['aa_user_anon_token'] = '';
@@ -61,8 +68,6 @@
6269 $this->addOption( 'ORDER BY', 'aa_revision DESC' );
6370 }
6471
65 - $this->addOption( 'LIMIT', count( $wgArticleFeedbackRatings ) );
66 -
6772 $res = $this->select( __METHOD__ );
6873
6974 $ratings = array();
@@ -106,13 +111,12 @@
107112 // Ratings can only be expired if the user has rated before
108113 $ratings[$params['pageid']]['status'] = 'current';
109114 if ( $params['userrating'] && $userRatedArticle ) {
110 - $dbr = wfGetDb( DB_SLAVE );
111 -
112115 global $wgArticleFeedbackRatingLifetime;
113116
114 - $res = $dbr->select(
 117+ $dbr = wfGetDb( DB_SLAVE );
 118+ $updates = $dbr->selectField(
115119 'revision',
116 - 'rev_id',
 120+ 'COUNT(rev_id) as revisions',
117121 array(
118122 'rev_page' => $params['pageid'],
119123 'rev_id > ' . $ratings[$pageId]['revid']
@@ -120,13 +124,12 @@
121125 __METHOD__,
122126 array ( 'LIMIT', $wgArticleFeedbackStaleCount + 1 )
123127 );
124 -
125 - if ( $res && $dbr->numRows( $res ) > $wgArticleFeedbackRatingLifetime ) {
 128+ if ( $updates > $wgArticleFeedbackRatingLifetime ) {
126129 // Expired status
127130 $ratings[$params['pageid']]['status'] = 'expired';
128131 }
129132 }
130 -
 133+
131134 foreach ( $ratings as $rat ) {
132135 $result->setIndexedTagName( $rat['ratings'], 'r' );
133136 $result->addValue( array( 'query', $this->getModuleName() ), null, $rat );
@@ -135,6 +138,33 @@
136139 $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'aa' );
137140 }
138141
 142+ /**
 143+ * Get the revision number of the oldest revision still being counted in totals.
 144+ *
 145+ * @param $pageId Integer: ID of page to check revisions for
 146+ * @return Integer: Oldest valid revision number or 0 of all revisions are valid
 147+ */
 148+ protected static function getRevisionLimit( $pageId ) {
 149+ global $wgArticleFeedbackRatingLifetime;
 150+
 151+ $dbr = wfGetDb( DB_SLAVE );
 152+ $revision = $dbr->selectField(
 153+ 'revision',
 154+ 'rev_id',
 155+ array( 'rev_page' => $pageId ),
 156+ __METHOD__,
 157+ array(
 158+ 'ORDER BY' => 'rev_id DESC',
 159+ 'LIMIT' => 1,
 160+ 'OFFSET' => $wgArticleFeedbackRatingLifetime - 1
 161+ )
 162+ );
 163+ if ( $revision ) {
 164+ return intval( $revision );
 165+ }
 166+ return 0;
 167+ }
 168+
139169 public function getAllowedParams() {
140170 return array(
141171 'pageid' => array(
Index: trunk/extensions/ArticleFeedback/sql/AddPageRevisionColumn.sql
@@ -0,0 +1,4 @@
 2+ALTER TABLE /*_*/article_feedback_pages
 3+ ADD aap_revision integer unsigned NOT NULL,
 4+ DROP PRIMARY KEY,
 5+ ADD PRIMARY KEY (aap_page_id, aap_rating_id, aap_revision);
\ No newline at end of file
Index: trunk/extensions/ArticleFeedback/sql/ArticleFeedback.sql
@@ -34,12 +34,15 @@
3535 -- 1 vote per user per revision
3636 PRIMARY KEY (aa_revision, aa_user_text, aa_rating_id, aa_user_anon_token)
3737 ) /*$wgDBTableOptions*/;
38 -CREATE INDEX /*i*/aa_user_page_revision ON /*_*/article_feedback (aa_user_id, aa_page_id, aa_revision);
 38+CREATE INDEX /*i*/aa_user_page_revision ON /*_*/article_feedback
 39+ (aa_user_id, aa_page_id, aa_revision);
3940
4041 -- Aggregate rating table for a page
4142 CREATE TABLE IF NOT EXISTS /*_*/article_feedback_pages (
4243 -- Foreign key to page.page_id
4344 aap_page_id integer unsigned NOT NULL,
 45+ -- Revision that totals are relevant to
 46+ aap_revision integer unsigned NOT NULL,
4447 -- Foreign key to article_feedback_ratings.aar_rating
4548 aap_rating_id integer unsigned NOT NULL,
4649 -- Sum (total) of all the ratings for this article revision
@@ -47,7 +50,7 @@
4851 -- Number of ratings
4952 aap_count integer unsigned NOT NULL,
5053 -- One rating row per page
51 - PRIMARY KEY (aap_page_id, aap_rating_id)
 54+ PRIMARY KEY (aap_page_id, aap_rating_id, aap_revision)
5255 ) /*$wgDBTableOptions*/;
5356
5457 -- Properties table for meta information
@@ -57,7 +60,6 @@
5861 afp_revision integer unsigned NOT NULL,
5962 afp_user_text varbinary(255) NOT NULL,
6063 afp_user_anon_token varbinary(32) NOT NULL DEFAULT '',
61 -
6264 -- Key/value pairs
6365 afp_key varbinary(255) NOT NULL,
6466 -- Integer value
@@ -65,4 +67,5 @@
6668 -- Text value
6769 afp_value_text varbinary(255) DEFAULT '' NOT NULL
6870 ) /*$wgDBTableOptions*/;
69 -CREATE UNIQUE INDEX /*i*/afp_rating_key ON /*_*/article_feedback_properties (afp_revision, afp_user_text, afp_user_anon_token, afp_key);
 71+CREATE UNIQUE INDEX /*i*/afp_rating_key ON /*_*/article_feedback_properties
 72+ (afp_revision, afp_user_text, afp_user_anon_token, afp_key);
Index: trunk/extensions/ArticleFeedback/ArticleFeedback.hooks.php
@@ -137,6 +137,15 @@
138138 true
139139 ) );
140140 }
 141+ if ( !$db->fieldExists( 'article_feedback_pages', 'aap_revision', __METHOD__ ) ) {
 142+ $updater->addExtensionUpdate( array(
 143+ 'addField',
 144+ 'article_feedback_pages',
 145+ 'aap_revision',
 146+ $dir . '/sql/AddPageRevisionColumn.sql',
 147+ true
 148+ ) );
 149+ }
141150 $updater->addExtensionUpdate( array(
142151 'addTable',
143152 'article_feedback_properties',
@@ -156,7 +165,7 @@
157166 }
158167 return true;
159168 }
160 -
 169+
161170 /**
162171 * ParserTestTables hook
163172 */

Follow-up revisions

RevisionCommit summaryAuthorDate
r84537Added documentation for parameter added to insertPageRating in r84535.tparscal17:24, 22 March 2011
r84623Added comments to help make it easier to understand the program flow - see r8...tparscal18:57, 23 March 2011
r84627Fixes issues in r84535...tparscal19:28, 23 March 2011
r84629Added comments to $pageId and $rev variables within a loop to help improve co...tparscal19:45, 23 March 2011
r84637Fixes more issues in r84535...tparscal21:52, 23 March 2011
r85964ArticleFeedback: Revert most of r84535, removing aap_revision again. This wil...catrope17:58, 13 April 2011

Comments

#Comment by Catrope (talk | contribs)   20:18, 22 March 2011

The logic in ApiArticleFeedback::insertPageRating() looks a bit wrong. Basically it looks like this:

try to insert article_feedback_pages row
if ( it wasn't there yet ) {
	if ( there was a previous rating ) { // how can that even happen? There was no pre-existing afp row!
		subtract the last rating from aap_total // how? That row doesn't exist, remember?
		subtract one from aap_count // same
	}
	update the afp table to set count to 1
		and rating to the current rating // can't do this with update, I guess you mean insert. Also overwrites the updates above, if they hadn't been impossible in the first place
} else {
	update the rating and count in the existing row as appropriate // this part is fine
}
#Comment by Catrope (talk | contribs)   21:27, 22 March 2011

Rereading the code, it turns out it all makes complete sense. I must've been smoking something.

#Comment by Catrope (talk | contribs)   20:26, 22 March 2011
-			$res = $dbr->select(
+			$dbr = wfGetDb( DB_SLAVE );
+			$updates = $dbr->selectField(
 				'revision',
-				'rev_id',
+				'COUNT(rev_id) as revisions',
 				array(
 					'rev_page' => $params['pageid'],
 					'rev_id > ' . $ratings[$pageId]['revid']
@@ -120,13 +124,12 @@
 				__METHOD__,
 				array ( 'LIMIT', $wgArticleFeedbackStaleCount + 1 )
 			);
-
-			if ( $res && $dbr->numRows( $res ) > $wgArticleFeedbackRatingLifetime ) {
+			if ( $updates > $wgArticleFeedbackRatingLifetime ) {

This checks whether the old rating is stale by counting how many revisions there were between the current revision and the old one. This is unacceptable, since the number of revisions in between may be arbitrarily large. Also, LIMIT doesn't work the way you think it does when combined with COUNT(). You don't even need this stuff either, since you already have getRevisionLimit(): use it.

Status & tagging log