Skip to content

Commit 12b77eb

Browse files
committed
refactor(preview-object-store): Refactor object store backend
Simplify logic Signed-off-by: Carl Schwan <[email protected]>
1 parent b8c5d86 commit 12b77eb

File tree

1 file changed

+69
-57
lines changed

1 file changed

+69
-57
lines changed

lib/private/Preview/Storage/ObjectStorePreviewStorage.php

Lines changed: 69 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222

2323
/**
2424
* @psalm-import-type ObjectStoreConfig from PrimaryObjectStoreConfig
25-
* @psalm-type ObjectStoreDefinition = array{store: IObjectStore, objectPrefix: string, config?: ObjectStoreConfig}
25+
* @psalm-type ObjectStoreDefinition = array{store: IObjectStore, urn: string}
2626
*/
2727
class ObjectStorePreviewStorage implements IPreviewStorage {
2828

2929
/**
30-
* @var array<string, array<string, ObjectStoreDefinition>>
30+
* @var array<string, array<string, IObjectStore>>
3131
*/
3232
private array $objectStoreCache = [];
3333

@@ -49,13 +49,12 @@ public function writePreview(Preview $preview, mixed $stream): int {
4949
});
5050

5151
[
52-
'objectPrefix' => $objectPrefix,
52+
'urn' => $urn,
5353
'store' => $store,
54-
'config' => $config,
55-
] = $this->getObjectStoreForPreview($preview);
54+
] = $this->getObjectStoreInfoForNewPreview($preview);
5655

5756
try {
58-
$store->writeObject($this->constructUrn($objectPrefix, $preview->getId()), $countStream);
57+
$store->writeObject($urn, $countStream);
5958
} catch (\Exception $exception) {
6059
throw new NotPermittedException('Unable to save preview to object store', previous: $exception);
6160
}
@@ -65,24 +64,26 @@ public function writePreview(Preview $preview, mixed $stream): int {
6564
#[Override]
6665
public function readPreview(Preview $preview): mixed {
6766
[
68-
'objectPrefix' => $objectPrefix,
67+
'urn' => $urn,
6968
'store' => $store,
70-
] = $this->getObjectStoreForPreview($preview);
69+
] = $this->getObjectStoreInfoForExistingPreview($preview);
70+
7171
try {
72-
return $store->readObject($this->constructUrn($objectPrefix, $preview->getId()));
72+
return $store->readObject($urn);
7373
} catch (\Exception $exception) {
74-
throw new NotPermittedException('Unable to read preview from object store', previous: $exception);
74+
throw new NotPermittedException('Unable to read preview from object store with urn:' . $urn, previous: $exception);
7575
}
7676
}
7777

