Skip to content

Commit 9e2f07b

Browse files
Merge pull request #56395 from nextcloud/carl/cache-bucket-exists
perf(s3): Cache whether bucket exists
2 parents 0f5bf92 + a228ffa commit 9e2f07b

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

lib/private/Files/ObjectStore/S3ConnectionTrait.php

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
use GuzzleHttp\Promise\Create;
1616
use GuzzleHttp\Promise\RejectedPromise;
1717
use OCP\Files\StorageNotAvailableException;
18+
use OCP\ICache;
19+
use OCP\ICacheFactory;
1820
use OCP\ICertificateManager;
1921
use OCP\Server;
2022
use Psr\Log\LoggerInterface;
@@ -28,6 +30,8 @@ trait S3ConnectionTrait {
2830

2931
protected ?S3Client $connection = null;
3032

33+
private ?ICache $existingBucketsCache = null;
34+
3135
protected function parseParams($params) {
3236
if (empty($params['bucket'])) {
3337
throw new \Exception('Bucket has to be configured.');
@@ -82,6 +86,11 @@ public function getConnection() {
8286
return $this->connection;
8387
}
8488

89+
if ($this->existingBucketsCache === null) {
90+
$this->existingBucketsCache = Server::get(ICacheFactory::class)
91+
->createLocal('s3-bucket-exists-cache');
92+
}
93+
8594
$scheme = (isset($this->params['use_ssl']) && $this->params['use_ssl'] === false) ? 'http' : 'https';
8695
$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
8796

@@ -143,22 +152,30 @@ public function getConnection() {
143152
['app' => 'objectstore']);
144153
}
145154

146-
if ($this->params['verify_bucket_exists'] && !$this->connection->doesBucketExist($this->bucket)) {
147-
try {
148-
$logger->info('Bucket "' . $this->bucket . '" does not exist - creating it.', ['app' => 'objectstore']);
149-
if (!$this->connection::isBucketDnsCompatible($this->bucket)) {
150-
throw new StorageNotAvailableException('The bucket will not be created because the name is not dns compatible, please correct it: ' . $this->bucket);
151-
}
152-
$this->connection->createBucket(['Bucket' => $this->bucket]);
153-
$this->testTimeout();
154-
} catch (S3Exception $e) {
155-
$logger->debug('Invalid remote storage.', [
156-
'exception' => $e,
157-
'app' => 'objectstore',
158-
]);
159-
if ($e->getAwsErrorCode() !== 'BucketAlreadyOwnedByYou') {
160-
throw new StorageNotAvailableException('Creation of bucket "' . $this->bucket . '" failed. ' . $e->getMessage());
155+
if ($this->params['verify_bucket_exists']) {
156+
$cacheKey = $this->params['hostname'] . $this->bucket;
157+
$exist = $this->existingBucketsCache->get($cacheKey) === 1;
158+
159+
if (!$exist) {
160+
if (!$this->connection->doesBucketExist($this->bucket)) {
161+
try {
162+
$logger->info('Bucket "' . $this->bucket . '" does not exist - creating it.', ['app' => 'objectstore']);
163+
if (!$this->connection::isBucketDnsCompatible($this->bucket)) {
164+
throw new StorageNotAvailableException('The bucket will not be created because the name is not dns compatible, please correct it: ' . $this->bucket);
165+
}
166+
$this->connection->createBucket(['Bucket' => $this->bucket]);
167+
$this->testTimeout();
168+
} catch (S3Exception $e) {
169+
$logger->debug('Invalid remote storage.', [
170+
'exception' => $e,
171+
'app' => 'objectstore',
172+
]);
173+
if ($e->getAwsErrorCode() !== 'BucketAlreadyOwnedByYou') {
174+
throw new StorageNotAvailableException('Creation of bucket "' . $this->bucket . '" failed. ' . $e->getMessage());
175+
}
176+
}
161177
}
178+
$this->existingBucketsCache->set($cacheKey, 1);
162179
}
163180
}
164181

0 commit comments

Comments
 (0)