X-Git-Url: https://git.cyclocoop.org/%242?a=blobdiff_plain;f=includes%2Ffilebackend%2FSwiftFileBackend.php;h=fb385de9ea3074b8245047c0a6ced7434d249879;hb=c5466ba03e0642b28075793ca1e2836fa8797896;hp=d13ac2232af485aa99e3d7a4e48f0ec38118f866;hpb=a3e5d604a7773c18a0f4baca35a14271bf0f55a7;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filebackend/SwiftFileBackend.php b/includes/filebackend/SwiftFileBackend.php index d13ac2232a..fb385de9ea 100644 --- a/includes/filebackend/SwiftFileBackend.php +++ b/includes/filebackend/SwiftFileBackend.php @@ -47,8 +47,14 @@ class SwiftFileBackend extends FileBackendStore { /** @var CF_Connection */ protected $conn; // Swift connection handle - protected $connStarted = 0; // integer UNIX timestamp - protected $connException; // CloudFiles exception + protected $sessionStarted = 0; // integer UNIX timestamp + + /** @var CloudFilesException */ + protected $connException; + protected $connErrorTime = 0; // UNIX timestamp + + /** @var BagOStuff */ + protected $srvCache; /** @var ProcessCacheLRU */ protected $connContainerCache; // container object cache @@ -75,6 +81,8 @@ class SwiftFileBackend extends FileBackendStore { * - levels : the number of hash levels (and digits) * - repeat : hash subdirectories are prefixed with all the * parent hash directory names (e.g. "a/ab/abc") + * - cacheAuthInfo : Whether to cache authentication tokens in APC/XCache. + * This is probably insecure in shared hosting environments. */ public function __construct( array $config ) { parent::__construct( $config ); @@ -103,14 +111,21 @@ class SwiftFileBackend extends FileBackendStore { : false; $this->swiftCDNExpiry = isset( $config['swiftCDNExpiry'] ) ? $config['swiftCDNExpiry'] - : 3600; // hour + : 12*3600; // 12 hours is safe (tokens last 24 hours per http://docs.openstack.org) $this->swiftCDNPurgable = isset( $config['swiftCDNPurgable'] ) ? $config['swiftCDNPurgable'] : true; - // Cache container info to mask latency + // Cache container information to mask latency $this->memCache = wfGetMainCache(); // Process cache for container info $this->connContainerCache = new ProcessCacheLRU( 300 ); + // Cache auth token information to avoid RTTs + if ( !empty( $config['cacheAuthInfo'] ) ) { + try { // look for APC, XCache, WinCache, ect... + $this->srvCache = ObjectCache::newAccelerator( array() ); + } catch ( Exception $e ) {} + } + $this->srvCache = $this->srvCache ? $this->srvCache : new EmptyBagOStuff(); } /** @@ -714,6 +729,7 @@ class SwiftFileBackend extends FileBackendStore { if ( isset( $obj->metadata['Sha1base36'] ) ) { return true; // nothing to do } + wfProfileIn( __METHOD__ ); $status = Status::newGood(); $scopeLockS = $this->getScopedFileLocks( array( $path ), LockManager::LOCK_UW, $status ); if ( $status->isOK() ) { @@ -724,11 +740,13 @@ class SwiftFileBackend extends FileBackendStore { if ( $hash !== false ) { $obj->metadata['Sha1base36'] = $hash; $obj->sync_metadata(); // save to Swift + wfProfileOut( __METHOD__ ); return true; // success } } } $obj->metadata['Sha1base36'] = false; + wfProfileOut( __METHOD__ ); return false; // failed } @@ -1122,36 +1140,62 @@ class SwiftFileBackend extends FileBackendStore { } /** - * Get a connection to the Swift proxy + * Get an authenticated connection handle to the Swift proxy * * @return CF_Connection|bool False on failure * @throws CloudFilesException */ protected function getConnection() { - if ( $this->connException instanceof Exception ) { - throw $this->connException; // failed last attempt + if ( $this->connException instanceof CloudFilesException ) { + if ( ( time() - $this->connErrorTime ) < 60 ) { + throw $this->connException; // failed last attempt; don't bother + } else { // actually retry this time + $this->connException = null; + $this->connErrorTime = 0; + } } // Session keys expire after a while, so we renew them periodically - if ( $this->conn && ( time() - $this->connStarted ) > $this->authTTL ) { - $this->conn->close(); // close active cURL connections - $this->conn = null; - } + $reAuth = ( ( time() - $this->sessionStarted ) > $this->authTTL ); // Authenticate with proxy and get a session key... - if ( !$this->conn ) { - $this->connStarted = 0; + if ( !$this->conn || $reAuth ) { + $this->sessionStarted = 0; $this->connContainerCache->clear(); - try { - $this->auth->authenticate(); - $this->conn = new CF_Connection( $this->auth ); - $this->connStarted = time(); - } catch ( CloudFilesException $e ) { - $this->connException = $e; // don't keep re-trying - throw $e; // throw it back + $cacheKey = $this->getCredsCacheKey( $this->auth->username ); + $creds = $this->srvCache->get( $cacheKey ); // credentials + if ( is_array( $creds ) ) { // cache hit + $this->auth->load_cached_credentials( + $creds['auth_token'], $creds['storage_url'], $creds['cdnm_url'] ); + $this->sessionStarted = time() - ceil( $this->authTTL/2 ); // skew for worst case + } else { // cache miss + try { + $this->auth->authenticate(); + $creds = $this->auth->export_credentials(); + $this->srvCache->add( $cacheKey, $creds, ceil( $this->authTTL/2 ) ); // cache + $this->sessionStarted = time(); + } catch ( CloudFilesException $e ) { + $this->connException = $e; // don't keep re-trying + $this->connErrorTime = time(); + throw $e; // throw it back + } + } + if ( $this->conn ) { // re-authorizing? + $this->conn->close(); // close active cURL handles in CF_Http object } + $this->conn = new CF_Connection( $this->auth ); } return $this->conn; } + /** + * Get the cache key for a container + * + * @param $username string + * @return string + */ + private function getCredsCacheKey( $username ) { + return wfMemcKey( 'backend', $this->getName(), 'usercreds', $username ); + } + /** * @see FileBackendStore::doClearCache() */