7878
#[Override]
7979
public function deletePreview(Preview $preview): void {
8080
[
81-
'objectPrefix' => $objectPrefix,
81+
'urn' => $urn,
8282
'store' => $store,
83-
] = $this->getObjectStoreForPreview($preview);
83+
] = $this->getObjectStoreInfoForExistingPreview($preview);
84+
8485
try {
85-
$store->deleteObject($this->constructUrn($objectPrefix, $preview->getId()));
86+
$store->deleteObject($urn);
8687
} catch (\Exception $exception) {
8788
throw new NotPermittedException('Unable to delete preview from object store', previous: $exception);
8889
}
@@ -91,72 +92,83 @@ public function deletePreview(Preview $preview): void {
9192
#[Override]
9293
public function migratePreview(Preview $preview, SimpleFile $file): void {
9394
// Just set the Preview::bucket and Preview::objectStore
94-
$this->getObjectStoreForPreview($preview, true);
95+
$this->getObjectStoreInfoForNewPreview($preview, migration: true);
9596
$this->previewMapper->update($preview);
9697
}
9798

9899
/**
99100
* @return ObjectStoreDefinition
100101
*/
101-
private function getObjectStoreForPreview(Preview $preview, bool $oldFallback = false): array {
102-
if ($preview->getObjectStoreName() === null) {
103-
$config = $this->objectStoreConfig->getObjectStoreConfiguration($oldFallback ? 'root' : 'preview');
104-
$objectStoreName = $this->objectStoreConfig->resolveAlias($oldFallback ? 'root' : 'preview');
105-
106-
$bucketName = $config['arguments']['bucket'];
107-
if ($config['arguments']['multibucket']) {
108-
if ($this->isMultibucketPreviewDistributionEnabled) {
109-
$oldLocationArray = str_split(substr(md5((string)$preview->getFileId()), 0, 2));
110-
$bucketNumber = hexdec('0x' . $oldLocationArray[0]) * 16 + hexdec('0x' . $oldLocationArray[0]);
111-
$bucketName .= '-preview-' . $bucketNumber;
112-
} else {
113-
$bucketName .= '0';
114-
}
115-
}
116-
$config['arguments']['bucket'] = $bucketName;
102+
private function getObjectStoreInfoForExistingPreview(Preview $preview): array {
103+
assert(!empty($preview->getObjectStoreName()));
104+
assert(!empty($preview->getBucketName()));
105+
106+
$config = $this->objectStoreConfig->getObjectStoreConfiguration($preview->getObjectStoreName());
107+
$config['arguments']['bucket'] = $preview->getBucketName();
108+
$objectStoreName = $preview->getObjectStoreName();
109+
110+
return [
111+
'urn' => $this->getUrn($preview, $config),
112+
'store' => $this->getObjectStore($objectStoreName, $config),
113+
];
114+
}
117115

118-
$locationId = $this->previewMapper->getLocationId($bucketName, $objectStoreName);
119-
$preview->setLocationId($locationId);
120-
$preview->setObjectStoreName($objectStoreName);
121-
$preview->setBucketName($bucketName);
122-
} else {
123-
$config = $this->objectStoreConfig->getObjectStoreConfiguration($preview->getObjectStoreName());
124-
$config['arguments']['bucket'] = $bucketName = $preview->getBucketName();
125-
$objectStoreName = $preview->getObjectStoreName();
116+
/**
117+
* @return ObjectStoreDefinition
118+
*/
119+
private function getObjectStoreInfoForNewPreview(Preview $preview, bool $migration = false): array {
120+
// When migrating old previews, use the 'root' object store configuration
121+
$config = $this->objectStoreConfig->getObjectStoreConfiguration($migration ? 'root' : 'preview');
122+
$objectStoreName = $this->objectStoreConfig->resolveAlias($migration ? 'root' : 'preview');
123+
124+
$bucketName = $config['arguments']['bucket'];
125+
if ($config['arguments']['multibucket']) {
126+
if ($this->isMultibucketPreviewDistributionEnabled) {
127+
// Spread the previews on different buckets depending on their corresponding fileId
128+
$oldLocationArray = str_split(substr(md5((string)$preview->getFileId()), 0, 2));
129+
$bucketNumber = hexdec('0x' . $oldLocationArray[0]) * 16 + hexdec('0x' . $oldLocationArray[0]);
130+
$bucketName .= '-preview-' . $bucketNumber;
131+
} else {
132+
// Put all previews in the root (0) bucket
133+
$bucketName .= '0';
134+
}
126135
}
136+
$config['arguments']['bucket'] = $bucketName;
137+
138+
// Get the locationId corresponding to the bucketName and objectStoreName, this will create
139+
// a new one, if no matching location is found in the DB.
140+
$locationId = $this->previewMapper->getLocationId($bucketName, $objectStoreName);
141+
$preview->setLocationId($locationId);
142+
$preview->setObjectStoreName($objectStoreName);
143+
$preview->setBucketName($bucketName);
144+
145+
return [
146+
'urn' => $this->getUrn($preview, $config),
147+
'store' => $this->getObjectStore($objectStoreName, $config),
148+
];
149+
}
127150

128-
$objectPrefix = $this->getObjectPrefix($preview, $config);
151+
private function getObjectStore(string $objectStoreName, array $config): IObjectStore {
152+
$bucketName = $config['arguments']['bucket'];
129153

130154
if (!isset($this->objectStoreCache[$objectStoreName])) {
131155
$this->objectStoreCache[$objectStoreName] = [];
132-
$this->objectStoreCache[$objectStoreName][$bucketName] = [
133-
'store' => $this->objectStoreConfig->buildObjectStore($config),
134-
'objectPrefix' => $objectPrefix,
135-
'config' => $config,
136-
];
156+
$this->objectStoreCache[$objectStoreName][$bucketName] = $this->objectStoreConfig->buildObjectStore($config);
137157
} elseif (!isset($this->objectStoreCache[$objectStoreName][$bucketName])) {
138-
$this->objectStoreCache[$objectStoreName][$bucketName] = [
139-
'store' => $this->objectStoreConfig->buildObjectStore($config),
140-
'objectPrefix' => $objectPrefix,
141-
'config' => $config,
142-
];
158+
$this->objectStoreCache[$objectStoreName][$bucketName] = $this->objectStoreConfig->buildObjectStore($config);
143159
}
144160

145161
return $this->objectStoreCache[$objectStoreName][$bucketName];
146162
}
147163

148-
private function constructUrn(string $objectPrefix, int $id): string {
149-
return $objectPrefix . $id;
150-
}
151-
152-
public function getObjectPrefix(Preview $preview, array $config): string {
164+
public function getUrn(Preview $preview, array $config): string {
153165
if ($preview->getOldFileId()) {
154-
return $config['arguments']['objectPrefix'] ?? 'uri:oid:';
166+
return ($config['arguments']['objectPrefix'] ?? 'urn:oid:') . $preview->getOldFileId();
155167
}
156168
if (isset($config['arguments']['objectPrefix'])) {
157-
return $config['arguments']['objectPrefix'] . 'preview:';
169+
return ($config['arguments']['objectPrefix'] . 'preview:') . $preview->getId();
158170
} else {
159-
return 'uri:oid:preview:';
171+
return 'uri:oid:preview:' . $preview->getId();
160172
}
161173
}
162174

0 commit comments

Comments
 (0)