protected $conn; // Swift connection handle
protected $connStarted = 0; // integer UNIX timestamp
protected $connContainers = array(); // container object cache
+ protected $connException; // CloudFiles exception
/**
* @see FileBackendStore::__construct()
$status = Status::newGood();
$scopeLockS = $this->getScopedFileLocks( array( $path ), LockManager::LOCK_UW, $status );
if ( $status->isOK() ) {
- $tmpFile = $this->getLocalCopy( array( 'src' => $path, 'latest' => 1 ) );
+ # Do not stat the file in getLocalCopy() to avoid infinite loops
+ $tmpFile = $this->getLocalCopy( array( 'src' => $path, 'latest' => 1, 'nostat' => 1 ) );
if ( $tmpFile ) {
$hash = $tmpFile->getSha1Base36();
if ( $hash !== false ) {
*/
public function getDirListPageInternal( $fullCont, $dir, &$after, $limit, array $params ) {
$dirs = array();
+ if ( $after === INF ) {
+ return $dirs; // nothing more
+ }
+ wfProfileIn( __METHOD__ . '-' . $this->name );
try {
$container = $this->getContainer( $fullCont );
if ( substr( $object, -1 ) === '/' ) {
$dirs[] = $object; // directories end in '/'
}
- $after = $object; // update last item
}
// Recursive: list all dirs under $dir and its subdirs
} else {
}
$lastDir = $objectDir;
}
- $after = $object; // update last item
}
}
+ if ( count( $objects ) < $limit ) {
+ $after = INF; // avoid a second RTT
+ } else {
+ $after = end( $objects ); // update last item
+ }
} catch ( NoSuchContainerException $e ) {
} catch ( CloudFilesException $e ) { // some other exception?
$this->handleException( $e, null, __METHOD__,
array( 'cont' => $fullCont, 'dir' => $dir ) );
}
+ wfProfileOut( __METHOD__ . '-' . $this->name );
return $dirs;
}
*/
public function getFileListPageInternal( $fullCont, $dir, &$after, $limit, array $params ) {
$files = array();
+ if ( $after === INF ) {
+ return $files; // nothing more
+ }
+ wfProfileIn( __METHOD__ . '-' . $this->name );
try {
$container = $this->getContainer( $fullCont );
}
// Recursive: list all files under $dir and its subdirs
} else { // files
- $files = $container->list_objects( $limit, $after, $prefix );
+ $objects = $container->list_objects( $limit, $after, $prefix );
+ $files = $objects;
+ }
+ if ( count( $objects ) < $limit ) {
+ $after = INF; // avoid a second RTT
+ } else {
+ $after = end( $objects ); // update last item
}
- $after = end( $files ); // update last item
- reset( $files ); // reset pointer
} catch ( NoSuchContainerException $e ) {
} catch ( CloudFilesException $e ) { // some other exception?
$this->handleException( $e, null, __METHOD__,
array( 'cont' => $fullCont, 'dir' => $dir ) );
}
+ wfProfileOut( __METHOD__ . '-' . $this->name );
return $files;
}
return null;
}
- if ( !$this->fileExists( $params ) ) {
+ # Check the recursion guard to avoid loops when filling metadata
+ if ( empty( $params['nostat'] ) && !$this->fileExists( $params ) ) {
return null;
}
$statuses[$index] = $status;
}
- foreach ( $fileOpHandles as $fileOpHandle ) {
- $fileOpHandle->closeResources();
- }
-
return $statuses;
}
* Get a connection to the Swift proxy
*
* @return CF_Connection|bool False on failure
- * @throws InvalidResponseException
+ * @throws CloudFilesException
*/
protected function getConnection() {
- if ( $this->conn === false ) {
- throw new InvalidResponseException; // failed last attempt
+ if ( $this->connException instanceof Exception ) {
+ throw $this->connException; // failed last attempt
}
// Session keys expire after a while, so we renew them periodically
if ( $this->conn && ( time() - $this->connStarted ) > $this->authTTL ) {
$this->conn = null;
}
// Authenticate with proxy and get a session key...
- if ( $this->conn === null ) {
+ if ( !$this->conn ) {
+ $this->connStarted = 0;
$this->connContainers = array();
try {
$this->auth->authenticate();
$this->conn = new CF_Connection( $this->auth );
$this->connStarted = time();
- } catch ( AuthenticationException $e ) {
- $this->conn = false; // don't keep re-trying
- } catch ( InvalidResponseException $e ) {
- $this->conn = false; // don't keep re-trying
+ } catch ( CloudFilesException $e ) {
+ $this->connException = $e; // don't keep re-trying
+ throw $e; // throw it back
}
}
- if ( !$this->conn ) {
- throw new InvalidResponseException; // auth/connection problem
- }
return $this->conn;
}
* @param $container string Container name
* @param $bypassCache bool Bypass all caches and load from Swift
* @return CF_Container
- * @throws NoSuchContainerException
- * @throws InvalidResponseException
+ * @throws CloudFilesException
*/
protected function getContainer( $container, $bypassCache = false ) {
$conn = $this->getConnection(); // Swift proxy connection