'cc_resource_type' => $this->resourceType,
'cc_record' => $record,
'cc_user' => $userId,
- 'cc_expiration' => time() + $this->expirationTime,
+ 'cc_expiration' => wfTimestamp( TS_MW, time() + $this->expirationTime ),
),
__METHOD__,
array( 'IGNORE' )
);
// not checked out by current user, checkout is unexpired, override is unset
- if( ! ( $override || $row->cc_user == $userId || $row->cc_expiration <= time() ) ) {
+ if( ! ( $override || $row->cc_user == $userId || wfTimestamp( TS_UNIX, $row->cc_expiration ) <= time() ) ) {
// 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
- $memc->set( $cacheKey, array( 'userId' => $row->cc_user, 'expiration' => $row->cc_expiration ), $row->cc_expiration - time() );
+ $memc->set( $cacheKey, array( 'userId' => $row->cc_user, 'expiration' => $row->cc_expiration ), wfTimestamp( TS_UNIX, $row->cc_expiration ) - time() );
$dbw->rollback();
return false;
}
'cc_resource_type' => $this->resourceType,
'cc_record' => $record,
'cc_user' => $userId,
- 'cc_expiration' => $expiration,
+ 'cc_expiration' => wfTimestamp( TS_MW, $expiration ),
),
__METHOD__
);
'concurrencycheck',
array( '*' ),
array(
- 'cc_expiration <= ' . $now,
+ 'cc_expiration <= ' . $dbw->addQuotes( wfTimestamp( TS_MW, $now ) ),
),
__METHOD__,
array()
$dbw->delete(
'concurrencycheck',
array(
- 'cc_expiration <= ' . $now,
+ 'cc_expiration <= ' . $dbw->addQuotes( wfTimestamp( TS_MW, $now ) ),
),
__METHOD__,
array()
'cc_resource_type' => $this->resourceType,
'cc_record' => $key,
'cc_user' => $cached['userId'],
- 'cc_expiration' => $cached['expiration'],
+ 'cc_expiration' => wfTimestamp( TS_MW, $cached['expiration'] ),
'cache' => 'cached',
);
} else {
array(
'cc_resource_type' => $this->resourceType,
'cc_record IN (' . implode( ',', $toSelect ) . ')',
- 'cc_expiration > unix_timestamp(now())'
+ 'cc_expiration > ' . $dbw->addQuotes( wfTimestamp( TS_MW ) ),
),
__METHOD__,
array()
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'),
);
}
--- /dev/null
+--
+-- 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);