r109597 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r109596‎ | r109597 | r109598 >
Date:01:01, 20 January 2012
Author:raindrift
Status:ok (Comments)
Tags:interfaceconcurrency 
Comment:
wrapped lines to 100 columns, re-enabled some tests that were disabled
followup to r109594
Modified paths:
  • /trunk/extensions/InterfaceConcurrency/includes/ConcurrencyCheck.php (modified) (history)
  • /trunk/extensions/InterfaceConcurrency/tests/phpunit/ApiConcurrencyTest.php (modified) (history)
  • /trunk/extensions/InterfaceConcurrency/tests/phpunit/ConcurrencyCheckTest.php (modified) (history)

Diff [purge]

Index: trunk/extensions/InterfaceConcurrency/tests/phpunit/ApiConcurrencyTest.php
@@ -77,7 +77,6 @@
7878 global $wgUser;
7979
8080 $wgUser = self::$users['one']->user;
81 - /* commenting these out since i need to go home and they're breakin CI. See commit summary for details.
8281
8382 list( $result, , $session ) = $this->doApiRequestWithToken( array(
8483 'action' => 'concurrency',
@@ -104,7 +103,6 @@
105104 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user );
106105
107106 $this->assertEquals( "success", $result['concurrency']['result'] );
108 - */
109107 }
110108
111109 /**
@@ -115,7 +113,6 @@
116114 global $wgUser;
117115
118116 $wgUser = self::$users['one']->user;
119 - /* commenting these out since i need to go home and they're breakin CI. See commit summary for details.
120117
121118 list( $result, , $session ) = $this->doApiRequestWithToken( array(
122119 'action' => 'concurrency',
@@ -142,7 +139,6 @@
143140 'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user );
144141
145142 $this->assertEquals( "success", $result['concurrency']['result'] );
146 - */
147143 }
148144
149145 /**
@@ -166,7 +162,6 @@
167163 $e->getMessage() );
168164 }
169165 $this->assertTrue( $exception, "Got exception" );
170 -
171166 }
172167
173168 }
Index: trunk/extensions/InterfaceConcurrency/tests/phpunit/ConcurrencyCheckTest.php
@@ -31,7 +31,8 @@
3232 global $wgMainCacheType, $wgInterfaceConcurrencyConfig;
3333 $this->oldcache = $wgMainCacheType;
3434 $wgMainCacheType = CACHE_MEMCACHED;
35 - $wgInterfaceConcurrencyConfig['ExpirationMin'] = -60; // negative numbers are needed for testing
 35+ // negative numbers are needed for testing
 36+ $wgInterfaceConcurrencyConfig['ExpirationMin'] = -60;
3637 }
3738
3839 public function tearDown() {
@@ -56,19 +57,43 @@
5758 // tests
5859 $this->assertTrue( $first->checkout( $testKey ), "Initial checkout" );
5960 $this->assertTrue( $first->checkout( $testKey ), "Cache hit" );
60 - $this->assertFalse( $second->checkout( $testKey ), "Checkout of locked resource fails as different user" );
61 - $this->assertTrue( $first->checkout( $testKey ), "Checkout of locked resource succeeds as original user" );
62 - $this->assertFalse( $second->checkin( $testKey ), "Checkin of locked resource fails as different user" );
63 - $this->assertTrue( $first->checkin( $testKey ), "Checkin of locked resource succeeds as original user" );
 61+ $this->assertFalse(
 62+ $second->checkout( $testKey ),
 63+ "Checkout of locked resource fails as different user"
 64+ );
 65+ $this->assertTrue(
 66+ $first->checkout( $testKey ),
 67+ "Checkout of locked resource succeeds as original user"
 68+ );
 69+ $this->assertFalse(
 70+ $second->checkin( $testKey ),
 71+ "Checkin of locked resource fails as different user"
 72+ );
 73+ $this->assertTrue(
 74+ $first->checkin( $testKey ),
 75+ "Checkin of locked resource succeeds as original user"
 76+ );
6477 $second->setExpirationTime( -5 );
65 - $this->assertTrue( $second->checkout( $testKey ), "Checked-in resource is now available to second user" );
 78+ $this->assertTrue(
 79+ $second->checkout( $testKey ),
 80+ "Checked-in resource is now available to second user"
 81+ );
6682 $second->setExpirationTime();
67 - $this->assertTrue( $first->checkout( $testKey ), "Checkout of expired resource succeeds as first user" );
 83+ $this->assertTrue(
 84+ $first->checkout( $testKey ),
 85+ "Checkout of expired resource succeeds as first user"
 86+ );
6887 $this->assertTrue( $second->checkout( $testKey, true ), "Checkout override" );
69 - $this->assertFalse( $first->checkout( $testKey ), "Checkout of overriden resource fails as different user" );
 88+ $this->assertFalse(
 89+ $first->checkout( $testKey ),
 90+ "Checkout of overriden resource fails as different user"
 91+ );
7092
7193 // cleanup
72 - $this->assertTrue( $second->checkin( $testKey ), "Checkin of record with changed ownership" );
 94+ $this->assertTrue(
 95+ $second->checkin( $testKey ),
 96+ "Checkin of record with changed ownership"
 97+ );
7398
7499 }
75100
@@ -97,9 +122,21 @@
98123 $output = $cc->status( array( 1337, 1338, 1339, 13310 ) );
99124 $this->assertEquals( true, is_array( $output ), "Status returns values" );
100125 $this->assertEquals( 4, count( $output ), "Output has the correct number of records" );
101 - $this->assertEquals( 'valid', $output[1337]['status'], "Current checkouts are listed as valid" );
102 - $this->assertEquals( 'invalid', $output[1339]['status'], "Expired checkouts are invalid" );
103 - $this->assertEquals( 'invalid', $output[13310]['status'], "Missing checkouts are invalid" );
 126+ $this->assertEquals(
 127+ 'valid',
 128+ $output[1337]['status'],
 129+ "Current checkouts are listed as valid"
 130+ );
 131+ $this->assertEquals(
 132+ 'invalid',
 133+ $output[1339]['status'],
 134+ "Expired checkouts are invalid"
 135+ );
 136+ $this->assertEquals(
 137+ 'invalid',
 138+ $output[13310]['status'],
 139+ "Missing checkouts are invalid"
 140+ );
104141 }
105142
106143 public function testListCheckouts() {
@@ -109,8 +146,15 @@
110147
111148 $output = $cc->listCheckouts();
112149 $this->assertTrue( $output[1337] && $output[1338], "Current checkouts are present" );
113 - $this->assertEquals( self::$users['user1']->user->getId(), $output[1337]['cc_user'], "User matches" );
114 - $this->assertTrue( array_key_exists( 'cc_expiration', $output[1337] ), "Expiration exists" );
 150+ $this->assertEquals(
 151+ self::$users['user1']->user->getId(),
 152+ $output[1337]['cc_user'],
 153+ "User matches"
 154+ );
 155+ $this->assertTrue(
 156+ array_key_exists( 'cc_expiration', $output[1337] ),
 157+ "Expiration exists"
 158+ );
115159 $this->assertTrue( $output[1337]['mine'], "Ownership flag set" );
116160 }
117161 }
Index: trunk/extensions/InterfaceConcurrency/includes/ConcurrencyCheck.php
@@ -3,17 +3,18 @@
44 /**
55 * Class for cooperative locking of web resources
66 *
7 - * Each resource is identified by a combination of the "resource type" (the application, the type
8 - * of content, etc), and the resource's primary key or some other unique numeric ID.
 7+ * Each resource is identified by a combination of the "resource type" (the application, the
 8+ * type of content, etc), and the resource's primary key or some other unique numeric ID.
99 *
10 - * Currently, a resource can only be checked out by a single user. Other attempts to check it out result
11 - * in the checkout failing. In the future, an option for multiple simulataneous checkouts could be added
12 - * without much trouble.
 10+ * Currently, a resource can only be checked out by a single user. Other attempts to check it
 11+ * out result in the checkout failing. In the future, an option for multiple simulataneous
 12+ * checkouts could be added without much trouble.
1313 *
14 - * This could be done with named locks, except then it would be impossible to build a list of all the
15 - * resources currently checked out for a given application. There's no good way to construct a query
16 - * that answers the question, "What locks do you have starting with [foo]" This could be done really well
17 - * with a concurrent, reliable, distributed key/value store, but we don't have one of those right now.
 14+ * This could be done with named locks, except then it would be impossible to build a list of
 15+ * all the resources currently checked out for a given application. There's no good way to
 16+ * construct a query that answers the question, "What locks do you have starting with [foo]"
 17+ * This could be done really well with a concurrent, reliable, distributed key/value store,
 18+ * but we don't have one of those right now.
1819 *
1920 * @author Ian Baker <ian@wikimedia.org>
2021 */
@@ -34,8 +35,8 @@
3536 */
3637 public function __construct( $resourceType, $user, $expirationTime = null ) {
3738
38 - // All database calls are to the master, since the whole point of this class is maintaining
39 - // concurrency. Most reads should come from cache anyway.
 39+ // All database calls are to the master, since the whole point of this class is
 40+ // maintaining concurrency. Most reads should come from cache anyway.
4041 $this->dbw = wfGetDb( DB_MASTER );
4142
4243 $this->user = $user;
@@ -64,7 +65,11 @@
6566 // check the cache first.
6667 $cached = $wgMemc->get( $cacheKey );
6768 if ( $cached ) {
68 - if ( !$override && $cached['userId'] != $userId && $cached['expiration'] > time() ) {
 69+ if (
 70+ !$override &&
 71+ $cached['userId'] != $userId &&
 72+ $cached['expiration'] > time()
 73+ ) {
6974 // this is already checked out.
7075 return false;
7176 }
@@ -87,7 +92,8 @@
8893
8994 // if the insert succeeded, checkout is done.
9095 if ( $dbw->affectedRows() === 1 ) {
91 - // "By default, MediaWiki opens a transaction at the first query, and commits it before the output is sent."
 96+ // "By default, MediaWiki opens a transaction at the first query, and commits
 97+ // it before the output is sent."
9298 // set the cache key, since this is inside an implicit transaction.
9399 $wgMemc->set( $cacheKey, array(
94100 'userId' => $userId,
@@ -120,8 +126,10 @@
121127 ! $override
122128 ) {
123129 // this was a cache miss. populate the cache with data from the db.
124 - // cache is set to expire at the same time as the checkout, since it'll become invalid then anyway.
125 - // inside this transaction, a row-level lock is established which ensures cache concurrency
 130+ // cache is set to expire at the same time as the checkout, since it'll become
 131+ // invalid then anyway.
 132+ // inside this transaction, a row-level lock is established which ensures cache
 133+ // concurrency
126134 $wgMemc->set( $cacheKey, array(
127135 'userId' => $row->cc_user,
128136 'expiration' => wfTimestamp( TS_UNIX, $row->cc_expiration )
@@ -146,7 +154,11 @@
147155 );
148156
149157 // cache the result.
150 - $wgMemc->set( $cacheKey, array( 'userId' => $userId, 'expiration' => $expiration ), $this->expirationTime );
 158+ $wgMemc->set(
 159+ $cacheKey,
 160+ array( 'userId' => $userId, 'expiration' => $expiration ),
 161+ $this->expirationTime
 162+ );
151163
152164 $dbw->commit( __METHOD__ );
153165 return true;
@@ -176,8 +188,8 @@
177189 array()
178190 );
179191
180 - // check row count (this is atomic since the dml establishes a lock, select would not be)
181 - // not that it matters too much, since cache deletes can happen w/o atomicity
 192+ // check row count (this is atomic since the dml establishes a lock, select would
 193+ // not be). not that it matters too much, since cache deletes can happen w/o atomicity
182194 if ( $dbw->affectedRows() === 1 ) {
183195 $wgMemc->delete( $cacheKey );
184196 $dbw->commit( __METHOD__ );
@@ -194,7 +206,8 @@
195207 * @return Integer describing the number of records expired.
196208 */
197209 public function expire() {
198 - // TODO: run this in a few other places that db access happens, to make sure the db stays non-crufty.
 210+ // TODO: run this in a few other places that db access happens, to make sure the db
 211+ // stays non-crufty.
199212 $dbw = $this->dbw;
200213
201214 // remove the rows from the db. trust memcached to expire the cache.
@@ -210,7 +223,8 @@
211224 $rowCount = $dbw->affectedRows();
212225 $dbw->commit( __METHOD__ );
213226
214 - // if I'm going to assume an implicit transaction, best not to contradict that assumption.
 227+ // if I'm going to assume an implicit transaction, best not to contradict that
 228+ // assumption.
215229 // expire() is called internally.
216230 $dbw->begin( __METHOD__ );
217231
@@ -289,12 +303,16 @@
290304 $checkouts[ $record['cc_record'] ] = $record;
291305
292306 // TODO: implement strategy #2 above, determine which DBMSes need which method.
293 - // for now, disable adding to cache here for databases that don't support read locking
 307+ // for now, disable adding to cache here for databases that don't support read
 308+ // locking
294309 if ( $wgDBtype !== 'mysql' ) {
295310 // safe to store values since this is inside the transaction
296311 $wgMemc->set(
297312 wfMemcKey( 'concurrencycheck', $this->resourceType, $record['cc_record'] ),
298 - array( 'userId' => $record['cc_user'], 'expiration' => wfTimestamp( TS_UNIX, $record['cc_expiration'] ) ),
 313+ array(
 314+ 'userId' => $record['cc_user'],
 315+ 'expiration' => wfTimestamp( TS_UNIX, $record['cc_expiration'] )
 316+ ),
299317 wfTimestamp( TS_UNIX, $record['cc_expiration'] ) - time()
300318 );
301319 }
@@ -389,14 +407,18 @@
390408 // negative number are allowed, though mostly only used for testing
391409 if ( $expirationTime && (int) $expirationTime == $expirationTime ) {
392410 if ( $expirationTime > $wgInterfaceConcurrencyConfig['ExpirationMax'] ) {
393 - $this->expirationTime = $wgInterfaceConcurrencyConfig['ExpirationMax']; // if the number is too high, limit it to the max value.
 411+ // if the number is too high, limit it to the max value.
 412+ $this->expirationTime = $wgInterfaceConcurrencyConfig['ExpirationMax'];
394413 } elseif ( $expirationTime < $wgInterfaceConcurrencyConfig['ExpirationMin'] ) {
395 - $this->expirationTime = $wgInterfaceConcurrencyConfig['ExpirationMin']; // low limit, default -1 min
 414+ // low limit, default -1 min
 415+ $this->expirationTime = $wgInterfaceConcurrencyConfig['ExpirationMin'];
396416 } else {
397 - $this->expirationTime = $expirationTime; // the amount of time before a checkout expires.
 417+ // the amount of time before a checkout expires.
 418+ $this->expirationTime = $expirationTime;
398419 }
399420 } else {
400 - $this->expirationTime = $wgInterfaceConcurrencyConfig['ExpirationDefault']; // global default is 15 mins.
 421+ // global default is generally 15 mins.
 422+ $this->expirationTime = $wgInterfaceConcurrencyConfig['ExpirationDefault'];
401423 }
402424 }
403425
@@ -409,7 +431,9 @@
410432 */
411433 private static function validateId ( $record ) {
412434 if ( (int) $record !== $record || $record <= 0 ) {
413 - throw new ConcurrencyCheckBadRecordIdException( 'Record ID ' . $record . ' must be a positive integer' );
 435+ throw new ConcurrencyCheckBadRecordIdException(
 436+ 'Record ID ' . $record . ' must be a positive integer'
 437+ );
414438 }
415439
416440 // TODO: add a hook here for client-side validation.

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r109594Added listCheckouts() and fixed some stuff per Tim's review:...raindrift00:46, 20 January 2012

Comments

#Comment by Johnduhart (talk | contribs)   14:37, 20 January 2012

Don't comment out tests. Mark them as broken.

Status & tagging log