* @return Status
*/
final public function createInternal( array $params ) {
+ wfProfileIn( __METHOD__ );
if ( strlen( $params['content'] ) > $this->maxFileSizeInternal() ) {
$status = Status::newFatal( 'backend-fail-create', $params['dst'] );
} else {
$status = $this->doCreateInternal( $params );
$this->clearCache( array( $params['dst'] ) );
}
+ wfProfileOut( __METHOD__ );
return $status;
}
* @return Status
*/
final public function storeInternal( array $params ) {
+ wfProfileIn( __METHOD__ );
if ( filesize( $params['src'] ) > $this->maxFileSizeInternal() ) {
$status = Status::newFatal( 'backend-fail-store', $params['dst'] );
} else {
$status = $this->doStoreInternal( $params );
$this->clearCache( array( $params['dst'] ) );
}
+ wfProfileOut( __METHOD__ );
return $status;
}
* @return Status
*/
final public function copyInternal( array $params ) {
+ wfProfileIn( __METHOD__ );
$status = $this->doCopyInternal( $params );
$this->clearCache( array( $params['dst'] ) );
+ wfProfileOut( __METHOD__ );
return $status;
}
* @return Status
*/
final public function deleteInternal( array $params ) {
+ wfProfileIn( __METHOD__ );
$status = $this->doDeleteInternal( $params );
$this->clearCache( array( $params['src'] ) );
+ wfProfileOut( __METHOD__ );
return $status;
}
* @return Status
*/
final public function moveInternal( array $params ) {
+ wfProfileIn( __METHOD__ );
$status = $this->doMoveInternal( $params );
$this->clearCache( array( $params['src'], $params['dst'] ) );
+ wfProfileOut( __METHOD__ );
return $status;
}
protected function doMoveInternal( array $params ) {
// Copy source to dest
$status = $this->copyInternal( $params );
- if ( !$status->isOK() ) {
- return $status;
+ if ( $status->isOK() ) {
+ // Delete source (only fails due to races or medium going down)
+ $status->merge( $this->deleteInternal( array( 'src' => $params['src'] ) ) );
+ $status->setResult( true, $status->value ); // ignore delete() errors
}
- // Delete source (only fails due to races or medium going down)
- $status->merge( $this->deleteInternal( array( 'src' => $params['src'] ) ) );
- $status->setResult( true, $status->value ); // ignore delete() errors
return $status;
}
* @see FileBackendBase::concatenate()
*/
final public function concatenate( array $params ) {
+ wfProfileIn( __METHOD__ );
$status = Status::newGood();
// Try to lock the source files for the scope of this function
$scopeLockS = $this->getScopedFileLocks( $params['srcs'], LockManager::LOCK_UW, $status );
- if ( !$status->isOK() ) {
- return $status; // abort
+ if ( $status->isOK() ) {
+ // Actually do the concatenation
+ $status->merge( $this->doConcatenate( $params ) );
}
- // Actually do the concatenation
- $status->merge( $this->doConcatenate( $params ) );
-
+ wfProfileOut( __METHOD__ );
return $status;
}
* @see FileBackendBase::doPrepare()
*/
final protected function doPrepare( array $params ) {
+ wfProfileIn( __METHOD__ );
+
$status = Status::newGood();
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) {
$status->fatal( 'backend-fail-invalidpath', $params['dir'] );
+ wfProfileOut( __METHOD__ );
return $status; // invalid storage path
}
+
if ( $shard !== null ) { // confined to a single container/shard
$status->merge( $this->doPrepareInternal( $fullCont, $dir, $params ) );
} else { // directory is on several shards
$status->merge( $this->doPrepareInternal( "{$fullCont}{$suffix}", $dir, $params ) );
}
}
+
+ wfProfileOut( __METHOD__ );
return $status;
}
* @see FileBackendBase::doSecure()
*/
final protected function doSecure( array $params ) {
+ wfProfileIn( __METHOD__ );
$status = Status::newGood();
+
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) {
$status->fatal( 'backend-fail-invalidpath', $params['dir'] );
+ wfProfileOut( __METHOD__ );
return $status; // invalid storage path
}
+
if ( $shard !== null ) { // confined to a single container/shard
$status->merge( $this->doSecureInternal( $fullCont, $dir, $params ) );
} else { // directory is on several shards
$status->merge( $this->doSecureInternal( "{$fullCont}{$suffix}", $dir, $params ) );
}
}
+
+ wfProfileOut( __METHOD__ );
return $status;
}
* @see FileBackendBase::doClean()
*/
final protected function doClean( array $params ) {
+ wfProfileIn( __METHOD__ );
$status = Status::newGood();
+
list( $fullCont, $dir, $shard ) = $this->resolveStoragePath( $params['dir'] );
if ( $dir === null ) {
$status->fatal( 'backend-fail-invalidpath', $params['dir'] );
+ wfProfileOut( __METHOD__ );
return $status; // invalid storage path
}
+
// Attempt to lock this directory...
$filesLockEx = array( $params['dir'] );
$scopedLockE = $this->getScopedFileLocks( $filesLockEx, LockManager::LOCK_EX, $status );
if ( !$status->isOK() ) {
+ wfProfileOut( __METHOD__ );
return $status; // abort
}
+
if ( $shard !== null ) { // confined to a single container/shard
$status->merge( $this->doCleanInternal( $fullCont, $dir, $params ) );
} else { // directory is on several shards
$status->merge( $this->doCleanInternal( "{$fullCont}{$suffix}", $dir, $params ) );
}
}
+
+ wfProfileOut( __METHOD__ );
return $status;
}
* @see FileBackendBase::fileExists()
*/
final public function fileExists( array $params ) {
+ wfProfileIn( __METHOD__ );
$stat = $this->getFileStat( $params );
- if ( $stat === null ) {
- return null; // failure
- }
- return (bool)$stat;
+ wfProfileOut( __METHOD__ );
+ return ( $stat === null ) ? null : (bool)$stat; // null => failure
}
/**
* @see FileBackendBase::getFileTimestamp()
*/
final public function getFileTimestamp( array $params ) {
+ wfProfileIn( __METHOD__ );
$stat = $this->getFileStat( $params );
- if ( $stat ) {
- return $stat['mtime'];
- } else {
- return false;
- }
+ wfProfileOut( __METHOD__ );
+ return $stat ? $stat['mtime'] : false;
}
/**
* @see FileBackendBase::getFileSize()
*/
final public function getFileSize( array $params ) {
+ wfProfileIn( __METHOD__ );
$stat = $this->getFileStat( $params );
- if ( $stat ) {
- return $stat['size'];
- } else {
- return false;
- }
+ wfProfileOut( __METHOD__ );
+ return $stat ? $stat['size'] : false;
}
/**
* @see FileBackendBase::getFileStat()
*/
final public function getFileStat( array $params ) {
+ wfProfileIn( __METHOD__ );
$path = $params['src'];
$latest = !empty( $params['latest'] );
if ( isset( $this->cache[$path]['stat'] ) ) {
// If we want the latest data, check that this cached
// value was in fact fetched with the latest available data.
if ( !$latest || $this->cache[$path]['stat']['latest'] ) {
+ wfProfileOut( __METHOD__ );
return $this->cache[$path]['stat'];
}
}
$this->cache[$path]['stat'] = $stat;
$this->cache[$path]['stat']['latest'] = $latest;
}
+ wfProfileOut( __METHOD__ );
return $stat;
}
* @see FileBackendBase::getFileContents()
*/
public function getFileContents( array $params ) {
+ wfProfileIn( __METHOD__ );
$tmpFile = $this->getLocalReference( $params );
if ( !$tmpFile ) {
+ wfProfileOut( __METHOD__ );
return false;
}
wfSuppressWarnings();
$data = file_get_contents( $tmpFile->getPath() );
wfRestoreWarnings();
+ wfProfileOut( __METHOD__ );
return $data;
}
* @see FileBackendBase::getFileSha1Base36()
*/
final public function getFileSha1Base36( array $params ) {
+ wfProfileIn( __METHOD__ );
$path = $params['src'];
if ( isset( $this->cache[$path]['sha1'] ) ) {
+ wfProfileOut( __METHOD__ );
return $this->cache[$path]['sha1'];
}
$hash = $this->doGetFileSha1Base36( $params );
$this->trimCache(); // limit memory
$this->cache[$path]['sha1'] = $hash;
}
+ wfProfileOut( __METHOD__ );
return $hash;
}
/**
* @see FileBackendBase::getFileProps()
*/
- public function getFileProps( array $params ) {
+ final public function getFileProps( array $params ) {
+ wfProfileIn( __METHOD__ );
$fsFile = $this->getLocalReference( $params );
- if ( !$fsFile ) {
- return FSFile::placeholderProps();
- } else {
- return $fsFile->getProps();
- }
+ $props = $fsFile ? $fsFile->getProps() : FSFile::placeholderProps();
+ wfProfileOut( __METHOD__ );
+ return $props;
}
/**
* @see FileBackendBase::getLocalReference()
*/
public function getLocalReference( array $params ) {
+ wfProfileIn( __METHOD__ );
$path = $params['src'];
if ( isset( $this->cache[$path]['localRef'] ) ) {
+ wfProfileOut( __METHOD__ );
return $this->cache[$path]['localRef'];
}
$tmpFile = $this->getLocalCopy( $params );
$this->trimCache(); // limit memory
$this->cache[$path]['localRef'] = $tmpFile;
}
+ wfProfileOut( __METHOD__ );
return $tmpFile;
}
* @see FileBackendBase::streamFile()
*/
final public function streamFile( array $params ) {
+ wfProfileIn( __METHOD__ );
$status = Status::newGood();
$info = $this->getFileStat( $params );
$status->fatal( 'backend-fail-stream', $params['src'] );
}
+ wfProfileOut( __METHOD__ );
return $status;
}
* @see FileBackendBase::doOperationsInternal()
*/
protected function doOperationsInternal( array $ops, array $opts ) {
+ wfProfileIn( __METHOD__ );
$status = Status::newGood();
// Build up a list of FileOps...
$scopeLockS = $this->getScopedFileLocks( $filesLockSh, LockManager::LOCK_UW, $status );
$scopeLockE = $this->getScopedFileLocks( $filesLockEx, LockManager::LOCK_EX, $status );
if ( !$status->isOK() ) {
+ wfProfileOut( __METHOD__ );
return $status; // abort
}
}
$status->merge( $subStatus );
$status->success = $subStatus->success; // not done in merge()
+ wfProfileOut( __METHOD__ );
return $status;
}
class FileBackendTest extends MediaWikiTestCase {
private $backend, $multiBackend;
private $filesToPrune;
+ private static $backendToUse;
function setUp() {
global $wgFileBackends;
parent::setUp();
$tmpDir = wfTempDir() . '/file-backend-test-' . time() . '-' . mt_rand();
if ( $this->getCliArg( 'use-filebackend=' ) ) {
- $name = $this->getCliArg( 'use-filebackend=' );
- $useConfig = array();
- foreach ( $wgFileBackends as $conf ) {
- if ( $conf['name'] == $name ) {
- $useConfig = $conf;
+ if ( self::$backendToUse ) {
+ $this->singleBackend = self::$backendToUse;
+ } else {
+ $name = $this->getCliArg( 'use-filebackend=' );
+ $useConfig = array();
+ foreach ( $wgFileBackends as $conf ) {
+ if ( $conf['name'] == $name ) {
+ $useConfig = $conf;
+ }
}
+ $useConfig['name'] = 'localtesting'; // swap name
+ self::$backendToUse = new $conf['class']( $useConfig );
+ $this->singleBackend = self::$backendToUse;
}
- $useConfig['name'] = 'localtesting'; // swap name
- $this->singleBackend = new $conf['class']( $useConfig );
} else {
$this->singleBackend = new FSFileBackend( array(
'name' => 'localtesting',
$this->backend->prepare( array( 'dir' => dirname( $dest ) ) );
file_put_contents( $source, "Unit test file" );
+
+ if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
+ $this->backend->store( $op );
+ }
+
$status = $this->backend->doOperation( $op );
$this->assertEquals( array(), $status->errors,
"Store from $source to $dest succeeded without warnings ($backendName)." );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Store from $source to $dest succeeded ($backendName)." );
$this->assertEquals( array( 0 => true ), $status->success,
"Store from $source to $dest has proper 'success' field in Status ($backendName)." );
$toPath, // dest
);
- $op['overwrite'] = true;
+ $op2 = $op;
+ $op2['overwrite'] = true;
$cases[] = array(
- $op, // operation
+ $op2, // operation
$tmpName, // source
$toPath, // dest
);
- // @TODO: test overwriteSame
+ $op2 = $op;
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $tmpName, // source
+ $toPath, // dest
+ );
return $cases;
}
$status = $this->backend->doOperation(
array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Creation of file at $source succeeded ($backendName)." );
+ if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
+ $this->backend->copy( $op );
+ }
+
$status = $this->backend->doOperation( $op );
+
$this->assertEquals( array(), $status->errors,
"Copy from $source to $dest succeeded without warnings ($backendName)." );
$this->assertEquals( true, $status->isOK(),
$dest, // dest
);
- $op['overwrite'] = true;
+ $op2 = $op;
+ $op2['overwrite'] = true;
$cases[] = array(
- $op, // operation
+ $op2, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
$source, // source
$dest, // dest
);
$status = $this->backend->doOperation(
array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Creation of file at $source succeeded ($backendName)." );
+ if ( isset( $op['overwrite'] ) || isset( $op['overwriteSame'] ) ) {
+ $this->backend->copy( $op );
+ }
+
$status = $this->backend->doOperation( $op );
$this->assertEquals( array(), $status->errors,
"Move from $source to $dest succeeded without warnings ($backendName)." );
$dest, // dest
);
- $op['overwrite'] = true;
+ $op2 = $op;
+ $op2['overwrite'] = true;
$cases[] = array(
- $op, // operation
+ $op2, // operation
+ $source, // source
+ $dest, // dest
+ );
+
+ $op2 = $op;
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
$source, // source
$dest, // dest
);
if ( $withSource ) {
$status = $this->backend->doOperation(
array( 'op' => 'create', 'content' => 'blahblah', 'dst' => $source ) );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Creation of file at $source succeeded ($backendName)." );
}
if ( $alreadyExists ) {
$status = $this->backend->doOperation(
array( 'op' => 'create', 'content' => $oldText, 'dst' => $dest ) );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Creation of file at $dest succeeded ($backendName)." );
}
strlen( $dummyText )
);
- $op['overwrite'] = true;
+ $op2 = $op;
+ $op2['overwrite'] = true;
$cases[] = array(
- $op, // operation
+ $op2, // operation
$source, // source
true, // dest already exists
true, // succeeds
strlen( $dummyText )
);
+ $op2 = $op;
+ $op2['overwriteSame'] = true;
+ $cases[] = array(
+ $op2, // operation
+ $source, // source
+ true, // dest already exists
+ false, // succeeds
+ strlen( $dummyText )
+ );
+
return $cases;
}
}
$status = $this->backend->doOperations( $ops );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Creation of source files succeeded ($backendName)." );
$dest = $params['dst'];
$status = $this->backend->doOperation(
array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Creation of file at $source succeeded ($backendName)." );
$tmpFile = $this->backend->getLocalCopy( array( 'src' => $source ) );
$status = $this->backend->doOperation(
array( 'op' => 'create', 'content' => $content, 'dst' => $source ) );
- $this->assertEquals( true, $status->isOK(),
+ $this->assertEquals( array(), $status->errors,
"Creation of file at $source succeeded ($backendName)." );
$tmpFile = $this->backend->getLocalReference( array( 'src' => $source ) );
$iter = $backend->getFileList( array( 'dir' => "$base/$container" ) );
if ( $iter ) {
foreach ( $iter as $file ) {
- $backend->doOperation( array( 'op' => 'delete', 'src' => "$base/$container/$file" ) );
+ $backend->delete( array( 'src' => "$base/$container/$file", 'ignoreMissingSource' => 1 ) );
$tmp = $file;
while ( $tmp = FileBackend::parentStoragePath( $tmp ) ) {
$backend->clean( array( 'dir' => $tmp ) );