diff options
author | Adrian Brzezinski <adrian.brzezinski@eo.pl> | 2020-01-14 09:47:18 +0100 |
---|---|---|
committer | Adrian Brzezinski <adrian.brzezinski@eo.pl> | 2020-04-27 14:16:50 +0200 |
commit | 354c0996d83c853ee88dd1a26ce47e15f9866504 (patch) | |
tree | ada6b1a733c543082d1b01a5e7b9acf57b41969a /lib | |
parent | 2d7f71facaea2c7527db1d0e95fdf27e15be9d4d (diff) | |
download | nextcloud-server-354c0996d83c853ee88dd1a26ce47e15f9866504.tar.gz nextcloud-server-354c0996d83c853ee88dd1a26ce47e15f9866504.zip |
It's a fix for issue #14116,
Improves efficiency when downloading files from Swift storage.
Before, files were downloaded and then pushed back to user.
That behaevior causes all kinds of performance problems.
Now, files are streamed directly to user.
Signed-off-by: Adrian Brzezinski <adrian.brzezinski@eo.pl>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/Files/ObjectStore/Swift.php | 37 | ||||
-rw-r--r-- | lib/private/Files/ObjectStore/SwiftFactory.php | 29 |
2 files changed, 48 insertions, 18 deletions
diff --git a/lib/private/Files/ObjectStore/Swift.php b/lib/private/Files/ObjectStore/Swift.php index 9a2aa82295e..e0d819f8a2a 100644 --- a/lib/private/Files/ObjectStore/Swift.php +++ b/lib/private/Files/ObjectStore/Swift.php @@ -25,6 +25,12 @@ namespace OC\Files\ObjectStore; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Exception\ConnectException; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\Exception\BadResponseException; +use GuzzleHttp\HandlerStack; use function GuzzleHttp\Psr7\stream_for; use Icewind\Streams\RetryWrapper; use OCP\Files\NotFoundException; @@ -89,30 +95,33 @@ class Swift implements IObjectStore { /** * @param string $urn the unified resource name used to identify the object * @return resource stream with the read data - * @throws \Exception from openstack lib when something goes wrong + * @throws \Exception from openstack or GuzzleHttp libs when something goes wrong * @throws NotFoundException if file does not exist */ public function readObject($urn) { try { - $object = $this->getContainer()->getObject($urn); - - // we need to keep a reference to objectContent or - // the stream will be closed before we can do anything with it - $objectContent = $object->download(); - } catch (BadResponseError $e) { - if ($e->getResponse()->getStatusCode() === 404) { + $publicUri = $this->getContainer()->getObject($urn)->getPublicUri(); + $tokenId = $this->swiftFactory->getCachedTokenId(); + + $response = (new Client())->request('GET', $publicUri, + [ + 'stream' => true, + 'headers' => [ + 'X-Auth-Token' => $tokenId, + 'Cache-Control' => 'no-cache' + ], + ] + ); + + } catch (BadResponseException $e) { + if ($e->getResponse() && $e->getResponse()->getStatusCode() === 404) { throw new NotFoundException("object $urn not found in object store"); } else { throw $e; } } - $objectContent->rewind(); - - $stream = $objectContent->detach(); - // save the object content in the context of the stream to prevent it being gc'd until the stream is closed - stream_context_set_option($stream, 'swift', 'content', $objectContent); - return RetryWrapper::wrap($stream); + return RetryWrapper::wrap($response->getBody()->detach()); } /** diff --git a/lib/private/Files/ObjectStore/SwiftFactory.php b/lib/private/Files/ObjectStore/SwiftFactory.php index 7c8a1b995b4..6950b15d3f2 100644 --- a/lib/private/Files/ObjectStore/SwiftFactory.php +++ b/lib/private/Files/ObjectStore/SwiftFactory.php @@ -69,6 +69,25 @@ class SwiftFactory { $this->logger = $logger; } + /** + * Gets currently cached token id + * + * @return string + * @throws StorageAuthException + */ + public function getCachedTokenId() { + if ( !isset($this->params['cachedToken']) ) { + throw new StorageAuthException('Unauthenticated ObjectStore connection'); + } + + // Is it V2 token? + if ( isset($this->params['cachedToken']['token']) ) { + return $this->params['cachedToken']['token']['id']; + } + + return $this->params['cachedToken']['id']; + } + private function getCachedToken(string $cacheKey) { $cachedTokenString = $this->cache->get($cacheKey . '/token'); if ($cachedTokenString) { @@ -81,10 +100,10 @@ class SwiftFactory { private function cacheToken(Token $token, string $serviceUrl, string $cacheKey) { if ($token instanceof \OpenStack\Identity\v3\Models\Token) { // for v3 the catalog is cached as part of the token, so no need to cache $serviceUrl separately - $value = json_encode($token->export()); + $value = $token->export(); } else { /** @var \OpenStack\Identity\v2\Models\Token $token */ - $value = json_encode([ + $value = [ 'serviceUrl' => $serviceUrl, 'token' => [ 'issued_at' => $token->issuedAt->format('c'), @@ -92,9 +111,11 @@ class SwiftFactory { 'id' => $token->id, 'tenant' => $token->tenant ] - ]); + ]; } - $this->cache->set($cacheKey . '/token', $value); + + $this->params['cachedToken'] = $value; + $this->cache->set($cacheKey . '/token', json_encode($value)); } /** |