/** * 初始化执行 * * @param bool $isRegisterServer */ public static function init($isRegisterServer = false) { if (self::$table) { return; } self::$isRegisterServer = $isRegisterServer ? true : false; if (isset(Server::$config['clusters']['count']) && ($size = Server::$config['clusters']['count'])) { # 必须是2的指数, 如1024,8192,65536等 $size = bindec(str_pad(1, strlen(decbin((int) $size - 1)), 0)) * 2; } else { $size = 1024; } $table = new Table($size * 2); $table->column('id', Table::TYPE_INT, 5); // 所在组ID $table->column('group', Table::TYPE_STRING, 64); // 分组 $table->column('ip', Table::TYPE_STRING, 64); // IP $table->column('port', Table::TYPE_INT, 5); // 端口 $table->column('worker_num', Table::TYPE_INT, 5); // 进程数 $table->column('encrypt', Table::TYPE_INT, 1); // 通讯数据是否加密 $table->column('key', Table::TYPE_STRING, 32); // 数据加密密钥 if (self::$isRegisterServer) { # 注册服务器需要多几个字段 $table->column('fd', Table::TYPE_INT, 10); // 所在 fd $table->column('from_id', Table::TYPE_INT, 10); // 所在 from_id $table->column('removed', Table::TYPE_INT, 10); // 移除时间 # 记录自动分配ID $groupIdTable = new Table(1024); $groupIdTable->column('id', Table::TYPE_INT, 5); $groupIdTable->create(); # fd 所对应的序号 $fdTable = new Table($size * 2); $fdTable->column('group', Table::TYPE_STRING, 64); $fdTable->column('id', Table::TYPE_INT, 5); $fdTable->create(); self::$fdToIdTable = $fdTable; self::$groupIdTable = $groupIdTable; } $table->create(); self::$table = $table; self::$lastChangeTime = new \Swoole\Atomic(time()); self::$taskIdAtomic = new \Swoole\Atomic(); }
/** * 创建MySQL类型的数据 * * @return bool */ protected function _createByMySQL() { # 先检查表是否存在 $table = $this->_link['table']; $sql = "SHOW TABLES LIKE `{$table}`"; $rs = $this->_driver()->query($sql); $has = $rs->num_rows ? true : false; $rs->free(); if ($has) { # 已经存在, 检查表结构 # 读取所有数据 $rs = $this->_driver()->query("select * from `{$table}`"); while ($row = $rs->fetch_assoc()) { $key = $row['_key']; unset($row['_key']); try { # 设置数据 parent::set($key, $row); } catch (\Exception $e) { Server::$instance->warn($e->getMessage()); } } unset($row); $rs->free(); # 检查表结构是否变化过 $sql = "SHOW COLUMNS FROM `{$table}`"; $rs = $this->_driver()->query($sql); $col = $this->_column; $removedFields = []; $changedFields = []; while ($row = $rs->fetch_assoc()) { $field = $row['Field']; $oldType = $row['Type']; if ($field === '_key') { continue; } if (isset($col[$field])) { # 此字段在字段设置里存在 list($newType, $newSize) = $col[$field]; $fieldChanged = false; if ($oldType === 'text') { # 超过 2000 则为 text 类型 if ($newType === \Swoole\Table::TYPE_STRING && $newSize > 2000) { # 相同 } else { $fieldChanged = true; } } elseif (preg_match('#(varchar|bigint|int)\\((\\d+)\\)#', $oldType, $m)) { # int(10), varchar(255) if ($newType === \Swoole\Table::TYPE_INT) { if ($newSize > 10) { if ($m[1] !== 'bigint') { $fieldChanged = true; } } else { if ($m[1] !== 'int') { $fieldChanged = true; } } } elseif ($newType === \Swoole\Table::TYPE_FLOAT) { $fieldChanged = true; } else { # \Swoole\Table::TYPE_STRING if ($m[1] !== 'varchar' || $newSize > 2000) { $fieldChanged = true; } } } elseif (preg_match('#decimal\\((\\d+),(\\d+)\\)#', $oldType, $m)) { if ($newType !== \Swoole\Table::TYPE_FLOAT) { $fieldChanged = true; } } else { $fieldChanged = true; } if ($fieldChanged) { $changedFields[$field] = $col[$field]; } unset($col[$field]); } else { # 没有对应的字段, 则说明已经被删除 $removedFields[] = $field; } } if ($col || $removedFields || $changedFields) { # 有新增字段或移除的字段或修改的字段 $tmp = []; if ($removedFields) { # ALTER TABLE `adv` DROP `t`; foreach ($removedFields as $field) { $tmp[] = "DROP `{$col}`"; } } if ($changedFields) { static::_mysqlBuilderFieldSQL($tmp, $changedFields, 1); } if ($col) { static::_mysqlBuilderFieldSQL($tmp, $changedFields, 0); } if ($tmp) { $sql = "ALTER TABLE `{$table}` " . implode(', ', $tmp); Server::$instance->debug("change mysql table: {$sql}"); # 执行结构变更 $this->_driver()->query($sql); } } } else { # 不存在对应的表, 创建表格 $tmp = []; static::_mysqlBuilderFieldSQL($tmp, $this->_column, 2); # 构造SQL $sql = "CREATE TABLE `{$table}` (`_key` VARCHAR(255) NOT NULL, " . implode(', ', $tmp) . ", PRIMARY KEY (`_key`)) ENGINE = InnoDB"; Server::$instance->debug("change mysql table: {$sql}"); $this->_driver()->query($sql); } return true; }