Skip to content

Commit 94d16bf

Browse files
committed
d
Signed-off-by: Maxence Lange <[email protected]>
1 parent 80d712e commit 94d16bf

4 files changed

Lines changed: 121 additions & 33 deletions

File tree

core/Command/Config/ListConfigs.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
112112
* @param bool $noSensitiveValues
113113
* @return array
114114
*/
115-
protected function getSystemConfigs($noSensitiveValues) {
115+
protected function getSystemConfigs(bool $noSensitiveValues): array {
116116
$keys = $this->systemConfig->getKeys();
117117

118118
$configs = [];

core/Migrations/Version29000Date20231126110901.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
4141
if (!$schema->hasTable('appconfig_lazy')) {
4242
$table = $schema->createTable('appconfig_lazy');
4343
$table->addColumn('app_id', Types::STRING, ['length' => 32]);
44+
$table->addColumn('extra', Types::STRING, ['length' => 32]);
4445
$table->addColumn('config_key', Types::STRING, ['length' => 64]);
4546
$table->addColumn('config_value', Types::TEXT);
4647

4748
$table->setPrimaryKey(['app_id', 'config_key'], 'lazy_app_prim');
48-
$table->addIndex(['app_id'], 'lazy_app_id_i');
49+
$table->addIndex(['app_id', 'extra'], 'lazy_app_id_i');
50+
$table->addIndex(['app_id', 'extra', 'config_key'], 'lazy_app_id_key_i');
4951
$updated = true;
5052
}
5153

lib/private/LazyConfig.php

Lines changed: 111 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,34 @@
3232
use OCP\ILazyConfig;
3333
use Psr\Log\LoggerInterface;
3434

35+
/**
36+
* Lazy load of your app config values.
37+
*
38+
* store a value:
39+
* $this->lazyConfig->setValueString('my_app', 'my_param', 'configuration_value');
40+
*
41+
* retrieve a value:
42+
* $this->lazyConfig->getValueString('my_app', 'my_param', 'default_value');
43+
*
44+
* The caching is made in a way that all configured value of my_app
45+
* are retrieved when getValue*() is called for the first time
46+
*
47+
* There is a way to get values only when needed, without filling the cache with rarely needed values
48+
* when getValue*() is called with 'my_app'. A group of values can be set by using 'my_app.my_group':
49+
*
50+
* $this->lazyConfig->setValueString('my_app.my_group', 'my_param', 'configuration_value');
51+
* $this->lazyConfig->getValueString('my_app.my_group', 'my_param', 'default_value');
52+
*
53+
* Values set in group 'my_group' are not cached when calling getValue*() on 'my_app', but
54+
* only when using 'my_app.my_group'.
55+
*
56+
* @since 29.0.0
57+
*/
3558
class LazyConfig implements ILazyConfig {
36-
private array $cache = [];
59+
public const APP_EXTRA_SEPARATOR = '.';
60+
61+
private array $cache = []; // cached config
62+
private array $extra = []; // list of loaded extra config
3763
protected array $sensitiveValues = [
3864
'circles' => [
3965
'/^key_pairs$/',
@@ -178,8 +204,8 @@ public function getApps(bool $loadValues = true): array {
178204
* @since 29.0.0
179205
*/
180206
public function getKeys(string $app): array {
181-
$this->loadConfig($app);
182-
return array_keys($this->cache[$app]);
207+
$appId = $this->loadConfig($app);
208+
return array_keys($this->cache[$appId]);
183209
}
184210

185211
/**
@@ -188,12 +214,11 @@ public function getKeys(string $app): array {
188214
*
189215
* @inheritDoc
190216
* @return bool
191-
* @throws DBException
192217
* @since 29.0.0
193218
*/
194219
public function hasKey(string $app, string $key): bool {
195-
$this->loadConfig($app);
196-
return isset($this->cache[$app][$key]);
220+
$appId = $this->loadConfig($app);
221+
return isset($this->cache[$appId][$key]);
197222
}
198223

199224
/**
@@ -202,20 +227,19 @@ public function hasKey(string $app, string $key): bool {
202227
*
203228
* @inheritDoc
204229
* @return array
205-
* @throws DBException
206230
* @since 29.0.0
207231
*/
208232
public function getValues(string $app, string $key = ''): array {
209-
$this->loadConfig($app);
233+
$appId = $this->loadConfig($app, true);
210234

211235
if ($key === '') {
212-
return $this->cache[$app] ?? [];
236+
return $this->cache[$appId] ?? [];
213237
}
214238

215239
$values = [];
216-
foreach (($this->cache[$app] ?? []) as $configkey => $configvalue) {
217-
if (str_starts_with($configkey, $key)) {
218-
$values[$configkey] = $configvalue;
240+
foreach (($this->cache[$appId] ?? []) as $configKey => $configValue) {
241+
if (str_starts_with($configKey, $key)) {
242+
$values[$configKey] = $configValue;
219243
}
220244
}
221245

@@ -251,12 +275,12 @@ public function getFilteredValues(string $app): array {
251275
* @since 29.0.0
252276
*/
253277
public function getValueString(string $app, string $key, string $default = ''): string {
254-
$this->loadConfig($app);
278+
$appId = $this->loadConfig($app);
255279
if (!$this->hasKey($app, $key)) {
256280
return $default;
257281
}
258282

259-
return $this->cache[$app][$key];
283+
return $this->cache[$appId][$key];
260284
}
261285

262286
/**
@@ -315,15 +339,17 @@ public function getValueArray(string $app, string $key, array $default = []): ar
315339
* @since 29.0.0
316340
*/
317341
public function setValueString(string $app, string $key, string $value): bool {
318-
$this->loadConfig($app);
342+
$appId = $this->loadConfig($app);
319343
$updated = !$this->hasKey($app, $key) || $value !== $this->getValueString($app, $key);
320344
if (!$updated) {
321345
return false;
322346
}
323347

348+
[, $extra] = $this->parseExtra($app);
324349
$insert = $this->connection->getQueryBuilder();
325350
$insert->insert('appconfig_lazy')
326-
->setValue('app_id', $insert->createNamedParameter($app))
351+
->setValue('app_id', $insert->createNamedParameter($appId))
352+
->setValue('extra', $insert->createNamedParameter($extra))
327353
->setValue('config_key', $insert->createNamedParameter($key))
328354
->setValue('config_value', $insert->createNamedParameter($value));
329355
try {
@@ -336,6 +362,7 @@ public function setValueString(string $app, string $key, string $value): bool {
336362
$update = $this->connection->getQueryBuilder();
337363
$update->update('appconfig_lazy')
338364
->set('config_value', $update->createNamedParameter($value))
365+
->set('extra', $update->createNamedParameter($extra))
339366
->where($update->expr()->eq('app_id', $update->createNamedParameter($app)))
340367
->andWhere($update->expr()->eq('config_key', $update->createNamedParameter($key)));
341368
$update->executeStatement();
@@ -422,56 +449,109 @@ public function unsetKey(string $app, string $key): void {
422449
* @since 29.0.0
423450
*/
424451
public function deleteApp(string $app): void {
425-
$this->loadConfig($app);
452+
$appId = $this->loadConfig($app);
453+
//[$appId,] = $this->parseExtra($app);
426454

427455
$sql = $this->connection->getQueryBuilder();
428456
$sql->delete('appconfig_lazy')
429-
->where($sql->expr()->eq('app_id', $sql->createNamedParameter($app)));
457+
->where($sql->expr()->eq('app_id', $sql->createNamedParameter($appId)));
430458
$sql->executeStatement();
431459

432-
$this->clearCache($app);
460+
$this->clearCache($appId);
433461
}
434462

435463
/**
436464
* @param string $app
437465
*
438-
* @throws DBException
466+
* @return array<string, string>
439467
*/
440-
private function loadConfig(string $app): void {
441-
if (array_key_exists($app, $this->cache)) {
442-
return;
468+
private function parseExtra(string $app): array {
469+
if (!strpos($app, self::APP_EXTRA_SEPARATOR)) {
470+
return [$app, ''];
443471
}
444472

445-
$this->cache[$app] = [];
473+
return explode(self::APP_EXTRA_SEPARATOR, $app, 2);
474+
}
446475

447-
$sql = $this->connection->getQueryBuilder();
448-
$sql->select('config_key', 'config_value')
476+
/**
477+
* @param string $app
478+
* @param bool $includeExtras
479+
*
480+
* @return string
481+
*/
482+
private function loadConfig(string $app, bool $includeExtras = false): string {
483+
[$appId, $extra] = $this->parseExtra($app);
484+
if ($this->isLoaded($appId, $extra)) {
485+
return $appId;
486+
}
487+
488+
if (!array_key_exists($appId, $this->cache)) {
489+
$this->cache[$appId] = [];
490+
$this->extra[$appId] = [];
491+
}
492+
493+
$qb = $this->connection->getQueryBuilder();
494+
$qb->select('config_key', 'config_value')
449495
->from('appconfig_lazy')
450-
->where($sql->expr()->eq('app_id', $sql->createNamedParameter($app)));
451-
$result = $sql->execute();
496+
->where($qb->expr()->eq('app_id', $qb->createNamedParameter($appId)));
497+
498+
if (!$includeExtras) {
499+
$qb->andWhere($qb->expr()->eq('extra', $qb->createNamedParameter($extra)));
500+
}
501+
$result = $qb->execute();
452502

453503
$rows = $result->fetchAll();
454504
foreach ($rows as $row) {
455-
$this->cache[$app][$row['config_key']] = $row['config_value'];
505+
$this->cache[$appId][$row['config_key']] = $row['config_value'];
506+
$this->setLoadedStatus($appId, $extra);
456507
}
457508
$result->closeCursor();
509+
510+
return $appId;
458511
}
459512

460513
/**
461514
* @throws DBException
462515
*/
463516
private function loadConfigAll(): void {
464517
$sql = $this->connection->getQueryBuilder();
465-
$sql->select('app_id', 'config_key', 'config_value')
518+
$sql->select('app_id', 'extra', 'config_key', 'config_value')
466519
->from('appconfig_lazy');
467520
$result = $sql->execute();
468521

469522
$rows = $result->fetchAll();
470523
foreach ($rows as $row) {
471524
$this->cache[$row['app_id']][$row['config_key']] = $row['config_value'];
525+
$this->setLoadedStatus($row['app_id'], $row['extra']);
526+
}
527+
}
528+
529+
530+
private function isLoaded(string $appId, string $extra): bool {
531+
if (!array_key_exists($appId, $this->cache)) {
532+
return false;
533+
}
534+
535+
if (!in_array($extra, $this->extra[$appId])) {
536+
return false;
537+
}
538+
539+
return true;
540+
}
541+
542+
public function currentCache(): void {
543+
echo 'current cache: ' . json_encode($this->cache, JSON_PRETTY_PRINT) . "\n";
544+
}
545+
546+
private function setLoadedStatus(string $appId, string $extra): void {
547+
if (in_array($extra, $this->extra[$appId] ?? [])) {
548+
return;
472549
}
550+
551+
$this->extra[$appId][] = $extra;
473552
}
474553

554+
475555
/**
476556
* @inheritDoc
477557
* @param string $app
@@ -481,6 +561,7 @@ private function loadConfigAll(): void {
481561
public function clearCache(string $app = ''): void {
482562
if ($app !== '') {
483563
unset($this->cache[$app]);
564+
unset($this->extra[$app]);
484565
return;
485566
}
486567

tests/Core/Command/Config/ListConfigsTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use OC\SystemConfig;
2626
use OCP\IAppConfig;
2727
use OCP\IConfig;
28+
use OCP\ILazyConfig;
2829
use Symfony\Component\Console\Input\InputInterface;
2930
use Symfony\Component\Console\Output\OutputInterface;
3031
use Test\TestCase;
@@ -52,12 +53,16 @@ protected function setUp(): void {
5253
$appConfig = $this->appConfig = $this->getMockBuilder(IAppConfig::class)
5354
->disableOriginalConstructor()
5455
->getMock();
56+
$lazyConfig = $this->lazyConfig = $this->getMockBuilder(ILazyConfig::class)
57+
->disableOriginalConstructor()
58+
->getMock();
5559
$this->consoleInput = $this->getMockBuilder(InputInterface::class)->getMock();
5660
$this->consoleOutput = $this->getMockBuilder(OutputInterface::class)->getMock();
5761

5862
/** @var \OC\SystemConfig $systemConfig */
5963
/** @var \OCP\IAppConfig $appConfig */
60-
$this->command = new ListConfigs($systemConfig, $appConfig);
64+
/** @var \OCP\ILazyConfig $lazyConfig */
65+
$this->command = new ListConfigs($systemConfig, $appConfig, $lazyConfig);
6166
}
6267

6368
public function listData() {

0 commit comments

Comments
 (0)