r87164 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r87163‎ | r87164 | r87165 >
Date:14:08, 30 April 2011
Author:ialex
Status:resolved (Comments)
Tags:brion 
Comment:
Recommit r87129 and follow-ups but with a fix for the bug Brion found (sorry)
Modified paths:
  • /trunk/phase3/RELEASE-NOTES (modified) (history)
  • /trunk/phase3/includes/Article.php (modified) (history)
  • /trunk/phase3/includes/GlobalFunctions.php (modified) (history)
  • /trunk/phase3/includes/User.php (modified) (history)
  • /trunk/phase3/includes/db/Database.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/User.php
@@ -157,10 +157,13 @@
158158 /**
159159 * Bool Whether the cache variables have been loaded.
160160 */
161 - var $mDataLoaded, $mAuthLoaded, $mOptionsLoaded;
 161+ //@{
 162+ var $mOptionsLoaded;
 163+ private $mLoadedItems = array();
 164+ //@}
162165
163166 /**
164 - * String Initialization data source if mDataLoaded==false. May be one of:
 167+ * String Initialization data source if mLoadedItems!==true. May be one of:
165168 * - 'defaults' anonymous user initialised from class defaults
166169 * - 'name' initialise from mName
167170 * - 'id' initialise from mId
@@ -211,13 +214,13 @@
212215 * Load the user table data for this object from the source given by mFrom.
213216 */
214217 function load() {
215 - if ( $this->mDataLoaded ) {
 218+ if ( $this->mLoadedItems === true ) {
216219 return;
217220 }
218221 wfProfileIn( __METHOD__ );
219222
220223 # Set it now to avoid infinite recursion in accessors
221 - $this->mDataLoaded = true;
 224+ $this->mLoadedItems = true;
222225
223226 switch ( $this->mFrom ) {
224227 case 'defaults':
@@ -336,6 +339,7 @@
337340 $u = new User;
338341 $u->mName = $name;
339342 $u->mFrom = 'name';
 343+ $u->setItemLoaded( 'name' );
340344 return $u;
341345 }
342346 }
@@ -350,6 +354,7 @@
351355 $u = new User;
352356 $u->mId = $id;
353357 $u->mFrom = 'id';
 358+ $u->setItemLoaded( 'id' );
354359 return $u;
355360 }
356361
@@ -390,7 +395,14 @@
391396
392397 /**
393398 * Create a new user object from a user row.
394 - * The row should have all fields from the user table in it.
 399+ * The row should have the following fields from the user table in it:
 400+ * - either user_name or user_id to load further data if needed (or both)
 401+ * - user_real_name
 402+ * - all other fields (email, password, etc.)
 403+ * It is useless to provide the remaining fields if either user_id,
 404+ * user_name and user_real_name are not provided because the whole row
 405+ * will be loaded once more from the database when accessing them.
 406+ *
395407 * @param $row Array A row from the user table
396408 * @return User
397409 */
@@ -847,6 +859,34 @@
848860 }
849861
850862 /**
 863+ * Return whether an item has been loaded.
 864+ *
 865+ * @param $item String: item to check. Current possibilities:
 866+ * - id
 867+ * - name
 868+ * - realname
 869+ * @param $all String: 'all' to check if the whole object has been loaded
 870+ * or any other string to check if only the item is available (e.g.
 871+ * for optimisation)
 872+ * @return Boolean
 873+ */
 874+ public function isItemLoaded( $item, $all = 'all' ) {
 875+ return ( $this->mLoadedItems === true && $all === 'all' ) ||
 876+ ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
 877+ }
 878+
 879+ /**
 880+ * Set that an item has been loaded
 881+ *
 882+ * @param $item String
 883+ */
 884+ private function setItemLoaded( $item ) {
 885+ if ( is_array( $this->mLoadedItems ) ) {
 886+ $this->mLoadedItems[$item] = true;
 887+ }
 888+ }
 889+
 890+ /**
851891 * Load user data from the session or login cookie. If there are no valid
852892 * credentials, initialises the user as an anonymous user.
853893 * @return Bool True if the user is logged in, false otherwise.
@@ -936,7 +976,7 @@
937977
938978 /**
939979 * Load user and user_group data from the database.
940 - * $this::mId must be set, this is how the user is identified.
 980+ * $this->mId must be set, this is how the user is identified.
941981 *
942982 * @return Bool True if the user exists, false if the user is anonymous
943983 * @private
@@ -976,25 +1016,51 @@
9771017 * @param $row Array Row from the user table to load.
9781018 */
9791019 function loadFromRow( $row ) {
980 - $this->mDataLoaded = true;
 1020+ $all = true;
9811021
 1022+ if ( isset( $row->user_name ) ) {
 1023+ $this->mName = $row->user_name;
 1024+ $this->mFrom = 'name';
 1025+ $this->setItemLoaded( 'name' );
 1026+ } else {
 1027+ $all = false;
 1028+ }
 1029+
 1030+ if ( isset( $row->user_name ) ) {
 1031+ $this->mRealName = $row->user_real_name;
 1032+ $this->setItemLoaded( 'realname' );
 1033+ } else {
 1034+ $all = false;
 1035+ }
 1036+
9821037 if ( isset( $row->user_id ) ) {
9831038 $this->mId = intval( $row->user_id );
 1039+ $this->mFrom = 'id';
 1040+ $this->setItemLoaded( 'id' );
 1041+ } else {
 1042+ $all = false;
9841043 }
985 - $this->mName = $row->user_name;
986 - $this->mRealName = $row->user_real_name;
987 - $this->mPassword = $row->user_password;
988 - $this->mNewpassword = $row->user_newpassword;
989 - $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time );
990 - $this->mEmail = $row->user_email;
991 - $this->decodeOptions( $row->user_options );
992 - $this->mTouched = wfTimestamp(TS_MW,$row->user_touched);
993 - $this->mToken = $row->user_token;
994 - $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
995 - $this->mEmailToken = $row->user_email_token;
996 - $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
997 - $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
998 - $this->mEditCount = $row->user_editcount;
 1044+
 1045+ if ( isset( $row->user_password ) ) {
 1046+ $this->mPassword = $row->user_password;
 1047+ $this->mNewpassword = $row->user_newpassword;
 1048+ $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time );
 1049+ $this->mEmail = $row->user_email;
 1050+ $this->decodeOptions( $row->user_options );
 1051+ $this->mTouched = wfTimestamp(TS_MW,$row->user_touched);
 1052+ $this->mToken = $row->user_token;
 1053+ $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
 1054+ $this->mEmailToken = $row->user_email_token;
 1055+ $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
 1056+ $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
 1057+ $this->mEditCount = $row->user_editcount;
 1058+ } else {
 1059+ $all = false;
 1060+ }
 1061+
 1062+ if ( $all ) {
 1063+ $this->mLoadedItems = true;
 1064+ }
