1
0
Fork 0

Merge pull request #12574 from nupplaphil/feat/keyvalue_storage

Introduce key-value storage
This commit is contained in:
Hypolite Petovan 2022-12-30 16:36:03 -05:00 committed by GitHub
commit bacf901d0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 674 additions and 118 deletions

View file

@ -115,7 +115,7 @@ if (is_readable($pidfile)) {
}
if (empty($pid) && in_array($mode, ['stop', 'status'])) {
DI::config()->set('system', 'worker_daemon_mode', false);
DI::keyValue()->set('worker_daemon_mode', false);
die("Pidfile wasn't found. Is the daemon running?\n");
}
@ -137,7 +137,7 @@ if ($mode == 'stop') {
Logger::notice('Worker daemon process was killed', ['pid' => $pid]);
DI::config()->set('system', 'worker_daemon_mode', false);
DI::keyValue()->set('worker_daemon_mode', false);
die("Worker daemon process $pid was killed.\n");
}
@ -181,7 +181,7 @@ if (!$foreground) {
DBA::connect();
}
DI::config()->set('system', 'worker_daemon_mode', true);
DI::keyValue()->set('worker_daemon_mode', true);
// Just to be sure that this script really runs endlessly
set_time_limit(0);

View file

@ -1,6 +1,6 @@
-- ------------------------------------------
-- Friendica 2023.03-dev (Giant Rhubarb)
-- DB_UPDATE_VERSION 1504
-- DB_UPDATE_VERSION 1505
-- ------------------------------------------
@ -839,6 +839,16 @@ CREATE TABLE IF NOT EXISTS `intro` (
FOREIGN KEY (`suggest-cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='';
--
-- TABLE key-value
--
CREATE TABLE IF NOT EXISTS `key-value` (
`k` varbinary(50) NOT NULL COMMENT '',
`v` mediumtext COMMENT '',
`updated_at` int unsigned NOT NULL COMMENT 'timestamp of the last update',
PRIMARY KEY(`k`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='A key value storage';
--
-- TABLE locks
--

View file

@ -40,6 +40,7 @@ Database Tables
| [inbox-status](help/database/db_inbox-status) | Status of ActivityPub inboxes |
| [intro](help/database/db_intro) | |
| [item-uri](help/database/db_item-uri) | URI and GUID for items |
| [key-value](help/database/db_key-value) | A key value storage |
| [locks](help/database/db_locks) | |
| [mail](help/database/db_mail) | private messages |
| [mailacct](help/database/db_mailacct) | Mail account data for fetching mails |

View file

@ -0,0 +1,23 @@
Table key-value
===========
A key value storage
Fields
------
| Field | Description | Type | Null | Key | Default | Extra |
| ---------- | ---------------------------- | ------------- | ---- | --- | ------- | ----- |
| k | | varbinary(50) | NO | PRI | NULL | |
| v | | mediumtext | YES | | NULL | |
| updated_at | timestamp of the last update | int unsigned | NO | | NULL | |
Indexes
------------
| Name | Fields |
| ------- | ------ |
| PRIMARY | k |
Return to [database documentation](help/database)

View file

@ -22,7 +22,7 @@
namespace Friendica\Console;
use Friendica\App;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs;
use Friendica\Core\L10n;
use Friendica\Core\Update;
@ -38,9 +38,9 @@ class PostUpdate extends \Asika\SimpleConsole\Console
*/
private $appMode;
/**
* @var IManageConfigValues
* @var IManageKeyValuePairs
*/
private $config;
private $keyValue;
/**
* @var L10n
*/
@ -60,12 +60,12 @@ HELP;
return $help;
}
public function __construct(App\Mode $appMode, IManageConfigValues $config, L10n $l10n, array $argv = null)
public function __construct(App\Mode $appMode, IManageKeyValuePairs $keyValue, L10n $l10n, array $argv = null)
{
parent::__construct($argv);
$this->appMode = $appMode;
$this->config = $config;
$this->keyValue = $keyValue;
$this->l10n = $l10n;
}
@ -83,7 +83,7 @@ HELP;
$this->out($this->getHelp());
return 0;
} elseif ($reset_version) {
$this->config->set('system', 'post_update_version', $reset_version);
$this->keyValue->set('post_update_version', $reset_version);
echo $this->l10n->t('Post update version number has been set to %s.', $reset_version) . "\n";
return 0;
}

View file

@ -0,0 +1,64 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\KeyValueStorage\Capabilities;
use Friendica\Core\KeyValueStorage\Exceptions\KeyValueStoragePersistenceException;
/**
* Interface for Friendica specific Key-Value pair storage
*/
interface IManageKeyValuePairs extends \ArrayAccess
{
/**
* Get a particular value from the KeyValue Storage
*
* @param string $key The key to query
*
* @return mixed Stored value or null if it does not exist
*
* @throws KeyValueStoragePersistenceException In case the persistence layer throws errors
*
*/
public function get(string $key);
/**
* Sets a value for a given key
*
* Note: Please do not store booleans - convert to 0/1 integer values!
*
* @param string $key The configuration key to set
* @param mixed $value The value to store
*
* @throws KeyValueStoragePersistenceException In case the persistence layer throws errors
*/
public function set(string $key, $value): void;
/**
* Deletes the given key.
*
* @param string $key The configuration key to delete
*
* @throws KeyValueStoragePersistenceException In case the persistence layer throws errors
*
*/
public function delete(string $key): void;
}

View file

@ -0,0 +1,30 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\KeyValueStorage\Exceptions;
class KeyValueStoragePersistenceException extends \RuntimeException
{
public function __construct($message = "", \Throwable $previous = null)
{
parent::__construct($message, 500, $previous);
}
}

View file

@ -0,0 +1,48 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\KeyValueStorage\Type;
use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs;
/**
* An abstract helper class for Key-Value storage classes
*/
abstract class AbstractKeyValueStorage implements IManageKeyValuePairs
{
/** {@inheritDoc} */
public function get(string $key)
{
return $this->offsetGet($key);
}
/** {@inheritDoc} */
public function set(string $key, $value): void
{
$this->offsetSet($key, $value);
}
/** {@inheritDoc} */
public function delete(string $key): void
{
$this->offsetUnset($key);
}
}

View file

@ -0,0 +1,117 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Core\KeyValueStorage\Type;
use Friendica\Core\Config\Util\ValueConversion;
use Friendica\Core\KeyValueStorage\Exceptions\KeyValueStoragePersistenceException;
use Friendica\Database\Database;
/**
* A Key-Value storage provider with DB as persistence layer
*/
class DBKeyValueStorage extends AbstractKeyValueStorage
{
const DB_KEY_VALUE_TABLE = 'key-value';
/** @var Database */
protected $database;
public function __construct(Database $database)
{
$this->database = $database;
}
/** {@inheritDoc} */
public function offsetExists($offset): bool
{
try {
return $this->database->exists(self::DB_KEY_VALUE_TABLE, ['k' => $offset]);
} catch (\Exception $exception) {
throw new KeyValueStoragePersistenceException(sprintf('Cannot check storage with key %s', $offset), $exception);
}
}
/** {@inheritDoc} */
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
try {
$result = $this->database->selectFirst(self::DB_KEY_VALUE_TABLE, ['v'], ['k' => $offset]);
if ($this->database->isResult($result)) {
$value = ValueConversion::toConfigValue($result['v']);
// just return it in case it is set
if (isset($value)) {
return $value;
}
}
} catch (\Exception $exception) {
throw new KeyValueStoragePersistenceException(sprintf('Cannot get value for key %s', $offset), $exception);
}
return null;
}
/** {@inheritDoc} */
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
try {
// We store our setting values in a string variable.
// So we have to do the conversion here so that the compare below works.
// The exception are array values.
$compare_value = (!is_array($value) ? (string)$value : $value);
$stored_value = $this->get($offset);
if (isset($stored_value) && ($stored_value === $compare_value)) {
return;
}
$dbValue = ValueConversion::toDbValue($value);
$return = $this->database->update(self::DB_KEY_VALUE_TABLE, [
'v' => $dbValue,
'updated_at' => time()
], ['k' => $offset], true);
if (!$return) {
throw new \Exception(sprintf('database update failed: %s', $this->database->errorMessage()));
}
} catch (\Exception $exception) {
throw new KeyValueStoragePersistenceException(sprintf('Cannot set value for %s for key %s', $value, $offset), $exception);
}
}
/** {@inheritDoc} */
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
try {
if (!$this->database->delete(self::DB_KEY_VALUE_TABLE, ['k' => $offset])) {
throw new \Exception(sprintf('database deletion failed: %s', $this->database->errorMessage()));
}
} catch (\Exception $exception) {
throw new KeyValueStoragePersistenceException(sprintf('Cannot delete value with key %s', $offset), $exception);
}
}
}

View file

@ -76,7 +76,7 @@ class Update
}
// The postupdate has to completed version 1288 for the new post views to take over
$postupdate = DI::config()->get('system', 'post_update_version', self::NEW_TABLE_STRUCTURE_VERSION);
$postupdate = DI::keyValue()->get('post_update_version') ?? self::NEW_TABLE_STRUCTURE_VERSION;
if ($postupdate < self::NEW_TABLE_STRUCTURE_VERSION) {
$error = DI::l10n()->t('Updates from postupdate version %s are not supported. Please update at least to version 2021.01 and wait until the postupdate finished version 1383.', $postupdate);
if (DI::mode()->getExecutor() == Mode::INDEX) {

View file

@ -89,9 +89,9 @@ class Worker
self::$process = $process;
// Kill stale processes every 5 minutes
$last_cleanup = DI::config()->get('system', 'worker_last_cleaned', 0);
$last_cleanup = DI::keyValue()->get('worker_last_cleaned') ?? 0;
if (time() > ($last_cleanup + 300)) {
DI::config()->set('system', 'worker_last_cleaned', time());
DI::keyValue()->set( 'worker_last_cleaned', time());
Worker\Cron::killStaleWorkers();
}
@ -388,7 +388,7 @@ class Worker
$stamp = (float)microtime(true);
$condition = ["`id` = ? AND `next_try` < ?", $queue['id'], DateTimeFormat::utcNow()];
if (DBA::update('workerqueue', ['done' => true], $condition)) {
DI::config()->set('system', 'last_worker_execution', DateTimeFormat::utcNow());
DI::keyValue()->set('last_worker_execution', DateTimeFormat::utcNow());
}
self::$db_duration = (microtime(true) - $stamp);
self::$db_duration_write += (microtime(true) - $stamp);
@ -429,7 +429,7 @@ class Worker
$stamp = (float)microtime(true);
if (DBA::update('workerqueue', ['done' => true], ['id' => $queue['id']])) {
DI::config()->set('system', 'last_worker_execution', DateTimeFormat::utcNow());
DI::keyValue()->set('last_worker_execution', DateTimeFormat::utcNow());
}
self::$db_duration = (microtime(true) - $stamp);
self::$db_duration_write += (microtime(true) - $stamp);
@ -1422,7 +1422,7 @@ class Worker
$duration = max($start, $end) - min($start, $end);
// Quit when the last cron execution had been after the previous window
$last_cron = DI::config()->get('system', 'last_cron_daily');
$last_cron = DI::keyValue()->get('last_cron_daily');
if ($last_cron + $duration > time()) {
Logger::info('The Daily cron had been executed recently', ['last' => date(DateTimeFormat::MYSQL, $last_cron), 'start' => date('H:i:s', $start), 'end' => date('H:i:s', $end)]);
return false;

View file

@ -47,7 +47,7 @@ class Daemon
return true;
}
$daemon_mode = DI::config()->get('system', 'worker_daemon_mode', false, true);
$daemon_mode = DI::keyValue()->get('worker_daemon_mode') ?? false;
if ($daemon_mode) {
return $daemon_mode;
}
@ -93,11 +93,11 @@ class Daemon
}
// Check every minute if the daemon is running
if (DI::config()->get('system', 'last_daemon_check', 0) + 60 > time()) {
if ((DI::keyValue()->get('last_daemon_check') ?? 0) + 60 > time()) {
return;
}
DI::config()->set('system', 'last_daemon_check', time());
DI::keyValue()->set('last_daemon_check', time());
$pidfile = DI::config()->get('system', 'pidfile');
if (empty($pidfile)) {

View file

@ -181,6 +181,11 @@ abstract class DI
return self::$dice->create(Core\Config\Capability\IManageConfigValues::class);
}
public static function keyValue(): Core\KeyValueStorage\Capabilities\IManageKeyValuePairs
{
return self::$dice->create(Core\KeyValueStorage\Capabilities\IManageKeyValuePairs::class);
}
/**
* @return Core\PConfig\Capability\IManagePersonalConfigValues
*/

View file

@ -53,7 +53,7 @@ class DBStructure
throw new \Asika\SimpleConsole\CommandArgsException('The version number must be numeric');
}
DI::config()->set('system', 'build', $version);
DI::keyValue()->set('build', $version);
echo DI::l10n()->t('The database version had been set to %s.', $version);
}
@ -65,7 +65,7 @@ class DBStructure
*/
public static function dropTables(bool $execute)
{
$postupdate = DI::config()->get('system', 'post_update_version', PostUpdate::VERSION);
$postupdate = DI::keyValue()->get('post_update_version') ?? PostUpdate::VERSION;
if ($postupdate < PostUpdate::VERSION) {
echo DI::l10n()->t('The post update is at version %d, it has to be at %d to safely drop the tables.', $postupdate, PostUpdate::VERSION);
return;

View file

@ -129,12 +129,12 @@ class PostUpdate
private static function update1297()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1297) {
if (DI::keyValue()->get('post_update_version') >= 1297) {
return true;
}
if (!DBStructure::existsTable('item-delivery-data')) {
DI::config()->set('system', 'post_update_version', 1297);
DI::keyValue()->set('post_update_version', 1297);
return true;
}
@ -154,7 +154,7 @@ class PostUpdate
Logger::info('Processed rows: ' . DBA::affectedRows());
DI::config()->set('system', 'post_update_version', 1297);
DI::keyValue()->set('post_update_version', 1297);
Logger::info('Done');
@ -169,7 +169,7 @@ class PostUpdate
private static function update1322()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1322) {
if (DI::keyValue()->get('post_update_version') >= 1322) {
return true;
}
@ -188,7 +188,7 @@ class PostUpdate
}
DBA::close($contact);
DI::config()->set('system', 'post_update_version', 1322);
DI::keyValue()->set('post_update_version', 1322);
Logger::info('Done');
@ -204,16 +204,16 @@ class PostUpdate
private static function update1329()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1329) {
if (DI::keyValue()->get('post_update_version') >= 1329) {
return true;
}
if (!DBStructure::existsTable('item')) {
DI::config()->set('system', 'post_update_version', 1329);
DI::keyValue()->set('post_update_version', 1329);
return true;
}
$id = DI::config()->get('system', 'post_update_version_1329_id', 0);
$id = DI::keyValue()->get('post_update_version_1329_id') ?? 0;
Logger::info('Start', ['item' => $id]);
@ -237,12 +237,12 @@ class PostUpdate
}
DBA::close($items);
DI::config()->set('system', 'post_update_version_1329_id', $id);
DI::keyValue()->set('post_update_version_1329_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set('system', 'post_update_version', 1329);
DI::keyValue()->set('post_update_version', 1329);
Logger::info('Done');
return true;
}
@ -259,16 +259,16 @@ class PostUpdate
private static function update1341()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1341) {
if (DI::keyValue()->get('post_update_version') >= 1341) {
return true;
}
if (!DBStructure::existsTable('item-content')) {
DI::config()->set('system', 'post_update_version', 1342);
DI::keyValue()->set('post_update_version', 1342);
return true;
}
$id = DI::config()->get('system', 'post_update_version_1341_id', 0);
$id = DI::keyValue()->get('post_update_version_1341_id') ?? 0;
Logger::info('Start', ['item' => $id]);
@ -288,19 +288,19 @@ class PostUpdate
$id = $item['uri-id'];
++$rows;
if ($rows % 1000 == 0) {
DI::config()->set('system', 'post_update_version_1341_id', $id);
DI::keyValue()->set('post_update_version_1341_id', $id);
}
}
DBA::close($items);
DI::config()->set('system', 'post_update_version_1341_id', $id);
DI::keyValue()->set('post_update_version_1341_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
// When there are less than 1,000 items processed this means that we reached the end
// The other entries will then be processed with the regular functionality
if ($rows < 1000) {
DI::config()->set('system', 'post_update_version', 1341);
DI::keyValue()->set('post_update_version', 1341);
Logger::info('Done');
return true;
}
@ -317,16 +317,16 @@ class PostUpdate
private static function update1342()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1342) {
if (DI::keyValue()->get('post_update_version') >= 1342) {
return true;
}
if (!DBStructure::existsTable('term') || !DBStructure::existsTable('item-content')) {
DI::config()->set('system', 'post_update_version', 1342);
DI::keyValue()->set('post_update_version', 1342);
return true;
}
$id = DI::config()->get('system', 'post_update_version_1342_id', 0);
$id = DI::keyValue()->get('post_update_version_1342_id') ?? 0;
Logger::info('Start', ['item' => $id]);
@ -364,19 +364,19 @@ class PostUpdate
$id = $term['tid'];
++$rows;
if ($rows % 1000 == 0) {
DI::config()->set('system', 'post_update_version_1342_id', $id);
DI::keyValue()->set('post_update_version_1342_id', $id);
}
}
DBA::close($terms);
DI::config()->set('system', 'post_update_version_1342_id', $id);
DI::keyValue()->set('post_update_version_1342_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
// When there are less than 1,000 items processed this means that we reached the end
// The other entries will then be processed with the regular functionality
if ($rows < 1000) {
DI::config()->set('system', 'post_update_version', 1342);
DI::keyValue()->set('post_update_version', 1342);
Logger::info('Done');
return true;
}
@ -393,16 +393,16 @@ class PostUpdate
private static function update1345()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1345) {
if (DI::keyValue()->get('post_update_version') >= 1345) {
return true;
}
if (!DBStructure::existsTable('item-delivery-data')) {
DI::config()->set('system', 'post_update_version', 1345);
DI::keyValue()->set('post_update_version', 1345);
return true;
}
$id = DI::config()->get('system', 'post_update_version_1345_id', 0);
$id = DI::keyValue()->get('post_update_version_1345_id') ?? 0;
Logger::info('Start', ['item' => $id]);
@ -427,14 +427,14 @@ class PostUpdate
}
DBA::close($deliveries);
DI::config()->set('system', 'post_update_version_1345_id', $id);
DI::keyValue()->set('post_update_version_1345_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
// When there are less than 100 items processed this means that we reached the end
// The other entries will then be processed with the regular functionality
if ($rows < 100) {
DI::config()->set('system', 'post_update_version', 1345);
DI::keyValue()->set('post_update_version', 1345);
Logger::info('Done');
return true;
}
@ -476,16 +476,16 @@ class PostUpdate
private static function update1346()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1346) {
if (DI::keyValue()->get('post_update_version') >= 1346) {
return true;
}
if (!DBStructure::existsTable('term')) {
DI::config()->set('system', 'post_update_version', 1346);
DI::keyValue()->set('post_update_version', 1346);
return true;
}
$id = DI::config()->get('system', 'post_update_version_1346_id', 0);
$id = DI::keyValue()->get('post_update_version_1346_id') ?? 0;
Logger::info('Start', ['item' => $id]);
@ -514,19 +514,19 @@ class PostUpdate
$id = $term['oid'];
++$rows;
if ($rows % 100 == 0) {
DI::config()->set('system', 'post_update_version_1346_id', $id);
DI::keyValue()->set('post_update_version_1346_id', $id);
}
}
DBA::close($terms);
DI::config()->set('system', 'post_update_version_1346_id', $id);
DI::keyValue()->set('post_update_version_1346_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
// When there are less than 10 items processed this means that we reached the end
// The other entries will then be processed with the regular functionality
if ($rows < 10) {
DI::config()->set('system', 'post_update_version', 1346);
DI::keyValue()->set('post_update_version', 1346);
Logger::info('Done');
return true;
}
@ -544,16 +544,16 @@ class PostUpdate
private static function update1347()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1347) {
if (DI::keyValue()->get('post_update_version') >= 1347) {
return true;
}
if (!DBStructure::existsTable('item-activity') || !DBStructure::existsTable('item')) {
DI::config()->set('system', 'post_update_version', 1347);
DI::keyValue()->set('post_update_version', 1347);
return true;
}
$id = DI::config()->get('system', 'post_update_version_1347_id', 0);
$id = DI::keyValue()->get('post_update_version_1347_id') ?? 0;
Logger::info('Start', ['item' => $id]);
@ -588,12 +588,12 @@ class PostUpdate
}
DBA::close($items);
DI::config()->set('system', 'post_update_version_1347_id', $id);
DI::keyValue()->set('post_update_version_1347_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set('system', 'post_update_version', 1347);
DI::keyValue()->set('post_update_version', 1347);
Logger::info('Done');
return true;
}
@ -611,11 +611,11 @@ class PostUpdate
private static function update1348()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1348) {
if (DI::keyValue()->get('post_update_version') >= 1348) {
return true;
}
$id = DI::config()->get('system', 'post_update_version_1348_id', 0);
$id = DI::keyValue()->get('post_update_version_1348_id') ?? 0;
Logger::info('Start', ['contact' => $id]);
@ -641,12 +641,12 @@ class PostUpdate
}
DBA::close($contacts);
DI::config()->set('system', 'post_update_version_1348_id', $id);
DI::keyValue()->set('post_update_version_1348_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set('system', 'post_update_version', 1348);
DI::keyValue()->set('post_update_version', 1348);
Logger::info('Done');
return true;
}
@ -664,11 +664,11 @@ class PostUpdate
private static function update1349()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1349) {
if (DI::keyValue()->get('post_update_version') >= 1349) {
return true;
}
$id = DI::config()->get('system', 'post_update_version_1349_id', '');
$id = DI::keyValue()->get('post_update_version_1349_id') ?? '';
Logger::info('Start', ['apcontact' => $id]);
@ -694,12 +694,12 @@ class PostUpdate
}
DBA::close($apcontacts);
DI::config()->set('system', 'post_update_version_1349_id', $id);
DI::keyValue()->set('post_update_version_1349_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set('system', 'post_update_version', 1349);
DI::keyValue()->set('post_update_version', 1349);
Logger::info('Done');
return true;
}
@ -717,7 +717,7 @@ class PostUpdate
private static function update1383()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1383) {
if (DI::keyValue()->get('post_update_version') >= 1383) {
return true;
}
@ -743,7 +743,7 @@ class PostUpdate
}
DBA::close($photos);
DI::config()->set('system', 'post_update_version', 1383);
DI::keyValue()->set('post_update_version', 1383);
Logger::info('Done', ['deleted' => $deleted]);
return true;
}
@ -758,7 +758,7 @@ class PostUpdate
private static function update1384()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1384) {
if (DI::keyValue()->get('post_update_version') >= 1384) {
return true;
}
@ -788,7 +788,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1384);
DI::keyValue()->set('post_update_version', 1384);
Logger::info('Done');
return true;
}
@ -806,12 +806,12 @@ class PostUpdate
private static function update1400()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1400) {
if (DI::keyValue()->get('post_update_version') >= 1400) {
return true;
}
if (!DBStructure::existsTable('item')) {
DI::config()->set('system', 'post_update_version', 1400);
DI::keyValue()->set('post_update_version', 1400);
return true;
}
@ -835,7 +835,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1400);
DI::keyValue()->set('post_update_version', 1400);
Logger::info('Done');
return true;
}
@ -853,7 +853,7 @@ class PostUpdate
private static function update1424()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1424) {
if (DI::keyValue()->get('post_update_version') >= 1424) {
return true;
}
@ -877,7 +877,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1424);
DI::keyValue()->set('post_update_version', 1424);
Logger::info('Done');
return true;
}
@ -895,12 +895,12 @@ class PostUpdate
private static function update1425()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1425) {
if (DI::keyValue()->get('post_update_version') >= 1425) {
return true;
}
if (!DBStructure::existsTable('fcontact')) {
DI::config()->set('system', 'post_update_version', 1425);
DI::keyValue()->set('post_update_version', 1425);
return true;
}
@ -929,7 +929,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1425);
DI::keyValue()->set('post_update_version', 1425);
Logger::info('Done');
return true;
}
@ -947,7 +947,7 @@ class PostUpdate
private static function update1426()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1426) {
if (DI::keyValue()->get('post_update_version') >= 1426) {
return true;
}
@ -976,7 +976,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1426);
DI::keyValue()->set('post_update_version', 1426);
Logger::info('Done');
return true;
}
@ -994,7 +994,7 @@ class PostUpdate
private static function update1427()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1427) {
if (DI::keyValue()->get('post_update_version') >= 1427) {
return true;
}
@ -1023,7 +1023,7 @@ class PostUpdate
Logger::info('Processed', ['rows' => $rows]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1427);
DI::keyValue()->set('post_update_version', 1427);
Logger::info('Done');
return true;
}
@ -1041,16 +1041,16 @@ class PostUpdate
private static function update1452()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1452) {
if (DI::keyValue()->get('post_update_version') >= 1452) {
return true;
}
if (!DBStructure::existsTable('conversation')) {
DI::config()->set('system', 'post_update_version', 1452);
DI::keyValue()->set('post_update_version', 1452);
return true;
}
$id = DI::config()->get('system', 'post_update_version_1452_id', 0);
$id = DI::keyValue()->get('post_update_version_1452_id') ?? 0;
Logger::info('Start', ['uri-id' => $id]);
@ -1089,12 +1089,12 @@ class PostUpdate
DBA::close($conversations);
DI::config()->set('system', 'post_update_version_1452_id', $id);
DI::keyValue()->set('post_update_version_1452_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id, 'last-received' => $received]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1452);
DI::keyValue()->set('post_update_version', 1452);
Logger::info('Done');
return true;
}
@ -1113,7 +1113,7 @@ class PostUpdate
private static function update1483()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1483) {
if (DI::keyValue()->get('post_update_version') >= 1483) {
return true;
}
@ -1129,7 +1129,7 @@ class PostUpdate
}
DBA::close($posts);
DI::config()->set('system', 'post_update_version', 1483);
DI::keyValue()->set('post_update_version', 1483);
Logger::info('Done');
return true;
}
@ -1144,11 +1144,11 @@ class PostUpdate
private static function update1484()
{
// Was the script completed?
if (DI::config()->get('system', 'post_update_version') >= 1484) {
if (DI::keyValue()->get('post_update_version') >= 1484) {
return true;
}
$id = DI::config()->get('system', 'post_update_version_1484_id', 0);
$id = DI::keyValue()->get('post_update_version_1484_id') ?? 0;
Logger::info('Start', ['id' => $id]);
@ -1172,12 +1172,12 @@ class PostUpdate
}
DBA::close($contacts);
DI::config()->set('system', 'post_update_version_1484_id', $id);
DI::keyValue()->set('post_update_version_1484_id', $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($rows <= 100) {
DI::config()->set('system', 'post_update_version', 1484);
DI::keyValue()->set('post_update_version', 1484);
Logger::info('Done');
return true;
}

View file

@ -624,7 +624,7 @@ class Contact
public static function getPublicAndUserContactID(int $cid, int $uid): array
{
// We have to use the legacy function as long as the post update hasn't finished
if (DI::config()->get('system', 'post_update_version') < 1427) {
if (DI::keyValue()->get('post_update_version') < 1427) {
return self::legacyGetPublicAndUserContactID($cid, $uid);
}

View file

@ -2145,7 +2145,7 @@ class GServer
*/
private static function discoverFederation()
{
$last = DI::config()->get('poco', 'last_federation_discovery');
$last = DI::keyValue()->get('poco_last_federation_discovery');
if ($last) {
$next = $last + (24 * 60 * 60);
@ -2189,7 +2189,7 @@ class GServer
}
}
DI::config()->set('poco', 'last_federation_discovery', time());
DI::keyValue()->set('poco_last_federation_discovery', time());
}
/**

View file

@ -42,7 +42,7 @@ class DBSync extends BaseAdmin
switch ($action) {
case 'mark':
if ($update) {
DI::config()->set('database', 'update_' . $update, 'success');
DI::keyValue()->set('database_update_' . $update, 'success');
$curr = DI::config()->get('system', 'build');
if (intval($curr) == $update) {
DI::config()->set('system', 'build', intval($curr) + 1);
@ -76,13 +76,13 @@ class DBSync extends BaseAdmin
$o = DI::l10n()->t("Executing %s failed with error: %s", $func, $retval);
} elseif ($retval === Update::SUCCESS) {
$o = DI::l10n()->t('Update %s was successfully applied.', $func);
DI::config()->set('database', $func, 'success');
DI::keyValue()->set(sprintf('database_%s', $func), 'success');
} else {
$o = DI::l10n()->t('Update %s did not return a status. Unknown if it succeeded.', $func);
}
} else {
$o = DI::l10n()->t('There was no additional update function %s that needed to be called.', $func) . "<br />";
DI::config()->set('database', $func, 'success');
DI::keyValue()->set(sprintf('database_%s', $func), 'success');
}
return $o;

View file

@ -98,7 +98,7 @@ class Summary extends BaseAdmin
$warningtext[] = DI::l10n()->t('The last update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear. (Some of the errors are possibly inside the logfile.)');
}
$last_worker_call = DI::config()->get('system', 'last_worker_execution', false);
$last_worker_call = DI::keyValue()->get('last_worker_execution');
if (!$last_worker_call) {
$warningtext[] = DI::l10n()->t('The worker was never executed. Please check your database structure!');
} elseif ((strtotime(DateTimeFormat::utcNow()) - strtotime($last_worker_call)) > 60 * 60) {

View file

@ -42,6 +42,7 @@ class Friendica extends BaseModule
protected function content(array $request = []): string
{
$config = DI::config();
$keyValue = DI::keyValue();
$visibleAddonList = Addon::getVisibleList();
if (!empty($visibleAddonList)) {
@ -100,7 +101,7 @@ class Friendica extends BaseModule
'<strong>' . App::VERSION . '</strong>',
DI::baseUrl()->get(),
'<strong>' . $config->get('system', 'build') . '/' . DB_UPDATE_VERSION . '</strong>',
'<strong>' . $config->get('system', 'post_update_version') . '/' . PostUpdate::VERSION . '</strong>'),
'<strong>' . $keyValue->get('post_update_version') . '/' . PostUpdate::VERSION . '</strong>'),
'friendica' => DI::l10n()->t('Please visit <a href="https://friendi.ca">Friendi.ca</a> to learn more about the Friendica project.'),
'bugs' => DI::l10n()->t('Bug reports and issues: please visit') . ' ' . '<a href="https://github.com/friendica/friendica/issues?state=open">' . DI::l10n()->t('the bugtracker at github') . '</a>',
'info' => DI::l10n()->t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'),

View file

@ -37,7 +37,7 @@ class Cron
{
$a = DI::app();
$last = DI::config()->get('system', 'last_cron');
$last = DI::keyValue()->get('last_cron');
$poll_interval = intval(DI::config()->get('system', 'cron_interval'));
@ -84,7 +84,7 @@ class Cron
Worker::add(Worker::PRIORITY_LOW, 'PostUpdate');
// Hourly cron calls
if (DI::config()->get('system', 'last_cron_hourly', 0) + 3600 < time()) {
if ((DI::keyValue()->get('last_cron_hourly') ?? 0) + 3600 < time()) {
// Update trending tags cache for the community page
@ -105,7 +105,7 @@ class Cron
// Clear cache entries
Worker::add(Worker::PRIORITY_LOW, 'ClearCache');
DI::config()->set('system', 'last_cron_hourly', time());
DI::keyValue()->set('last_cron_hourly', time());
}
// Daily maintenance cron calls
@ -145,12 +145,12 @@ class Cron
// Resubscribe to relay servers
Relay::reSubscribe();
DI::config()->set('system', 'last_cron_daily', time());
DI::keyValue()->set('last_cron_daily', time());
}
Logger::notice('end');
DI::config()->set('system', 'last_cron', time());
DI::keyValue()->set('last_cron', time());
}
/**

View file

@ -45,7 +45,7 @@ class PullDirectory
return;
}
$now = (int)DI::config()->get('system', 'last-directory-sync', 0);
$now = (int)(DI::keyValue()->get('last-directory-sync') ?? 0);
Logger::info('Synchronization started.', ['now' => $now, 'directory' => $directory]);
@ -64,7 +64,7 @@ class PullDirectory
$result = Contact::addByUrls($contacts['results']);
$now = $contacts['now'] ?? 0;
DI::config()->set('system', 'last-directory-sync', $now);
DI::keyValue()->set('last-directory-sync', $now);
Logger::info('Synchronization ended', ['now' => $now, 'count' => $result['count'], 'added' => $result['added'], 'updated' => $result['updated'], 'unchanged' => $result['unchanged'], 'directory' => $directory]);
}

View file

@ -55,7 +55,7 @@
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1504);
define('DB_UPDATE_VERSION', 1505);
}
return [
@ -889,6 +889,17 @@ return [
"uid" => ["uid"],
]
],
"key-value" => [
"comment" => "A key value storage",
"fields" => [
"k" => ["type" => "varbinary(50)", "not null" => "1", "primary" => "1", "comment" => ""],
"v" => ["type" => "mediumtext", "comment" => ""],
"updated_at" => ["type" => "int unsigned", "not null" => "1", "comment" => "timestamp of the last update"],
],
"indexes" => [
"PRIMARY" => ["k"],
],
],
"locks" => [
"comment" => "",
"fields" => [

View file

@ -245,6 +245,9 @@ return [
['getBackend', [], Dice::CHAIN_CALL],
],
],
\Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs::class => [
'instanceOf' => \Friendica\Core\KeyValueStorage\Type\DBKeyValueStorage::class,
],
Network\HTTPClient\Capability\ICanSendHttpRequests::class => [
'instanceOf' => Network\HTTPClient\Factory\HttpClient::class,
'call' => [

View file

@ -0,0 +1,96 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Test\src\Core\KeyValueStorage;
use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs;
use Friendica\Core\KeyValueStorage\Type\DBKeyValueStorage;
use Friendica\Database\Database;
use Friendica\Database\Definition\DbaDefinition;
use Friendica\Database\Definition\ViewDefinition;
use Friendica\Test\DatabaseTestTrait;
use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Util\BasePath;
use Friendica\Util\Profiler;
class DBKeyValueStorageTest extends KeyValueStorageTest
{
use DatabaseTestTrait;
/** @var Database */
protected $database;
protected function setUp(): void
{
parent::setUp();
$this->setUpDb();
}
protected function tearDown(): void
{
parent::tearDown();
$this->tearDownDb();
}
public function getInstance(): IManageKeyValuePairs
{
$cache = new Cache();
$cache->set('database', 'disable_pdo', true);
$basePath = new BasePath(dirname(__FILE__, 5), $_SERVER);
$this->database = new StaticDatabase($cache, new Profiler($cache), (new DbaDefinition($basePath->getPath()))->load(), (new ViewDefinition($basePath->getPath()))->load());
$this->database->setTestmode(true);
return new DBKeyValueStorage($this->database);
}
/** @dataProvider dataTests */
public function testUpdatedAt($k, $v)
{
$instance = $this->getInstance();
$instance->set($k, $v);
self::assertEquals($v, $instance->get($k));
self::assertEquals($v, $instance[$k]);
$entry = $this->database->selectFirst(DBKeyValueStorage::DB_KEY_VALUE_TABLE, ['updated_at'], ['k' => $k]);
self::assertNotEmpty($entry);
$updateAt = $entry['updated_at'];
$instance->set($k, 'another_value');
self::assertEquals('another_value', $instance->get($k));
self::assertEquals('another_value', $instance[$k]);
$entry = $this->database->selectFirst(DBKeyValueStorage::DB_KEY_VALUE_TABLE, ['updated_at'], ['k' => $k]);
self::assertNotEmpty($entry);
$updateAtAfter = $entry['updated_at'];
self::assertLessThanOrEqual($updateAt, $updateAtAfter);
}
}

View file

@ -0,0 +1,105 @@
<?php
/**
* @copyright Copyright (C) 2010-2022, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Friendica\Test\src\Core\KeyValueStorage;
use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs;
use Friendica\Test\MockedTest;
abstract class KeyValueStorageTest extends MockedTest
{
abstract public function getInstance(): IManageKeyValuePairs;
public function testInstance()
{
$instance = $this->getInstance();
self::assertInstanceOf(IManageKeyValuePairs::class, $instance);
}
public function dataTests(): array
{
return [
'string' => ['k' => 'data', 'v' => 'it'],
'boolTrue' => ['k' => 'data', 'v' => true],
'boolFalse' => ['k' => 'data', 'v' => false],
'integer' => ['k' => 'data', 'v' => 235],
'decimal' => ['k' => 'data', 'v' => 2.456],
'array' => ['k' => 'data', 'v' => ['1', 2, '3', true, false]],
'boolIntTrue' => ['k' => 'data', 'v' => 1],
'boolIntFalse' => ['k' => 'data', 'v' => 0],
];
}
/**
* @dataProvider dataTests
*/
public function testGetSetDelete($k, $v)
{
$instance = $this->getInstance();
$instance->set($k, $v);
self::assertEquals($v, $instance->get($k));
self::assertEquals($v, $instance[$k]);
$instance->delete($k);
self::assertNull($instance->get($k));
self::assertNull($instance[$k]);
}
/**
* @dataProvider dataTests
*/
public function testSetOverride($k, $v)
{
$instance = $this->getInstance();
$instance->set($k, $v);
self::assertEquals($v, $instance->get($k));
self::assertEquals($v, $instance[$k]);
$instance->set($k, 'another_value');
self::assertEquals('another_value', $instance->get($k));
self::assertEquals('another_value', $instance[$k]);
}
/**
* @dataProvider dataTests
*/
public function testOffsetSetDelete($k, $v)
{
$instance = $this->getInstance();
$instance[$k] = $v;
self::assertEquals($v, $instance->get($k));
self::assertEquals($v, $instance[$k]);
unset($instance[$k]);
self::assertNull($instance->get($k));
self::assertNull($instance[$k]);
}
}

View file

@ -21,15 +21,16 @@
namespace Friendica\Test\src\Core\Lock;
use Friendica\Core\Config\ValueObject\Cache;
use Friendica\Core\Lock\Type\DatabaseLock;
use Friendica\Core\Config\Factory\Config;
use Friendica\DI;
use Friendica\Database\Database;
use Friendica\Database\Definition\DbaDefinition;
use Friendica\Database\Definition\ViewDefinition;
use Friendica\Test\DatabaseTestTrait;
use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Test\Util\VFSTrait;
use Friendica\Util\BasePath;
use Friendica\Util\Profiler;
use Mockery;
use Psr\Log\NullLogger;
class DatabaseLockDriverTest extends LockTest
{
@ -38,6 +39,9 @@ class DatabaseLockDriverTest extends LockTest
protected $pid = 123;
/** @var Database */
protected $database;
protected function setUp(): void
{
$this->setUpVfsDir();
@ -49,7 +53,15 @@ class DatabaseLockDriverTest extends LockTest
protected function getInstance()
{
return new DatabaseLock(DI::dba(), $this->pid);
$cache = new Cache();
$cache->set('database', 'disable_pdo', true);
$basePath = new BasePath(dirname(__FILE__, 5), $_SERVER);
$this->database = new StaticDatabase($cache, new Profiler($cache), (new DbaDefinition($basePath->getPath()))->load(), (new ViewDefinition($basePath->getPath()))->load());
$this->database->setTestmode(true);
return new DatabaseLock($this->database, $this->pid);
}
protected function tearDown(): void

View file

@ -982,7 +982,7 @@ function update_1429()
return Update::FAILED;
}
DI::config()->set('system', 'post_update_version', 1423);
DI::keyValue()->set('post_update_version', 1423);
return Update::SUCCESS;
}
@ -1145,3 +1145,33 @@ function update_1502()
DBA::e("UPDATE `pconfig` SET `cat` = 'calendar' WHERE `k` = 'first_day_of_week'");
return Update::SUCCESS;
}
function update_1505()
{
$conditions = [
"((`cat` = ?) AND ((`k` LIKE ?) OR (`k` = ?) OR (`k` LIKE ?) OR (`k` = ?))) OR " .
"((`cat` != ?) AND (`k` LIKE ?)) OR " .
"((`cat` = ?) AND (`k` LIKE ?))",
"system",
"post_update_%",
"worker_last_cleaned",
"last%",
"worker_daemon_mode",
"system",
"last_%",
"database",
"update_%",
];
$postUpdateEntries = DBA::selectToArray('config', ['cat', 'k', 'v'], $conditions);
foreach ($postUpdateEntries as $postUpdateEntry) {
if ($postUpdateEntry['cat'] === 'system') {
DI::keyValue()->set($postUpdateEntry['k'], $postUpdateEntry['v']);
} else {
DI::keyValue()->set(sprintf('%s_%s', $postUpdateEntry['cat'], $postUpdateEntry['k']), $postUpdateEntry['v']);
}
}
return DBA::delete('config', $conditions) ? Update::SUCCESS : Update::FAILED;
}