reverts Concurrency works
authorAntoine Musso <hashar@users.mediawiki.org>
Wed, 11 Jan 2012 09:05:56 +0000 (09:05 +0000)
committerAntoine Musso <hashar@users.mediawiki.org>
Wed, 11 Jan 2012 09:05:56 +0000 (09:05 +0000)
trunk is frozen pending stabilisation so we can release MediaWiki 1.19.
Those changes introduces API changes and new SQL tables, so that sounds like
new feature we do not have time to review right now.

Please reapply changes in branches/concurrency and have code review handled
there. Once the branch has been reviewed, please hold. Once trunk is stable
enough and 1.19 got branched, you are welcome to merge the branch in trunk.

Note: we can have a Jenkins jobs setup to run the branch tests if you need.

Reverts:
r108595 r108591 r108585 r108584 108572 r108564 108560 r108559

12 files changed:
includes/AutoLoader.php
includes/ConcurrencyCheck.php [deleted file]
includes/DefaultSettings.php
includes/api/ApiConcurrency.php [deleted file]
includes/api/ApiMain.php
includes/installer/MysqlUpdater.php
includes/installer/SqliteUpdater.php
maintenance/archives/patch-concurrencycheck.sql [deleted file]
maintenance/sqlite/archives/patch-concurrencycheck.sql [deleted file]
maintenance/tables.sql
tests/phpunit/includes/ConcurrencyCheckTest.php [deleted file]
tests/phpunit/includes/api/ApiConcurrencyTest.php [deleted file]