9991065 }
10001066
10011067 /**
@@ -1032,7 +1098,7 @@
10331099 $this->mOptions = null;
10341100
10351101 if ( $reloadFrom ) {
1036 - $this->mDataLoaded = false;
 1102+ $this->mLoadedItems = array();
10371103 $this->mFrom = $reloadFrom;
10381104 }
10391105 }
@@ -1461,7 +1527,7 @@
14621528 && User::isIP( $this->mName ) ) {
14631529 // Special case, we know the user is anonymous
14641530 return 0;
1465 - } elseif( $this->mId === null ) {
 1531+ } elseif( !$this->isItemLoaded( 'id' ) ) {
14661532 // Don't load if this was initialized from an ID
14671533 $this->load();
14681534 }
@@ -1482,7 +1548,7 @@
14831549 * @return String User's name or IP address
14841550 */
14851551 function getName() {
1486 - if ( !$this->mDataLoaded && $this->mFrom == 'name' ) {
 1552+ if ( $this->isItemLoaded( 'name', 'only' ) ) {
14871553 # Special case optimisation
14881554 return $this->mName;
14891555 } else {
@@ -1910,7 +1976,10 @@
19111977 * @return String User's real name
19121978 */
19131979 function getRealName() {
1914 - $this->load();
 1980+ if ( !$this->isItemLoaded( 'realname' ) ) {
 1981+ $this->load();
 1982+ }
 1983+
19151984 return $this->mRealName;
19161985 }
19171986
@@ -2859,6 +2928,8 @@
28602929 */
28612930 function checkTemporaryPassword( $plaintext ) {
28622931 global $wgNewPasswordExpiry;
 2932+
 2933+ $this->load();
28632934 if( self::comparePasswords( $this->mNewpassword, $plaintext, $this->getId() ) ) {
28642935 if ( is_null( $this->mNewpassTime ) ) {
28652936 return true;
@@ -3174,9 +3245,11 @@
31753246 * non-existent/anonymous user accounts.
31763247 */
31773248 public function getRegistration() {
3178 - return $this->getId() > 0
3179 - ? $this->mRegistration
3180 - : false;
 3249+ if ( $this->isAnon() ) {
 3250+ return false;
 3251+ }
 3252+ $this->load();
 3253+ return $this->mRegistration;
31813254 }
31823255
31833256 /**
Index: trunk/phase3/includes/Article.php
@@ -836,11 +836,18 @@
837837 $dbr = wfGetDB( DB_SLAVE );
838838 $userTable = $dbr->tableName( 'user' );
839839
 840+ if ( $dbr->implicitGroupby() ) {
 841+ $realNameField = 'user_real_name';
 842+ } else {
 843+ $realNameField = 'FIRST(user_real_name) AS user_real_name';
 844+ }
 845+
840846 $tables = array( 'revision', 'user' );
841847
842848 $fields = array(
843 - "$userTable.*",
 849+ 'rev_user as user_id',
844850 'rev_user_text AS user_name',
 851+ $realNameField,
845852 'MAX(rev_timestamp) AS timestamp',
846853 );
847854
Index: trunk/phase3/includes/GlobalFunctions.php
@@ -389,9 +389,9 @@
390390 if ( $forward ) {
391391 $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})";
392392 }
393 - // Don't unstub $wgUser at this late stage just for statistics purposes
 393+ // Don't load $wgUser at this late stage just for statistics purposes
394394 // FIXME: We can detect some anons even if it is not loaded. See User::getId()
395 - if ( $wgUser->mDataLoaded && $wgUser->isAnon() ) {
 395+ if ( $wgUser->isItemLoaded( 'id' ) && $wgUser->isAnon() ) {
396396 $forward .= ' anon';
397397 }
398398 $log = sprintf( "%s\t%04.3f\t%s\n",
Index: trunk/phase3/includes/db/Database.php
@@ -668,7 +668,7 @@
669669 # Add a comment for easy SHOW PROCESSLIST interpretation
670670 # if ( $fname ) {
671671 global $wgUser;
672 - if ( is_object( $wgUser ) && $wgUser->mDataLoaded ) {
 672+ if ( is_object( $wgUser ) && $wgUser->isItemLoaded( 'name' ) ) {
673673 $userName = $wgUser->getName();
674674 if ( mb_strlen( $userName ) > 15 ) {
675675 $userName = mb_substr( $userName, 0, 15 ) . '...';
Index: trunk/phase3/RELEASE-NOTES
@@ -254,6 +254,7 @@
255255 * (bug 27249) "Installed software" table in Special:Version should always be
256256 left-to-right.
257257 * (bug 28719) Do not call mLinkHolders __destruct explicitly
 258+* (bug 21196) Article::getContributors() no longer fail on PostgreSQL.
258259 * (bug 28752) XCache doesn't work in CLI mode.
259260
260261 === API changes in 1.18 ===

Follow-up revisions

RevisionCommit summaryAuthorDate
r89464Fixing fixme in r87164 (wrong if check)krinkle14:04, 4 June 2011
r90161r87164 removed mDataLoaded and broke this test databaseless nature.platonides21:22, 15 June 2011
r98222Per OverlordQ, fix for r87164: let's use an aggregate function that exists in...ialex14:47, 27 September 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r87129* (bug 21196) Article::getContributors() no longer fail on PostgreSQL...ialex18:27, 29 April 2011

Comments

#Comment by Siebrand (talk | contribs)   15:46, 30 April 2011

Typo in release notes: fail -> fails.

#Comment by Krinkle (talk | contribs)   14:02, 4 June 2011
+		if ( isset( $row->user_name ) ) {
+			$this->mName = $row->user_name;
..
+		}
+
+		if ( isset( $row->user_name ) ) {
+			$this->mRealName = $row->user_real_name;
..
+		}
+
 		if ( isset( $row->user_id ) ) {
 			$this->mId = intval( $row->user_id );

The second one should be checking user_real_name instead of user_name

#Comment by Krinkle (talk | contribs)   14:05, 4 June 2011

I fixed it myself for now since it was causing issues in another project I'm working on.

r89464. Setting status back to new.

#Comment by Brion VIBBER (talk | contribs)   00:28, 8 June 2011

Does all this stuff for partial rows have anything to do with the PostgreSQL query failure in bug 21196?

Or is it an attempt at optimizing the later loop over the output by avoiding later loads from the db?

#Comment by IAlex (talk | contribs)   07:05, 8 June 2011

Yes, the problem is that you cannot select the entire table, such as the user table in this case, with a GROUP BY on only some fields (here rev_user and rev_user_text) in PostgreSQL, so I worked arround this by only selecting the user_real_name field from the user table (user_id and user_name come from the revision table) and this required those changes in the User object.

#Comment by Aaron Schulz (talk | contribs)   04:27, 22 June 2011

Why is the Article change mixed in here?

#Comment by Aaron Schulz (talk | contribs)   04:30, 22 June 2011

Ahh, nevermind.

#Comment by Aaron Schulz (talk | contribs)   19:17, 7 September 2011

loadFromRow() is confusing, how does $all ever get set? If $row is false? If it can be false then the docs should mention that.

#Comment by IAlex (talk | contribs)   19:36, 7 September 2011

You can pass partial rows to it as you can see in the Article::getContributors() query that only gets user_id, user_name and user_real_name. In such case $row->user_password will not be set and trigger the $all = false; part.

#Comment by Aaron Schulz (talk | contribs)   19:53, 7 September 2011

Nevermind, I misread the user_password part. In that case, it seems OK.

#Comment by OverlordQ (talk | contribs)   22:10, 26 September 2011

There is no FIRST() aggregate in Pg.

#Comment by IAlex (talk | contribs)   14:48, 27 September 2011

Fixed in r98222.

Status & tagging log