diff --git a/database.sql b/database.sql index fcbcbb394..9b19517bb 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2021.12-dev (Siberian Iris) --- DB_UPDATE_VERSION 1442 +-- DB_UPDATE_VERSION 1443 -- ------------------------------------------ @@ -681,16 +681,6 @@ CREATE TABLE IF NOT EXISTS `hook` ( UNIQUE INDEX `hook_file_function` (`hook`,`file`,`function`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='addon hook registry'; --- --- TABLE host --- -CREATE TABLE IF NOT EXISTS `host` ( - `id` tinyint unsigned NOT NULL auto_increment COMMENT 'sequential ID', - `name` varchar(128) NOT NULL DEFAULT '' COMMENT 'The hostname', - PRIMARY KEY(`id`), - UNIQUE INDEX `name` (`name`) -) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Hostname'; - -- -- TABLE inbox-status -- @@ -1325,10 +1315,11 @@ CREATE TABLE IF NOT EXISTS `post-user-notification` ( -- TABLE process -- CREATE TABLE IF NOT EXISTS `process` ( - `pid` int unsigned NOT NULL COMMENT '', + `pid` int unsigned NOT NULL COMMENT 'The process ID of the current node', + `hostname` varchar(32) NOT NULL COMMENT 'The hostname of the node', `command` varbinary(32) NOT NULL DEFAULT '' COMMENT '', `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - PRIMARY KEY(`pid`), + PRIMARY KEY(`pid`, `hostname`), INDEX `command` (`command`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Currently running system processes'; diff --git a/src/Core/Worker/Entity/Process.php b/src/Core/Worker/Entity/Process.php index 7161f9ca4..1353e2635 100644 --- a/src/Core/Worker/Entity/Process.php +++ b/src/Core/Worker/Entity/Process.php @@ -1,4 +1,23 @@ . + * + */ namespace Friendica\Core\Worker\Entity; @@ -8,6 +27,7 @@ use Friendica\BaseEntity; /** * @property-read int $pid * @property-read string $command + * @property-read string $hostname * @property-read DateTime $created */ class Process extends BaseEntity @@ -16,18 +36,22 @@ class Process extends BaseEntity protected $pid; /** @var string */ protected $command; + /** @var string */ + protected $hostname; /** @var DateTime */ protected $created; /** - * @param int $pid - * @param string $command + * @param int $pid + * @param string $command + * @param string $hostname * @param DateTime $created */ - public function __construct(int $pid, string $command, DateTime $created) + public function __construct(int $pid, string $command, string $hostname, DateTime $created) { - $this->pid = $pid; - $this->command = $command; - $this->created = $created; + $this->pid = $pid; + $this->command = $command; + $this->hostname = $hostname; + $this->created = $created; } } diff --git a/src/Core/Worker/Exception/ProcessPersistenceException.php b/src/Core/Worker/Exception/ProcessPersistenceException.php index c1c34453a..034a21cb5 100644 --- a/src/Core/Worker/Exception/ProcessPersistenceException.php +++ b/src/Core/Worker/Exception/ProcessPersistenceException.php @@ -1,4 +1,23 @@ . + * + */ namespace Friendica\Core\Worker\Exception; diff --git a/src/Core/Worker/Factory/Process.php b/src/Core/Worker/Factory/Process.php index 1b6690689..9a45eebc4 100644 --- a/src/Core/Worker/Factory/Process.php +++ b/src/Core/Worker/Factory/Process.php @@ -1,4 +1,23 @@ . + * + */ namespace Friendica\Core\Worker\Factory; @@ -8,28 +27,18 @@ use Friendica\Core\Worker\Entity; class Process extends BaseFactory implements ICanCreateFromTableRow { + public function determineHost(?string $hostname = null): string + { + return strtolower($hostname ?? php_uname('n')); + } + public function createFromTableRow(array $row): Entity\Process { return new Entity\Process( $row['pid'], $row['command'], + $this->determineHost($row['hostname'] ?? null), new \DateTime($row['created'] ?? 'now', new \DateTimeZone('UTC')) ); } - - /** - * Creates a new process entry for a given PID - * - * @param int $pid - * @param string $command - * - * @return Entity\Process - */ - public function create(int $pid, string $command): Entity\Process - { - return $this->createFromTableRow([ - 'pid' => $pid, - 'command' => $command, - ]); - } } diff --git a/src/Core/Worker/Repository/Process.php b/src/Core/Worker/Repository/Process.php index 1e91d867f..1c53462be 100644 --- a/src/Core/Worker/Repository/Process.php +++ b/src/Core/Worker/Repository/Process.php @@ -34,18 +34,25 @@ use Psr\Log\LoggerInterface; */ class Process extends BaseRepository { + const NODE_ENV = 'NODE_ENV'; + protected static $table_name = 'process'; /** @var Factory\Process */ protected $factory; - public function __construct(Database $database, LoggerInterface $logger, Factory\Process $factory) + /** @var string */ + private $currentHost; + + public function __construct(Database $database, LoggerInterface $logger, Factory\Process $factory, array $server) { parent::__construct($database, $logger, $factory); + + $this->currentHost = $factory->determineHost($server[self::NODE_ENV] ?? null); } /** - * Starts and Returns the process for a given PID + * Starts and Returns the process for a given PID at the current host * * @param int $pid * @param string $command @@ -60,19 +67,18 @@ class Process extends BaseRepository try { $this->db->transaction(); - $newProcess = $this->factory->create($pid, $command); - - if (!$this->db->exists('process', ['pid' => $pid])) { + if (!$this->db->exists(static::$table_name, ['pid' => $pid, 'hostname' => $this->currentHost])) { if (!$this->db->insert(static::$table_name, [ - 'pid' => $newProcess->pid, - 'command' => $newProcess->command, - 'created' => $newProcess->created->format(DateTimeFormat::MYSQL) + 'pid' => $pid, + 'command' => $command, + 'hostname' => $this->currentHost, + 'created' => DateTimeFormat::utcNow() ])) { throw new ProcessPersistenceException(sprintf('The process with PID %s already exists.', $pid)); } } - $result = $this->_selectOne(['pid' => $pid]); + $result = $this->_selectOne(['pid' => $pid, 'hostname' => $this->currentHost]); $this->db->commit(); @@ -86,7 +92,8 @@ class Process extends BaseRepository { try { if (!$this->db->delete(static::$table_name, [ - 'pid' => $process->pid + 'pid' => $process->pid, + 'hostname' => $this->currentHost, ])) { throw new ProcessPersistenceException(sprintf('The process with PID %s doesn\'t exists.', $process->pi)); } @@ -103,10 +110,10 @@ class Process extends BaseRepository $this->db->transaction(); try { - $processes = $this->db->select('process', ['pid']); + $processes = $this->db->select(static::$table_name, ['pid'], ['hostname' => $this->currentHost]); while ($process = $this->db->fetch($processes)) { if (!posix_kill($process['pid'], 0)) { - $this->db->delete('process', ['pid' => $process['pid']]); + $this->db->delete(static::$table_name, ['pid' => $process['pid']]); } } $this->db->close($processes); diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 4a1588dd1..2b0e3d1e3 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -82,7 +82,7 @@ class DBStructure $old_tables = ['fserver', 'gcign', 'gcontact', 'gcontact-relation', 'gfollower' ,'glink', 'item-delivery-data', 'item-activity', 'item-content', 'item_id', 'participation', 'poll', 'poll_result', 'queue', 'retriever_rule', 'deliverq', 'dsprphotoq', 'ffinder', 'sign', 'spam', 'term', 'user-item', 'thread', 'item', 'challenge', - 'auth_codes', 'clients', 'tokens', 'profile_check']; + 'auth_codes', 'clients', 'tokens', 'profile_check', 'host']; $tables = DBA::selectToArray(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_NAME'], ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_TYPE' => 'BASE TABLE']); diff --git a/src/Model/Host.php b/src/Model/Host.php deleted file mode 100644 index 078c2f931..000000000 --- a/src/Model/Host.php +++ /dev/null @@ -1,79 +0,0 @@ -. - * - */ - -namespace Friendica\Model; - -use Friendica\Core\Logger; -use Friendica\Database\DBA; - -class Host -{ - /** - * Get the id for a given hostname - * When empty, the current hostname is used - * - * @param string $hostname - * - * @return integer host name id - * @throws \Exception - */ - public static function getId(string $hostname = '') - { - if (empty($hostname)) { - $hostname = php_uname('n'); - } - - $hostname = strtolower($hostname); - - $host = DBA::selectFirst('host', ['id'], ['name' => $hostname]); - if (!empty($host['id'])) { - return $host['id']; - } - - DBA::replace('host', ['name' => $hostname]); - - $host = DBA::selectFirst('host', ['id'], ['name' => $hostname]); - if (empty($host['id'])) { - Logger::warning('Host name could not be inserted', ['name' => $hostname]); - return 0; - } - - return $host['id']; - } - - /** - * Get the hostname for a given id - * - * @param int $id - * - * @return string host name - * @throws \Exception - */ - public static function getName(int $id) - { - $host = DBA::selectFirst('host', ['name'], ['id' => $id]); - if (!empty($host['name'])) { - return $host['name']; - } - - return ''; - } -} diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 0019fdf7b..409829acd 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1442); + define('DB_UPDATE_VERSION', 1443); } return [ @@ -743,17 +743,6 @@ return [ "hook_file_function" => ["UNIQUE", "hook", "file", "function"], ] ], - "host" => [ - "comment" => "Hostname", - "fields" => [ - "id" => ["type" => "tinyint unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], - "name" => ["type" => "varchar(128)", "not null" => "1", "default" => "", "comment" => "The hostname"], - ], - "indexes" => [ - "PRIMARY" => ["id"], - "name" => ["UNIQUE", "name"], - ] - ], "inbox-status" => [ "comment" => "Status of ActivityPub inboxes", "fields" => [ @@ -1343,12 +1332,13 @@ return [ "process" => [ "comment" => "Currently running system processes", "fields" => [ - "pid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "comment" => ""], + "pid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "comment" => "The process ID of the current node"], + "hostname" => ["type" => "varchar(32)", "not null" => "1", "primary" => "1", "comment" => "The hostname of the current node"], "command" => ["type" => "varbinary(32)", "not null" => "1", "default" => "", "comment" => ""], "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], ], "indexes" => [ - "PRIMARY" => ["pid"], + "PRIMARY" => ["pid", "hostname"], "command" => ["command"], ] ], diff --git a/static/dependencies.config.php b/static/dependencies.config.php index d3034a2ba..57ef629bb 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -238,4 +238,9 @@ return [ [Dice::INSTANCE => Util\ReversedFileReader::class], ] ], + \Friendica\Core\Worker\Repository\Process::class => [ + 'constructParams' => [ + $_SERVER + ], + ], ]; diff --git a/tests/src/Core/Worker/Repository/ProcessTest.php b/tests/src/Core/Worker/Repository/ProcessTest.php new file mode 100644 index 000000000..be7b87a69 --- /dev/null +++ b/tests/src/Core/Worker/Repository/ProcessTest.php @@ -0,0 +1,38 @@ +create(getmypid(), 'test'); + + self::assertEquals(getmypid(), $entityNew->pid); + self::assertEquals('test', $entityNew->command); + self::assertLessThanOrEqual(new \DateTime('now', new \DateTimeZone('UTC')), $entityNew->created); + self::assertEquals(php_uname('n'), $entityNew->hostname); + } + + public function testHostnameEnv() + { + $factory = new Factory\Process(new NullLogger()); + $repository = new Repository\Process(DI::dba(), new NullLogger(), $factory, [Repository\Process::NODE_ENV => 'test_node']); + + $entityNew = $repository->create(getmypid(), 'test'); + + self::assertEquals(getmypid(), $entityNew->pid); + self::assertEquals('test', $entityNew->command); + self::assertLessThanOrEqual(new \DateTime('now', new \DateTimeZone('UTC')), $entityNew->created); + self::assertEquals('test_node', $entityNew->hostname); + } +}