index 9136b9e..61ae868 100644 (file)
@@ -43,7 +43,6 @@ $wgAutoloadLocalClasses = array(
        'ChannelFeed' => 'includes/Feed.php',
        'Collation' => 'includes/Collation.php',
        'ConcatenatedGzipHistoryBlob' => 'includes/HistoryBlob.php',
-       'ConcurrencyCheck' => 'includes/ConcurrencyCheck.php',
        'ConfEditor' => 'includes/ConfEditor.php',
        'ConfEditorParseError' => 'includes/ConfEditor.php',
        'ConfEditorToken' => 'includes/ConfEditor.php',
@@ -53,6 +52,7 @@ $wgAutoloadLocalClasses = array(
        'DeferredUpdates' => 'includes/DeferredUpdates.php',
        'DerivativeRequest' => 'includes/WebRequest.php',
        'DiffHistoryBlob' => 'includes/HistoryBlob.php',
+
        'DoubleReplacer' => 'includes/StringUtils.php',
        'DummyLinker' => 'includes/Linker.php',
        'Dump7ZipOutput' => 'includes/Export.php',
@@ -271,7 +271,6 @@ $wgAutoloadLocalClasses = array(
        'ApiBase' => 'includes/api/ApiBase.php',
        'ApiBlock' => 'includes/api/ApiBlock.php',
        'ApiComparePages' => 'includes/api/ApiComparePages.php',
-       'ApiConcurrency' => 'includes/api/ApiConcurrency.php',
        'ApiDelete' => 'includes/api/ApiDelete.php',
        'ApiDisabled' => 'includes/api/ApiDisabled.php',
        'ApiEditPage' => 'includes/api/ApiEditPage.php',
diff --git a/includes/ConcurrencyCheck.php b/includes/ConcurrencyCheck.php
deleted file mode 100644 (file)
index f439129..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-<?php
-
-/**
- * Class for cooperative locking of web resources
- *
- * Each resource is identified by a combination of the "resource type" (the application, the type
- * of content, etc), and the resource's primary key or some other unique numeric ID.
- *
- * Currently, a resource can only be checked out by a single user.  Other attempts to check it out result
- * in the checkout failing.  In the future, an option for multiple simulataneous checkouts could be added
- * without much trouble.
- *
- * This could be done with named locks, except then it would be impossible to build a list of all the
- * resources currently checked out for a given application.  There's no good way to construct a query
- * that answers the question, "What locks do you have starting with [foo]"  This could be done really well
- * with a concurrent, reliable, distributed key/value store, but we don't have one of those right now.
- *
- * @author Ian Baker <ian@wikimedia.org>
- */
-class ConcurrencyCheck {
-
-       protected $expirationTime;
-
-       /**
-        * @var User
-        */
-       protected $user;
-
-       /**
-        * Constructor
-        * 
-        * @var $resourceType String The calling application or type of resource, conceptually like a namespace
-        * @var $user User object, the current user
-        * @var $expirationTime Integer (optional) How long should a checkout last, in seconds
-        */
-       public function __construct( $resourceType, $user, $expirationTime = null ) {
-
-               // All database calls are to the master, since the whole point of this class is maintaining
-               // concurrency. Most reads should come from cache anyway.
-               $this->dbw = wfGetDb( DB_MASTER );
-
-               $this->user = $user;
-               // TODO: create a registry of all valid resourceTypes that client app can add to.
-               $this->resourceType = $resourceType;
-               $this->setExpirationTime( $expirationTime );
-       }
-
-       /**
-        * Check out a resource.  This establishes an atomically generated, cooperative lock
-        * on a key.  The lock is tied to the current user.
-        *
-        * @var $record Integer containing the record id to check out
-        * @var $override Boolean (optional) describing whether to override an existing checkout
-        * @return boolean
-        */
-       public function checkout( $record, $override = null ) {
-               global $wgMemc;
-               $this->validateId( $record );
-               $dbw = $this->dbw;
-               $userId = $this->user->getId();
-               $cacheKey = wfMemcKey( 'concurrencycheck', $this->resourceType, $record );
-
-               // when operating with a single memcached cluster, it's reasonable to check the cache here.
-               global $wgConcurrency;
-               if( $wgConcurrency['TrustMemc'] ) {
-               $cached = $wgMemc->get( $cacheKey );
-                       if( $cached ) {
-                               if( ! $override && $cached['userId'] != $userId && $cached['expiration'] > time() ) {
-                                       // this is already checked out.
-                                       return false;
-                               }
-                       }
-               }
-               
-               // attempt an insert, check success (this is atomic)
-               $insertError = null;
-               $res = $dbw->insert(
-                       'concurrencycheck',
-                       array(
-                               'cc_resource_type' => $this->resourceType,
-                               'cc_record' => $record,
-                               'cc_user' => $userId,
-                               'cc_expiration' => wfTimestamp( TS_MW, time() + $this->expirationTime ),
-                       ),
-                       __METHOD__,
-                       array( 'IGNORE' )
-               );
-
-               // if the insert succeeded, checkout is done.
-               if( $dbw->affectedRows() === 1 ) {
-                       // delete any existing cache key.  can't create a new key here
-                       // since the insert didn't happen inside a transaction.
-                       $wgMemc->delete( $cacheKey );
-                       return true;
-               }
-
-               // if the insert failed, it's necessary to check the expiration.
-               // here, check by deleting, since that permits the use of write locks
-               // (SELECT..LOCK IN SHARE MODE), rather than read locks (SELECT..FOR UPDATE)
-               $dbw->begin();
-               $dbw->delete(
-                       'concurrencycheck',
-                       array(
-                               'cc_resource_type' => $this->resourceType,
-                               'cc_record' => $record,
-                               '(cc_user = ' . $userId . ' OR cc_expiration <= ' . $dbw->addQuotes(wfTimestamp( TS_MW )) . ')',  // only the owner can perform a checkin
-                       ),
-                       __METHOD__,
-                       array()
-               );
-                       
-               // delete failed: not checked out by current user, checkout is unexpired, override is unset
-               if( $dbw->affectedRows() !== 1 && ! $override) {
-                       // fetch the existing data to cache it
-                       $row = $dbw->selectRow(
-                               'concurrencycheck',
-                               array( '*' ),
-                               array(
-                                       'cc_resource_type' => $this->resourceType,
-                                       'cc_record' => $record,
-                               ),
-                               __METHOD__,
-                               array()
-                       );
-                       
-                       // this was a cache miss.  populate the cache with data from the db.
-                       // cache is set to expire at the same time as the checkout, since it'll become invalid then anyway.
-                       // inside this transaction, a row-level lock is established which ensures cache concurrency
-                       $wgMemc->set( $cacheKey, array( 'userId' => $row->cc_user, 'expiration' => wfTimestamp( TS_UNIX, $row->cc_expiration ) ), wfTimestamp( TS_UNIX, $row->cc_expiration ) - time() );
-                       $dbw->rollback();
-                       return false;
-               }
-
-               $expiration = time() + $this->expirationTime;
-
-               // delete succeeded, insert a new row.
-               // replace is used here to support the override parameter
-               $res = $dbw->replace(
-                       'concurrencycheck',
-                       array( 'cc_resource_type', 'cc_record' ),
-                       array(
-                               'cc_resource_type' => $this->resourceType,
-                               'cc_record' => $record,
-                               'cc_user' => $userId,
-                               'cc_expiration' => wfTimestamp( TS_MW, $expiration ),
-                       ),
-                       __METHOD__
-               );
-
-               // cache the result.
-               $wgMemc->set( $cacheKey, array( 'userId' => $userId, 'expiration' => $expiration ), $this->expirationTime );
-               
-               $dbw->commit();
-               return true;
-       }
-
-       /**
-        * Check in a resource. Only works if the resource is checked out by the current user.
-        *
-        * @var $record Integer containing the record id to checkin
-        * @return Boolean
-        */
-       public function checkin( $record ) {
-               global $wgMemc;
-               $this->validateId( $record );           
-               $dbw = $this->dbw;
-               $userId = $this->user->getId();
-               $cacheKey = wfMemcKey( 'concurrencycheck', $this->resourceType, $record );
-
-               $dbw->delete(
-                       'concurrencycheck',
-                       array(
-                               'cc_resource_type' => $this->resourceType,
-                               'cc_record' => $record,
-                               'cc_user' => $userId,  // only the owner can perform a checkin
-                       ),
-                       __METHOD__,
-                       array()
-               );
-
-               // check row count (this is atomic, select would not be)
-               if( $dbw->affectedRows() === 1 ) {
-                       $wgMemc->delete( $cacheKey );
-                       return true;
-               }
-
-               return false;
-       }
-
-       /**
-        * Remove all expired checkouts.
-        *
-        * @return Integer describing the number of records expired.
-        */
-       public function expire() {
-               // TODO: run this in a few other places that db access happens, to make sure the db stays non-crufty.
-               $dbw = $this->dbw;
-               $now = time();
-
-               // remove the rows from the db.  trust memcached to expire the cache.
-               $dbw->delete(
-                       'concurrencycheck',
-                       array(
-                               'cc_expiration <= ' . $dbw->addQuotes( wfTimestamp( TS_MW, $now ) ),
-                       ),
-                       __METHOD__,
-                       array()
-               );
-
-               // return the number of rows removed.
-               return $dbw->affectedRows();
-       }
-
-       public function status( $keys ) {
-               global $wgMemc, $wgDBtype;
-               $dbw = $this->dbw;
-               $now = time();
-
-               $checkouts = array();
-               $toSelect = array();
-
-               // validate keys, attempt to retrieve from cache.
-               foreach( $keys as $key ) {
-                       $this->validateId( $key );
-
-                       $cached = $wgMemc->get( wfMemcKey( 'concurrencycheck', $this->resourceType, $key ) );
-                       if( $cached && $cached['expiration'] > $now ) {
-                               $checkouts[$key] = array(
-                                       'status' => 'valid',
-                                       'cc_resource_type' => $this->resourceType,
-                                       'cc_record' => $key,
-                                       'cc_user' => $cached['userId'],
-                                       'cc_expiration' => wfTimestamp( TS_MW, $cached['expiration'] ),
-                                       'cache' => 'cached',
-                               );
-                       } else {
-                               $toSelect[] = $key;
-                       }
-               }
-
-               // if there were cache misses...
-               if( $toSelect ) {
-                       // If it's time to go to the database, go ahead and expire old rows.
-                       $this->expire();
-                       
-                       
-                       // Why LOCK IN SHARE MODE, you might ask?  To avoid a race condition: Otherwise, it's possible for
-                       // a checkin and/or checkout to occur between this select and the value being stored in cache, which
-                       // makes for an incorrect cache.  This, in turn, could make checkout() above (which uses the cache)
-                       // function incorrectly.
-                       //
-                       // Another option would be to run the select, then check each row in-turn before setting the cache
-                       // key using either SELECT (with LOCK IN SHARE MODE) or UPDATE that checks a timestamp (and which
-                       // would establish the same lock). That method would mean smaller, quicker locks, but more overall
-                       // database overhead.
-                       //
-                       // It appears all the DBMSes we use support LOCK IN SHARE MODE, but if that's not the case, the second
-                       // solution above could be implemented instead.
-                       $queryParams = array();
-                       if( $wgDBtype === 'mysql' ) {
-                               $queryParamsp[] = 'LOCK IN SHARE MODE';
-
-                               // the transaction seems incongruous, I know, but it's to keep the cache update atomic.
-                               $dbw->begin();
-                       }
-                       
-                       $res = $dbw->select(
-                               'concurrencycheck',
-                               array( '*' ),
-                               array(
-                                       'cc_resource_type' => $this->resourceType,
-                                       'cc_record' => $toSelect,
-                                       'cc_expiration > ' . $dbw->addQuotes( wfTimestamp( TS_MW ) ),
-                               ),
-                               __METHOD__,
-                               $queryParams
-                       );
-
-                       while( $res && $record = $res->fetchRow() ) {
-                               $record['status'] = 'valid';
-                               $checkouts[ $record['cc_record'] ] = $record;
-
-                               // TODO: implement strategy #2 above, determine which DBMSes need which method.
-                               // for now, disable adding to cache here for databases that don't support read locking
-                               if( $wgDBtype !== 'mysql' ) {
-                                       // safe to store values since this is inside the transaction
-                                       $wgMemc->set(
-                                               wfMemcKey( 'concurrencycheck', $this->resourceType, $record['cc_record'] ),
-                                               array( 'userId' => $record['cc_user'], 'expiration' => wfTimestamp( TS_UNIX, $record['cc_expiration'] ) ),
-                                               wfTimestamp( TS_UNIX, $record['cc_expiration'] ) - time()
-                                       );
-                               }
-                       }
-
-                       if( $wgDBtype === 'mysql' ) {
-                               // end the transaction.
-                               $dbw->rollback();
-                       }
-               }
-
-               // if a key was passed in but has no (unexpired) checkout, include it in the
-               // result set to make things easier and more consistent on the client-side.
-               foreach( $keys as $key ) {
-                       if( ! array_key_exists( $key, $checkouts ) ) {
-                               $checkouts[$key]['status'] = 'invalid';
-                       }
-               }
-
-               return $checkouts;
-       }
-
-       public function listCheckouts() {
-               // TODO: fill in the function that lets you get the complete set of checkouts for a given application.
-       }
-
-       /**
-        * @param $user user
-        */
-       public function setUser( $user ) {
-               $this->user = $user;
-       }
-
-       public function setExpirationTime( $expirationTime = null ) {
-               global $wgConcurrency;
-               
-               // check to make sure the time is a number
-               // negative number are allowed, though mostly only used for testing
-               if( $expirationTime && (int) $expirationTime == $expirationTime ) {
-                       if( $expirationTime > $wgConcurrency['ExpirationMax'] ) {
-                               $this->expirationTime = $wgConcurrency['ExpirationMax']; // if the number is too high, limit it to the max value.
-                       } elseif ( $expirationTime < $wgConcurrency['ExpirationMin'] ) {
-                               $this->expirationTime = $wgConcurrency['ExpirationMin']; // low limit, default -1 min
-                       } else {
-                               $this->expirationTime = $expirationTime; // the amount of time before a checkout expires.
-                       }
-               } else {
-                       $this->expirationTime = $wgConcurrency['ExpirationDefault']; // global default is 15 mins.
-               }
-       }
-
-       /**
-        * Check to make sure a record ID is numeric, throw an exception if not.
-        *
-        * @var $record Integer
-        * @throws ConcurrencyCheckBadRecordIdException
-        * @return boolean
-        */
-       private static function validateId ( $record ) {
-               if( (int) $record !== $record || $record <= 0 ) {
-                       throw new ConcurrencyCheckBadRecordIdException( 'Record ID ' . $record . ' must be a positive integer' );
-               }
-
-               // TODO: add a hook here for client-side validation.
-               return true;
-       }
-}
-
-class ConcurrencyCheckBadRecordIdException extends MWException {}
index d7b9304..e86f0f7 100644 (file)
@@ -5716,16 +5716,6 @@ $wgSeleniumConfigFile = null;
 $wgDBtestuser = ''; //db user that has permission to create and drop the test databases only
 $wgDBtestpassword = '';
 
-/**
- * ConcurrencyCheck keeps track of which web resources are in use, for producing higher-quality UI
- */
-$wgConcurrency = array();
-$wgConcurrency['ExpirationDefault'] = 60 * 15; // Default checkout duration. 15 minutes.
-$wgConcurrency['ExpirationMax'] = 60 * 30; // Maximum possible checkout duration. 30 minutes.
-$wgConcurrency['ExpirationMin'] = 1; // Minimum possible checkout duration.  Negative is possible for testing if you want.
-$wgConcurrency['TrustMemc'] = true; // If running in an environment with multiple discrete caches, set to false.
-
-
 /**
  * For really cool vim folding this needs to be at the end:
  * vim: foldmarker=@{,@} foldmethod=marker
diff --git a/includes/api/ApiConcurrency.php b/includes/api/ApiConcurrency.php
deleted file mode 100644 (file)
index 4eeaeab..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-
-/**
- * API module that handles cooperative locking of web resources
- */
-class ApiConcurrency extends ApiBase {
-       public function __construct( $main, $action ) {
-               parent::__construct( $main, $action );
-       }
-
-       public function execute() {
-               global $wgUser;
-
-               $this->checkPermission( $wgUser );
-
-               $params = $this->extractRequestParams();
-
-               $res = array();
-
-               $concurrencyCheck = new ConcurrencyCheck( $params['resourcetype'], $wgUser );
-
-               switch ( $params['ccaction'] ) {
-                       case 'checkout':
-                       case 'checkin':
-                               if ( $concurrencyCheck->$params['ccaction']( $params['record'] ) ) {
-                                       $res['result'] = 'success';
-                               } else {
-                                       $res['result'] = 'failure';
-                               }
-                               break;
-
-                       default:
-                               ApiBase::dieDebug( __METHOD__, "Unhandled concurrency action: {$params['ccaction']}" );
-               }
-
-               $this->getResult()->addValue( null, $this->getModuleName(), $res );
-       }
-
-       public function mustBePosted() {
-               return true;
-       }
-
-       public function isWriteMode() {
-               return true;
-       }
-
-       public function getAllowedParams() {
-               return array(
-                       'resourcetype' => array(
-                               ApiBase::PARAM_TYPE => 'string',
-                               ApiBase::PARAM_REQUIRED => true
-                       ),
-                       'record' => array(
-                               ApiBase::PARAM_TYPE => 'integer',
-                               ApiBase::PARAM_REQUIRED => true
-                       ),
-                       'token' => null,
-                       'expiry' => array(
-                               ApiBase::PARAM_TYPE => 'integer'
-                       ),
-                       'ccaction' => array(
-                               ApiBase::PARAM_REQUIRED => true,
-                               ApiBase::PARAM_TYPE => array(
-                                       'checkout',
-                                       'checkin',
-                               ),
-                       ),
-               );
-       }
-
-       public function getParamDescription() {
-               return array(
-                       'resourcetype' => 'the resource type for concurrency check',
-                       'record' => 'an unique identifier for a record of the defined resource type',
-                       'expiry' => 'the time interval for expiration',
-                       'ccaction' => 'the action for concurrency check',
-               );
-       }
-
-       public function getDescription() {
-               return 'Get/Set a concurrency check for a web resource type';
-       }
-
-       public function needsToken() {
-               return true;
-       }
-
-       public function getTokenSalt() {
-               return '';
-       }
-
-       public function getVersion() {
-               return __CLASS__ . ': $Id$';
-       }
-       
-       private function checkPermission( $user ) {
-               if ( $user->isAnon() ) {
-                       $this->dieUsage( "You don't have permission to do that", 'permission-denied' );
-               }
-               if ( $user->isBlocked( false ) ) {
-                       $this->dieUsageMsg( array( 'blockedtext' ) );
-               }
-       }
-
-}
index 03d6dea..3219709 100644 (file)
@@ -79,7 +79,6 @@ class ApiMain extends ApiBase {
                'patrol' => 'ApiPatrol',
                'import' => 'ApiImport',
                'userrights' => 'ApiUserrights',
-               'concurrency' => 'ApiConcurrency',
        );
 
        /**
index 1c2c111..a5ffea4 100644 (file)
@@ -192,7 +192,6 @@ class MysqlUpdater extends DatabaseUpdater {
                        array( 'modifyField', 'user', 'ug_group', 'patch-ug_group-length-increase.sql' ),
                        array( 'addField',      'uploadstash',  'us_chunk_inx',         'patch-uploadstash_chunk.sql' ),
                        array( 'addfield', 'job',           'job_timestamp',    'patch-jobs-add-timestamp.sql' ),
-                       array( 'addTable', 'concurrencycheck',                                  'patch-concurrencycheck.sql'),
                );
        }
 
index e89e382..fdb6437 100644 (file)
@@ -71,7 +71,6 @@ class SqliteUpdater extends DatabaseUpdater {
                        array( 'modifyField', 'user', 'ug_group', 'patch-ug_group-length-increase.sql' ),
                        array( 'addField',      'uploadstash',  'us_chunk_inx',         'patch-uploadstash_chunk.sql' ),
                        array( 'addfield', 'job',           'job_timestamp',    'patch-jobs-add-timestamp.sql' ),
-                       array( 'addTable', 'concurrencycheck',                                  'patch-concurrencycheck.sql'),
                );
        }
 
diff --git a/maintenance/archives/patch-concurrencycheck.sql b/maintenance/archives/patch-concurrencycheck.sql
deleted file mode 100644 (file)
index f76b923..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
---
--- Store atomic locking information for web resources, to permit
--- UI that warns users when concurrently editing things that aren't
--- concurrently editable.
---
-CREATE TABLE /*_*/concurrencycheck (
-       -- a string describing the resource or application being checked out.
-       cc_resource_type varchar(255) NOT NULL,
-
-       -- the (numeric) ID of the record that's being checked out.
-       cc_record int unsigned NOT NULL,
-
-       -- the user who has control of the resource
-       cc_user int unsigned NOT NULL,
-
-       -- the date/time on which this record expires
-       cc_expiration varbinary(14) not null
-
-) /*$wgDBTableOptions*/;
--- composite pk.
-CREATE UNIQUE INDEX /*i*/cc_resource_record ON /*_*/concurrencycheck (cc_resource_type, cc_record);
--- sometimes there's a delete based on userid.
-CREATE INDEX /*i*/cc_user ON /*_*/concurrencycheck (cc_user);
--- sometimes there's a delete based on expiration
-CREATE INDEX /*i*/cc_expiration ON /*_*/concurrencycheck (cc_expiration);
diff --git a/maintenance/sqlite/archives/patch-concurrencycheck.sql b/maintenance/sqlite/archives/patch-concurrencycheck.sql
deleted file mode 100644 (file)
index f76b923..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
---
--- Store atomic locking information for web resources, to permit
--- UI that warns users when concurrently editing things that aren't
--- concurrently editable.
---
-CREATE TABLE /*_*/concurrencycheck (
-       -- a string describing the resource or application being checked out.
-       cc_resource_type varchar(255) NOT NULL,
-
-       -- the (numeric) ID of the record that's being checked out.
-       cc_record int unsigned NOT NULL,
-
-       -- the user who has control of the resource
-       cc_user int unsigned NOT NULL,
-
-       -- the date/time on which this record expires
-       cc_expiration varbinary(14) not null
-
-) /*$wgDBTableOptions*/;
--- composite pk.
-CREATE UNIQUE INDEX /*i*/cc_resource_record ON /*_*/concurrencycheck (cc_resource_type, cc_record);
--- sometimes there's a delete based on userid.
-CREATE INDEX /*i*/cc_user ON /*_*/concurrencycheck (cc_user);
--- sometimes there's a delete based on expiration
-CREATE INDEX /*i*/cc_expiration ON /*_*/concurrencycheck (cc_expiration);
index f82e068..f43e613 100644 (file)
@@ -1483,31 +1483,4 @@ CREATE TABLE /*_*/config (
 -- Should cover *most* configuration - strings, ints, bools, etc.
 CREATE INDEX /*i*/cf_name_value ON /*_*/config (cf_name,cf_value(255));
 
---
--- Store atomic locking information for web resources, to permit
--- UI that warns users when concurrently editing things that aren't
--- concurrently editable.
---
-CREATE TABLE /*_*/concurrencycheck (
-       -- a string describing the resource or application being checked out.
-       cc_resource_type varchar(255) NOT NULL,
-
-       -- the (numeric) ID of the record that's being checked out.
-       cc_record int unsigned NOT NULL,
-
-       -- the user who has control of the resource
-       cc_user int unsigned NOT NULL,
-
-       -- the date/time on which this record expires
-       cc_expiration varbinary(14) not null
-
-) /*$wgDBTableOptions*/;
--- composite pk.
-CREATE UNIQUE INDEX /*i*/cc_resource_record ON /*_*/concurrencycheck (cc_resource_type, cc_record);
--- sometimes there's a delete based on userid.
-CREATE INDEX /*i*/cc_user ON /*_*/concurrencycheck (cc_user);
--- sometimes there's a delete based on expiration
-CREATE INDEX /*i*/cc_expiration ON /*_*/concurrencycheck (cc_expiration);
-
-
 -- vim: sw=2 sts=2 et
diff --git a/tests/phpunit/includes/ConcurrencyCheckTest.php b/tests/phpunit/includes/ConcurrencyCheckTest.php
deleted file mode 100644 (file)
index db1e05c..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-class ConcurrencyCheckTest extends MediaWikiTestCase {
-       /**
-        * @var Array of test users
-        */
-       public static $users;
-
-       // Prepare test environment
-
-       public function setUp() {
-               parent::setUp();
-       
-               self::$users = array(
-                       'user1' => new ApiTestUser(
-                               'Concurrencychecktestuser1',
-                               'ConcurrencyCheck Test User 1',
-                               'concurrency_check_test_user_1@example.com',
-                               array()
-                       ),
-                       'user2' => new ApiTestUser(
-                               'Concurrencychecktestuser2',
-                               'ConcurrencyCheck Test User 2',
-                               'concurrency_check_test_user_2@example.com',
-                               array()
-                       ),
-               );
-
-               // turn on memcached for this test.
-               // if no memcached is present, this still works fine.
-               global $wgMainCacheType, $wgConcurrency;
-               $this->oldcache = $wgMainCacheType;
-               $wgMainCacheType = CACHE_MEMCACHED;
-               $wgConcurrency['ExpirationMin'] = -60;  // negative numbers are needed for testing
-       }
-
-       public function tearDown() {
-               // turn off caching again.
-               global $wgMainCacheType;
-               $wgMainCacheType = $this->oldcache;
-
-               parent::tearDown();
-       }
-
-       // Actual tests from here down
-       
-       public function testCheckoutCheckin() {
-               $first = new ConcurrencyCheck( 'CCUnitTest',  self::$users['user1']->user );
-               $second = new ConcurrencyCheck( 'CCUnitTest',  self::$users['user2']->user );
-               $testKey = 1337;
-
-               // clean up after any previously failed tests
-               $first->checkin($testKey);
-               $second->checkin($testKey);
-
-               // tests
-               /* turning these tests off per robla, since I need to go home.
-               $this->assertTrue( $first->checkout($testKey), "Initial checkout" );
-               $this->assertTrue( $first->checkout($testKey), "Cache hit" );
-               $this->assertFalse( $second->checkout($testKey), "Checkout of locked resource fails as different user" );
-               $this->assertTrue( $first->checkout($testKey), "Checkout of locked resource succeeds as original user" );
-               $this->assertFalse( $second->checkin($testKey), "Checkin of locked resource fails as different user" );
-               $this->assertTrue( $first->checkin($testKey), "Checkin of locked resource succeeds as original user" );
-               $second->setExpirationTime(-5);
-               $this->assertTrue( $second->checkout($testKey), "Checked-in resource is now available to second user" );
-               $second->setExpirationTime();
-               $this->assertTrue( $first->checkout($testKey), "Checkout of expired resource succeeds as first user");
-               $this->assertTrue( $second->checkout($testKey, true), "Checkout override" );
-               $this->assertFalse( $first->checkout($testKey), "Checkout of overriden resource fails as different user" );
-               
-
-               // cleanup
-               $this->assertTrue( $second->checkin($testKey), "Checkin of record with changed ownership" );
-               */
-       }
-
-       public function testExpire() {
-               $cc = new ConcurrencyCheck( 'CCUnitTest',  self::$users['user1']->user );
-               $cc->setExpirationTime(-1);
-               $cc->checkout( 1338 );  // these numbers are test record ids.
-               $cc->checkout( 1339 );
-               $cc->setExpirationTime();
-               $cc->checkout( 13310 );
-
-               // tests
-               $this->assertEquals( 2, $cc->expire(), "Resource expiration" );
-               $this->assertTrue( $cc->checkin( 13310 ), "Checkin succeeds after expiration" );                
-       }
-       
-       public function testStatus() {
-               $cc = new ConcurrencyCheck( 'CCUnitTest',  self::$users['user1']->user );
-               $cc->checkout( 1337 );
-               $cc->checkout( 1338 );
-               $cc->setExpirationTime(-5);
-               $cc->checkout( 1339 );
-               $cc->setExpirationTime();
-
-               // tests
-               $output = $cc->status( array( 1337, 1338, 1339, 13310 ) );
-               $this->assertEquals( true, is_array( $output ), "Status returns values" );
-               $this->assertEquals( 4, count( $output ), "Output has the correct number of records" );
-               $this->assertEquals( 'valid', $output[1337]['status'], "Current checkouts are listed as valid");
-               $this->assertEquals( 'invalid', $output[1339]['status'], "Expired checkouts are invalid");
-               $this->assertEquals( 'invalid', $output[13310]['status'], "Missing checkouts are invalid");             
-       }
-}
diff --git a/tests/phpunit/includes/api/ApiConcurrencyTest.php b/tests/phpunit/includes/api/ApiConcurrencyTest.php
deleted file mode 100644 (file)
index 3c14f96..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-<?php
-
-class ApiConcurrencyTest extends ApiTestCase {
-       /**
-        * @var Array of test users
-        */
-       public static $users;
-
-       // Prepare test environment
-
-       function setUp() {
-               parent::setUp();
-
-               self::$users['one'] = new ApiTestUser(
-                               'ApitestuserA',
-                               'Api Test UserA',
-                               'api_test_userA@example.com',
-                               array()
-               );
-
-               self::$users['two'] = new ApiTestUser(
-                               'ApitestuserB',
-                               'Api Test UserB',
-                               'api_test_userB@example.com',
-                               array()
-               );
-       }
-
-       public function tearDown() {
-               parent::tearDown();
-       }
-
-       function testLogin() {
-
-               $sessionArray = array();
-
-               foreach ( self::$users as $key => $user ) {
-
-                       $params = array(
-                               'action' => 'login',
-                               'lgname' => $user->username,
-                               'lgpassword' => $user->password
-                       );
-                       list( $result, , $session ) = $this->doApiRequest( $params );
-                       $this->assertArrayHasKey( "login", $result );
-                       $this->assertArrayHasKey( "result", $result['login'] );
-                       $this->assertEquals( "NeedToken", $result['login']['result'] );
-                       $token = $result['login']['token'];
-
-                       $params = array(
-                               'action' => 'login',
-                               'lgtoken' => $token,
-                               'lgname' => $user->username,
-                               'lgpassword' => $user->password
-                       );
-                       list( $result, , $session ) = $this->doApiRequest( $params, $session );
-                       $this->assertArrayHasKey( "login", $result );
-                       $this->assertArrayHasKey( "result", $result['login'] );
-                       $this->assertEquals( "Success", $result['login']['result'] );
-                       $this->assertArrayHasKey( 'lgtoken', $result['login'] );
-
-                       $this->assertNotEmpty( $session, 'API Login must return a session' );
-
-                       $sessionArray[$key] = $session;
-
-               }
-
-               return $sessionArray;
-
-       }
-
-       /**
-        * @depends testLogin
-        */
-       function testCheckOut( $sessionArray ) {
-
-               global $wgUser;
-
-               $wgUser = self::$users['one']->user;
-               /* commenting these out since i need to go home and they're breakin CI.  See commit summary for details.
-               
-               list( $result, , $session ) =  $this->doApiRequestWithToken( array(
-                                                                       'action' => 'concurrency',
-                                                                       'ccaction' => 'checkout',
-                                                                       'record' => 1,
-                                                                       'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user );
-
-               $this->assertEquals( "success", $result['concurrency']['result'] );
-
-               $wgUser = self::$users['two']->user;
-
-               list( $result, , $session ) =  $this->doApiRequestWithToken( array(
-                                                                       'action' => 'concurrency',
-                                                                       'ccaction' => 'checkout',
-                                                                       'record' => 1,
-                                                                       'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user );
-
-               $this->assertEquals( "failure", $result['concurrency']['result'] );
-
-               list( $result, , $session ) =  $this->doApiRequestWithToken( array(
-                                                                       'action' => 'concurrency',
-                                                                       'ccaction' => 'checkout',
-                                                                       'record' => 2,
-                                                                       'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user );
-
-               $this->assertEquals( "success", $result['concurrency']['result'] );
-               */
-       }
-
-       /**
-        * @depends testLogin
-        */
-       function testCheckIn( $sessionArray ) {
-
-               global $wgUser;
-
-               $wgUser = self::$users['one']->user;
-               /* commenting these out since i need to go home and they're breakin CI.  See commit summary for details.
-
-               list( $result, , $session ) =  $this->doApiRequestWithToken( array(
-                                                                       'action' => 'concurrency',
-                                                                       'ccaction' => 'checkin',
-                                                                       'record' => 1,
-                                                                       'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user );
-
-               $this->assertEquals( "success", $result['concurrency']['result'] );
-
-               list( $result, , $session ) =  $this->doApiRequestWithToken( array(
-                                                                       'action' => 'concurrency',
-                                                                       'ccaction' => 'checkin',
-                                                                       'record' => 2,
-                                                                       'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user );
-
-               $this->assertEquals( "failure", $result['concurrency']['result'] );
-
-               $wgUser = self::$users['two']->user;
-
-               list( $result, , $session ) =  $this->doApiRequestWithToken( array(
-                                                                       'action' => 'concurrency',
-                                                                       'ccaction' => 'checkin',
-                                                                       'record' => 2,
-                                                                       'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['two'], self::$users['two']->user );
-
-               $this->assertEquals( "success", $result['concurrency']['result'] );
-               */      
-       }
-
-       /**
-        * @depends testLogin
-        */
-       function testInvalidCcacton( $sessionArray ) {
-               $exception = false;
-               try {
-                       global $wgUser;
-                       
-                       $wgUser = self::$users['one']->user;
-               
-                       list( $result, , $session ) =  $this->doApiRequestWithToken( array(
-                                                                                               'action' => 'concurrency',
-                                                                                               'ccaction' => 'checkinX',
-                                                                                               'record' => 1,
-                                                                                               'resourcetype' => 'responding-to-moodbar-feedback'), $sessionArray['one'], self::$users['one']->user );
-               } catch ( UsageException $e ) {
-                       $exception = true;
-                       $this->assertEquals("Unrecognized value for parameter 'ccaction': checkinX",
-                               $e->getMessage() );
-               }
-               $this->assertTrue( $exception, "Got exception" );
-
-       }
-
-}