Completed
Push — master ( e89a8d...1fdcfe )
by
unknown
28:49
created
lib/private/Memcache/Factory.php 1 patch
Indentation   +226 added lines, -226 removed lines patch added patch discarded remove patch
@@ -18,230 +18,230 @@
 block discarded – undo
18 18
 use Psr\Log\LoggerInterface;
19 19
 
20 20
 class Factory implements ICacheFactory {
21
-	public const NULL_CACHE = NullCache::class;
22
-
23
-	protected ?string $globalPrefix = null;
24
-	/**
25
-	 * @var class-string<ICache> $localCacheClass
26
-	 */
27
-	protected string $localCacheClass;
28
-
29
-	/**
30
-	 * @var class-string<ICache> $distributedCacheClass
31
-	 */
32
-	protected string $distributedCacheClass;
33
-
34
-	/**
35
-	 * @var class-string<IMemcache> $lockingCacheClass
36
-	 */
37
-	protected string $lockingCacheClass;
38
-
39
-	/**
40
-	 * @param ?class-string<ICache> $localCacheClass
41
-	 * @param ?class-string<ICache> $distributedCacheClass
42
-	 * @param ?class-string<IMemcache> $lockingCacheClass
43
-	 */
44
-	public function __construct(
45
-		protected LoggerInterface $logger,
46
-		protected IProfiler $profiler,
47
-		protected ServerVersion $serverVersion,
48
-		?string $localCacheClass = null,
49
-		?string $distributedCacheClass = null,
50
-		?string $lockingCacheClass = null,
51
-		protected string $logFile = '',
52
-	) {
53
-		if (!$localCacheClass) {
54
-			$localCacheClass = self::NULL_CACHE;
55
-		}
56
-		$localCacheClass = ltrim($localCacheClass, '\\');
57
-
58
-		if (!$distributedCacheClass) {
59
-			$distributedCacheClass = $localCacheClass;
60
-		}
61
-		$distributedCacheClass = ltrim($distributedCacheClass, '\\');
62
-
63
-		$missingCacheMessage = 'Memcache {class} not available for {use} cache';
64
-		$missingCacheHint = 'Is the matching PHP module installed and enabled?';
65
-		if (!class_exists($localCacheClass)
66
-			|| !is_a($localCacheClass, ICache::class, true)
67
-			|| !$localCacheClass::isAvailable()
68
-		) {
69
-			if (\OC::$CLI && !defined('PHPUNIT_RUN') && $localCacheClass === APCu::class) {
70
-				// CLI should not fail if APCu is not available but fallback to NullCache.
71
-				// This can be the case if APCu is used without apc.enable_cli=1.
72
-				// APCu however cannot be shared between PHP instances (CLI and web) anyway.
73
-				$localCacheClass = self::NULL_CACHE;
74
-			} else {
75
-				throw new \OCP\HintException(strtr($missingCacheMessage, [
76
-					'{class}' => $localCacheClass, '{use}' => 'local'
77
-				]), $missingCacheHint);
78
-			}
79
-		}
80
-
81
-		if (!class_exists($distributedCacheClass)
82
-			|| !is_a($distributedCacheClass, ICache::class, true)
83
-			|| !$distributedCacheClass::isAvailable()
84
-		) {
85
-			if (\OC::$CLI && !defined('PHPUNIT_RUN') && $distributedCacheClass === APCu::class) {
86
-				// CLI should not fail if APCu is not available but fallback to NullCache.
87
-				// This can be the case if APCu is used without apc.enable_cli=1.
88
-				// APCu however cannot be shared between Nextcloud (PHP) instances anyway.
89
-				$distributedCacheClass = self::NULL_CACHE;
90
-			} else {
91
-				throw new \OCP\HintException(strtr($missingCacheMessage, [
92
-					'{class}' => $distributedCacheClass, '{use}' => 'distributed'
93
-				]), $missingCacheHint);
94
-			}
95
-		}
96
-
97
-		if (!$lockingCacheClass
98
-			|| !class_exists($lockingCacheClass)
99
-			|| !is_a($lockingCacheClass, IMemcache::class, true)
100
-			|| !$lockingCacheClass::isAvailable()
101
-		) {
102
-			// don't fall back since the fallback might not be suitable for storing lock
103
-			$lockingCacheClass = self::NULL_CACHE;
104
-		}
105
-		/** @var class-string<IMemcache> */
106
-		$lockingCacheClass = ltrim($lockingCacheClass, '\\');
107
-
108
-		$this->localCacheClass = $localCacheClass;
109
-		$this->distributedCacheClass = $distributedCacheClass;
110
-		$this->lockingCacheClass = $lockingCacheClass;
111
-	}
112
-
113
-	protected function getGlobalPrefix(): string {
114
-		if ($this->globalPrefix === null) {
115
-			$config = \OCP\Server::get(SystemConfig::class);
116
-			$maintenanceMode = $config->getValue('maintenance', false);
117
-			$versions = [];
118
-			if ($config->getValue('installed', false) && !$maintenanceMode) {
119
-				$appConfig = \OCP\Server::get(IAppConfig::class);
120
-				// only get the enabled apps to clear the cache in case an app is enabled or disabled (e.g. clear routes)
121
-				$versions = $appConfig->getAppInstalledVersions(true);
122
-				ksort($versions);
123
-			} else {
124
-				// if not installed or in maintenance mode, we should distinguish between both states.
125
-				$versions['core:maintenance'] = $maintenanceMode ? '1' : '0';
126
-			}
127
-			$versions['core'] = implode('.', $this->serverVersion->getVersion());
128
-
129
-			// Include instanceid in the prefix, in case multiple instances use the same cache (e.g. same FPM pool)
130
-			$instanceid = $config->getValue('instanceid');
131
-			$installedApps = implode(',', array_keys($versions)) . implode(',', array_values($versions));
132
-			$this->globalPrefix = hash('xxh128', $instanceid . $installedApps);
133
-		}
134
-		return $this->globalPrefix;
135
-	}
136
-
137
-	/**
138
-	 * Override the global prefix for a specific closure.
139
-	 * This should only be used internally for bootstrapping purpose!
140
-	 *
141
-	 * @param \Closure $closure - The closure with the cache factory as the first parameter
142
-	 */
143
-	public function withServerVersionPrefix(\Closure $closure): void {
144
-		$backupPrefix = $this->globalPrefix;
145
-
146
-		// Include instanceid in the prefix, in case multiple instances use the same cache (e.g. same FPM pool)
147
-		$instanceid = \OCP\Server::get(SystemConfig::class)->getValue('instanceid');
148
-		$this->globalPrefix = hash('xxh128', $instanceid . implode('.', $this->serverVersion->getVersion()));
149
-		$closure($this);
150
-		$this->globalPrefix = $backupPrefix;
151
-	}
152
-
153
-	/**
154
-	 * create a cache instance for storing locks
155
-	 *
156
-	 * @param string $prefix
157
-	 * @return IMemcache
158
-	 */
159
-	public function createLocking(string $prefix = ''): IMemcache {
160
-		$cache = new $this->lockingCacheClass($this->getGlobalPrefix() . '/' . $prefix);
161
-		if ($this->lockingCacheClass === Redis::class) {
162
-			if ($this->profiler->isEnabled()) {
163
-				// We only support the profiler with Redis
164
-				$cache = new ProfilerWrapperCache($cache, 'Locking');
165
-				$this->profiler->add($cache);
166
-			}
167
-
168
-			if ($this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
169
-				$cache = new LoggerWrapperCache($cache, $this->logFile);
170
-			}
171
-		}
172
-		return $cache;
173
-	}
174
-
175
-	/**
176
-	 * create a distributed cache instance
177
-	 *
178
-	 * @param string $prefix
179
-	 * @return ICache
180
-	 */
181
-	public function createDistributed(string $prefix = ''): ICache {
182
-		$cache = new $this->distributedCacheClass($this->getGlobalPrefix() . '/' . $prefix);
183
-		if ($this->distributedCacheClass === Redis::class) {
184
-			if ($this->profiler->isEnabled()) {
185
-				// We only support the profiler with Redis
186
-				$cache = new ProfilerWrapperCache($cache, 'Distributed');
187
-				$this->profiler->add($cache);
188
-			}
189
-
190
-			if ($this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
191
-				$cache = new LoggerWrapperCache($cache, $this->logFile);
192
-			}
193
-		}
194
-		return $cache;
195
-	}
196
-
197
-	/**
198
-	 * create a local cache instance
199
-	 *
200
-	 * @param string $prefix
201
-	 * @return ICache
202
-	 */
203
-	public function createLocal(string $prefix = ''): ICache {
204
-		$cache = new $this->localCacheClass($this->getGlobalPrefix() . '/' . $prefix);
205
-		if ($this->localCacheClass === Redis::class) {
206
-			if ($this->profiler->isEnabled()) {
207
-				// We only support the profiler with Redis
208
-				$cache = new ProfilerWrapperCache($cache, 'Local');
209
-				$this->profiler->add($cache);
210
-			}
211
-
212
-			if ($this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
213
-				$cache = new LoggerWrapperCache($cache, $this->logFile);
214
-			}
215
-		}
216
-		return $cache;
217
-	}
218
-
219
-	/**
220
-	 * check memcache availability
221
-	 *
222
-	 * @return bool
223
-	 */
224
-	public function isAvailable(): bool {
225
-		return $this->distributedCacheClass !== self::NULL_CACHE;
226
-	}
227
-
228
-	public function createInMemory(int $capacity = 512): ICache {
229
-		return new CappedMemoryCache($capacity);
230
-	}
231
-
232
-	/**
233
-	 * Check if a local memory cache backend is available
234
-	 *
235
-	 * @return bool
236
-	 */
237
-	public function isLocalCacheAvailable(): bool {
238
-		return $this->localCacheClass !== self::NULL_CACHE;
239
-	}
240
-
241
-	public function clearAll(): void {
242
-		$this->createLocal()->clear();
243
-		$this->createDistributed()->clear();
244
-		$this->createLocking()->clear();
245
-		$this->createInMemory()->clear();
246
-	}
21
+    public const NULL_CACHE = NullCache::class;
22
+
23
+    protected ?string $globalPrefix = null;
24
+    /**
25
+     * @var class-string<ICache> $localCacheClass
26
+     */
27
+    protected string $localCacheClass;
28
+
29
+    /**
30
+     * @var class-string<ICache> $distributedCacheClass
31
+     */
32
+    protected string $distributedCacheClass;
33
+
34
+    /**
35
+     * @var class-string<IMemcache> $lockingCacheClass
36
+     */
37
+    protected string $lockingCacheClass;
38
+
39
+    /**
40
+     * @param ?class-string<ICache> $localCacheClass
41
+     * @param ?class-string<ICache> $distributedCacheClass
42
+     * @param ?class-string<IMemcache> $lockingCacheClass
43
+     */
44
+    public function __construct(
45
+        protected LoggerInterface $logger,
46
+        protected IProfiler $profiler,
47
+        protected ServerVersion $serverVersion,
48
+        ?string $localCacheClass = null,
49
+        ?string $distributedCacheClass = null,
50
+        ?string $lockingCacheClass = null,
51
+        protected string $logFile = '',
52
+    ) {
53
+        if (!$localCacheClass) {
54
+            $localCacheClass = self::NULL_CACHE;
55
+        }
56
+        $localCacheClass = ltrim($localCacheClass, '\\');
57
+
58
+        if (!$distributedCacheClass) {
59
+            $distributedCacheClass = $localCacheClass;
60
+        }
61
+        $distributedCacheClass = ltrim($distributedCacheClass, '\\');
62
+
63
+        $missingCacheMessage = 'Memcache {class} not available for {use} cache';
64
+        $missingCacheHint = 'Is the matching PHP module installed and enabled?';
65
+        if (!class_exists($localCacheClass)
66
+            || !is_a($localCacheClass, ICache::class, true)
67
+            || !$localCacheClass::isAvailable()
68
+        ) {
69
+            if (\OC::$CLI && !defined('PHPUNIT_RUN') && $localCacheClass === APCu::class) {
70
+                // CLI should not fail if APCu is not available but fallback to NullCache.
71
+                // This can be the case if APCu is used without apc.enable_cli=1.
72
+                // APCu however cannot be shared between PHP instances (CLI and web) anyway.
73
+                $localCacheClass = self::NULL_CACHE;
74
+            } else {
75
+                throw new \OCP\HintException(strtr($missingCacheMessage, [
76
+                    '{class}' => $localCacheClass, '{use}' => 'local'
77
+                ]), $missingCacheHint);
78
+            }
79
+        }
80
+
81
+        if (!class_exists($distributedCacheClass)
82
+            || !is_a($distributedCacheClass, ICache::class, true)
83
+            || !$distributedCacheClass::isAvailable()
84
+        ) {
85
+            if (\OC::$CLI && !defined('PHPUNIT_RUN') && $distributedCacheClass === APCu::class) {
86
+                // CLI should not fail if APCu is not available but fallback to NullCache.
87
+                // This can be the case if APCu is used without apc.enable_cli=1.
88
+                // APCu however cannot be shared between Nextcloud (PHP) instances anyway.
89
+                $distributedCacheClass = self::NULL_CACHE;
90
+            } else {
91
+                throw new \OCP\HintException(strtr($missingCacheMessage, [
92
+                    '{class}' => $distributedCacheClass, '{use}' => 'distributed'
93
+                ]), $missingCacheHint);
94
+            }
95
+        }
96
+
97
+        if (!$lockingCacheClass
98
+            || !class_exists($lockingCacheClass)
99
+            || !is_a($lockingCacheClass, IMemcache::class, true)
100
+            || !$lockingCacheClass::isAvailable()
101
+        ) {
102
+            // don't fall back since the fallback might not be suitable for storing lock
103
+            $lockingCacheClass = self::NULL_CACHE;
104
+        }
105
+        /** @var class-string<IMemcache> */
106
+        $lockingCacheClass = ltrim($lockingCacheClass, '\\');
107
+
108
+        $this->localCacheClass = $localCacheClass;
109
+        $this->distributedCacheClass = $distributedCacheClass;
110
+        $this->lockingCacheClass = $lockingCacheClass;
111
+    }
112
+
113
+    protected function getGlobalPrefix(): string {
114
+        if ($this->globalPrefix === null) {
115
+            $config = \OCP\Server::get(SystemConfig::class);
116
+            $maintenanceMode = $config->getValue('maintenance', false);
117
+            $versions = [];
118
+            if ($config->getValue('installed', false) && !$maintenanceMode) {
119
+                $appConfig = \OCP\Server::get(IAppConfig::class);
120
+                // only get the enabled apps to clear the cache in case an app is enabled or disabled (e.g. clear routes)
121
+                $versions = $appConfig->getAppInstalledVersions(true);
122
+                ksort($versions);
123
+            } else {
124
+                // if not installed or in maintenance mode, we should distinguish between both states.
125
+                $versions['core:maintenance'] = $maintenanceMode ? '1' : '0';
126
+            }
127
+            $versions['core'] = implode('.', $this->serverVersion->getVersion());
128
+
129
+            // Include instanceid in the prefix, in case multiple instances use the same cache (e.g. same FPM pool)
130
+            $instanceid = $config->getValue('instanceid');
131
+            $installedApps = implode(',', array_keys($versions)) . implode(',', array_values($versions));
132
+            $this->globalPrefix = hash('xxh128', $instanceid . $installedApps);
133
+        }
134
+        return $this->globalPrefix;
135
+    }
136
+
137
+    /**
138
+     * Override the global prefix for a specific closure.
139
+     * This should only be used internally for bootstrapping purpose!
140
+     *
141
+     * @param \Closure $closure - The closure with the cache factory as the first parameter
142
+     */
143
+    public function withServerVersionPrefix(\Closure $closure): void {
144
+        $backupPrefix = $this->globalPrefix;
145
+
146
+        // Include instanceid in the prefix, in case multiple instances use the same cache (e.g. same FPM pool)
147
+        $instanceid = \OCP\Server::get(SystemConfig::class)->getValue('instanceid');
148
+        $this->globalPrefix = hash('xxh128', $instanceid . implode('.', $this->serverVersion->getVersion()));
149
+        $closure($this);
150
+        $this->globalPrefix = $backupPrefix;
151
+    }
152
+
153
+    /**
154
+     * create a cache instance for storing locks
155
+     *
156
+     * @param string $prefix
157
+     * @return IMemcache
158
+     */
159
+    public function createLocking(string $prefix = ''): IMemcache {
160
+        $cache = new $this->lockingCacheClass($this->getGlobalPrefix() . '/' . $prefix);
161
+        if ($this->lockingCacheClass === Redis::class) {
162
+            if ($this->profiler->isEnabled()) {
163
+                // We only support the profiler with Redis
164
+                $cache = new ProfilerWrapperCache($cache, 'Locking');
165
+                $this->profiler->add($cache);
166
+            }
167
+
168
+            if ($this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
169
+                $cache = new LoggerWrapperCache($cache, $this->logFile);
170
+            }
171
+        }
172
+        return $cache;
173
+    }
174
+
175
+    /**
176
+     * create a distributed cache instance
177
+     *
178
+     * @param string $prefix
179
+     * @return ICache
180
+     */
181
+    public function createDistributed(string $prefix = ''): ICache {
182
+        $cache = new $this->distributedCacheClass($this->getGlobalPrefix() . '/' . $prefix);
183
+        if ($this->distributedCacheClass === Redis::class) {
184
+            if ($this->profiler->isEnabled()) {
185
+                // We only support the profiler with Redis
186
+                $cache = new ProfilerWrapperCache($cache, 'Distributed');
187
+                $this->profiler->add($cache);
188
+            }
189
+
190
+            if ($this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
191
+                $cache = new LoggerWrapperCache($cache, $this->logFile);
192
+            }
193
+        }
194
+        return $cache;
195
+    }
196
+
197
+    /**
198
+     * create a local cache instance
199
+     *
200
+     * @param string $prefix
201
+     * @return ICache
202
+     */
203
+    public function createLocal(string $prefix = ''): ICache {
204
+        $cache = new $this->localCacheClass($this->getGlobalPrefix() . '/' . $prefix);
205
+        if ($this->localCacheClass === Redis::class) {
206
+            if ($this->profiler->isEnabled()) {
207
+                // We only support the profiler with Redis
208
+                $cache = new ProfilerWrapperCache($cache, 'Local');
209
+                $this->profiler->add($cache);
210
+            }
211
+
212
+            if ($this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
213
+                $cache = new LoggerWrapperCache($cache, $this->logFile);
214
+            }
215
+        }
216
+        return $cache;
217
+    }
218
+
219
+    /**
220
+     * check memcache availability
221
+     *
222
+     * @return bool
223
+     */
224
+    public function isAvailable(): bool {
225
+        return $this->distributedCacheClass !== self::NULL_CACHE;
226
+    }
227
+
228
+    public function createInMemory(int $capacity = 512): ICache {
229
+        return new CappedMemoryCache($capacity);
230
+    }
231
+
232
+    /**
233
+     * Check if a local memory cache backend is available
234
+     *
235
+     * @return bool
236
+     */
237
+    public function isLocalCacheAvailable(): bool {
238
+        return $this->localCacheClass !== self::NULL_CACHE;
239
+    }
240
+
241
+    public function clearAll(): void {
242
+        $this->createLocal()->clear();
243
+        $this->createDistributed()->clear();
244
+        $this->createLocking()->clear();
245
+        $this->createInMemory()->clear();
246
+    }
247 247
 }
Please login to merge, or discard this patch.