构建运行时缓存

@param string $runtimeFile 如果为空则默认为runtime.cache
@return void
9084
public static function buildRuntime($runtimeFile = null)
    {
        /**
         * 处理列类型和大小
         *
         * @param \Imi\Model\Annotation\Column $column
         * @return [$type, $size]
         */
        $parseColumnTypeAndSize = function($column) {
            $type = $column->type;
            switch($type)
            {
                case 'string':
                    $type = \Swoole\Table::TYPE_STRING;
                    $size = $column->length;
                    break;
                case 'int':
                    $type = \Swoole\Table::TYPE_INT;
                    $size = $column->length;
                    if(!in_array($size, [1, 2, 4, 8]))
                    {
                        $size = 4;
                    }
                    break;
                case 'float':
                    $type = \Swoole\Table::TYPE_FLOAT;
                    $size = 8;
                    break;
            }
            return [$type, $size];
        };
        
        /**
         * 获取内存表列
         *
         * @param array $columnAnnotationsSet
         * @return array
         */
        $getMemoryTableColumns = function($columnAnnotationsSet) use($parseColumnTypeAndSize) {
            $columns = [];

            foreach($columnAnnotationsSet as $propertyName => $annotations)
            {
                $columnAnnotation = $annotations[0];
                list($type, $size) = $parseColumnTypeAndSize($columnAnnotation);
                $columns[] = [
                    'name' => $columnAnnotation->name,
                    'type' => $type,
                    'size' => $size,
                ];
            }
            
            return $columns;
        };

        $runtimeInfo = App::getRuntimeInfo();
        $annotationsSet = AnnotationManager::getAnnotationPoints(MemoryTable::class, 'Class');
        foreach($annotationsSet as &$item)
        {
            $item['columns'] = $getMemoryTableColumns(AnnotationManager::getPropertiesAnnotations($item['class'], Column::class)) ?? [];
        }
        $runtimeInfo->memoryTable = $annotationsSet;
        $runtimeInfo->annotationParserData = [Annotation::getInstance()->getParser()->getData(), Annotation::getInstance()->getParser()->getFileMap()];
        $runtimeInfo->annotationParserParsers = Annotation::getInstance()->getParser()->getParsers();
        $runtimeInfo->annotationManagerAnnotations = AnnotationManager::getAnnotations();
        $runtimeInfo->annotationManagerAnnotationRelation = AnnotationManager::getAnnotationRelation();
        $runtimeInfo->parsersData = [];
        foreach(array_unique($runtimeInfo->annotationParserParsers) as $parserClass)
        {
            $parser = $parserClass::getInstance();
            $runtimeInfo->parsersData[$parserClass] = $parser->getData();
        }
        if(null === $runtimeFile)
        {
            $runtimeFile = \Imi\Util\Imi::getRuntimePath('runtime.cache');
        }
        file_put_contents($runtimeFile, serialize($runtimeInfo));
    }
464193
public function attach($file = __FILE__)
    {
        if (!file_exists($file)) {
            $touch = touch($file);
            if (!$touch) {
                throw new \RuntimeException("file is not exists and it can not be created. file: {$file}");
            }
        }
        $key = ftok($file, 'a');
        $this->shm = shm_attach($key, $this->size); //allocate shared memory
    }
695144
public function clearImiRuntime()
    {
        $file = \Imi\Util\Imi::getRuntimePath('imi-runtime.cache');
        if(is_file($file))
        {
            unlink($file);
            echo 'Clear imi runtime complete', PHP_EOL;
        }
        else
        {
            echo 'Imi runtime does not exists', PHP_EOL;
        }
    }
447688
protected function _load($url)
    {
        $file = $this->_locate($url);
        $type = pathinfo($file, PATHINFO_EXTENSION);

        if(in_array($type, $this->getFileTypes()))
        {
            if(!$this->_source = file_get_contents($file)) {
                throw new RuntimeException(sprintf('The template "%s" cannot be loaded.', $file));
            }
        }
        else $this->_source = $this->getTemplate()->loadFile($file)->render($this->getData());

        return $this->_source;
    }
302664
public function filePut($file, $data)
    {
        $file = $this->alias->resolve($file);

        $this->_dirCreate(dirname($file));
        if (file_put_contents($file, $data, LOCK_EX) === false) {
            throw new RuntimeException(['write `:file` file failed: :last_error_message', 'file' => $file]);
        }
    }
684007
public function flush()
    {
        if ($this->is_done) {
            throw new RuntimeException('This batch insert is already done');
        }

        $count_rows = count($this->rows);

        if ($count_rows > 0) {
            $this->connection->execute($this->sql_foundation . implode(', ', $this->rows));

            $this->rows = [];
            $this->total += $count_rows;
        }
    }
1352848
public function doPerform()
    {
        if (!$this->mayInstall()) {
            throw new \RuntimeException('Project directory not empty.');
        }

        // Will throw exception upon error.
        $this->prepareTmpDir();

        $this->preserveEnvironment();

        try {
            parent::doPerform();
            $this->moveFiles();
        } catch (\Exception $exception) {
            $this->restoreEnvironment();
            throw new \RuntimeException('Project could not be created.', 1, $exception);
        } finally {
            $this->restoreEnvironment();
        }

        rmdir($this->tempDir);
    }
955313
public function execute()
	{
		$this->connect();

		if (!is_object($this->connection))
		{
			$this->log(
				Log\LogLevel::ERROR,
				'Database query failed (error #{code}): {message}',
				array('code' => $this->errorNum, 'message' => $this->errorMsg)
			);
			throw new \RuntimeException($this->errorMsg, $this->errorNum);
		}

		// Take a local copy so that we don't modify the original query and cause issues later
		$sql = $this->replacePrefix((string) $this->sql);

		if ($this->limit > 0 || $this->offset > 0)
		{
			$sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
		}

		// Increment the query counter.
		$this->count++;

		// If debugging is enabled then let's log the query.
		if ($this->debug)
		{
			// Add the query to the object queue.
			$this->log(
				Log\LogLevel::DEBUG,
				'{sql}',
				array('sql' => $sql, 'category' => 'databasequery', 'trace' => debug_backtrace())
			);
		}

		// Reset the error values.
		$this->errorNum = 0;
		$this->errorMsg = '';

		// Execute the query. Error suppression is used here to prevent warnings/notices that the connection has been lost.
		$this->cursor = @mysqli_query($this->connection, $sql);

		// If an error occurred handle it.
		if (!$this->cursor)
		{
			$this->errorNum = (int) mysqli_errno($this->connection);
			$this->errorMsg = (string) mysqli_error($this->connection) . "\n-- SQL --\n" . $sql;

			// Check if the server was disconnected.
			if (!$this->connected())
			{
				try
				{
					// Attempt to reconnect.
					$this->connection = null;
					$this->connect();
				}
				catch (\RuntimeException $e)
				// If connect fails, ignore that exception and throw the normal exception.
				{
					$this->log(
						Log\LogLevel::ERROR,
						'Database query failed (error #{code}): {message}',
						array('code' => $this->errorNum, 'message' => $this->errorMsg)
					);
					throw new \RuntimeException($this->errorMsg, $this->errorNum);
				}

				// Since we were able to reconnect, run the query again.
				return $this->execute();
			}
			else
			// The server was not disconnected.
			{
				$this->log(
					Log\LogLevel::ERROR,
					'Database query failed (error #{code}): {message}',
					array('code' => $this->errorNum, 'message' => $this->errorMsg)
				);
				throw new \RuntimeException($this->errorMsg, $this->errorNum);
			}
		}

		return $this->cursor;
	}
1083791
private function checkCacheValid( $cacheFile )
	{
		if ( file_exists( $cacheFile ) && ( filemtime( $cacheFile ) >  filemtime( $this->filePath ) ) )
		{
			return true;
		}

		return false;
	}
946068
private function resolveCache()
    {
        if (!$this->filesystem->exists($this->cacheFile)) {
            throw new \RuntimeException(sprintf(
                'The file "%s" can\'t be parsed!',
                $this->cacheFile
            ));
        }

        return unserialize(file_get_contents($this->cacheFile));
    }
244714
public function run()
    {
        if (($content = $this->getCachedContent()) !== false) {
            echo $content;
        } elseif ($this->cache instanceof Cache) {
            $content = ob_get_clean();
            if ($content === false || $content === '') {
                return;
            }
            array_pop($this->getView()->cacheStack);
            if (is_array($this->dependency)) {
                $this->dependency = Yii::createObject($this->dependency);
            }
            $data = [$content, $this->dynamicPlaceholders];
            $this->cache->set($this->calculateKey(), $data, $this->duration, $this->dependency);

            if (empty($this->getView()->cacheStack) && !empty($this->dynamicPlaceholders)) {
                $content = $this->updateDynamicContent($content, $this->dynamicPlaceholders);
            }
            echo $content;
        }
    }
931568
public function execute()
	{
		$this->connect();

		if (!is_object($this->connection))
		{
			$this->log(
				Log\LogLevel::ERROR,
				'Database query failed (error #{code}): {message}',
				array('code' => $this->errorNum, 'message' => $this->errorMsg)
			);
			throw new \RuntimeException($this->errorMsg, $this->errorNum);
		}

		// Take a local copy so that we don't modify the original query and cause issues later
		$sql = $this->replacePrefix((string) $this->sql);

		if ($this->limit > 0 || $this->offset > 0)
		{
			// @TODO
			$sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;
		}

		// Increment the query counter.
		$this->count++;

		// If debugging is enabled then let's log the query.
		if ($this->debug)
		{
			// Add the query to the object queue.
			$this->log(
				Log\LogLevel::DEBUG,
				'{sql}',
				array('sql' => $sql, 'category' => 'databasequery', 'trace' => debug_backtrace())
			);
		}

		// Reset the error values.
		$this->errorNum = 0;
		$this->errorMsg = '';

		// Execute the query.
		$this->executed = false;

		if ($this->prepared instanceof \PDOStatement)
		{
			// Bind the variables:
			if ($this->sql instanceof PreparableInterface)
			{
				$bounded =& $this->sql->getBounded();

				foreach ($bounded as $key => $obj)
				{
					$this->prepared->bindParam($key, $obj->value, $obj->dataType, $obj->length, $obj->driverOptions);
				}
			}

			$this->executed = $this->prepared->execute();
		}

		// If an error occurred handle it.
		if (!$this->executed)
		{
			// Get the error number and message before we execute any more queries.
			$errorNum = (int) $this->connection->errorCode();
			$errorMsg = (string) 'SQL: ' . implode(", ", $this->connection->errorInfo());

			// Check if the server was disconnected.
			if (!$this->connected())
			{
				try
				{
					// Attempt to reconnect.
					$this->connection = null;
					$this->connect();
				}
				catch (\RuntimeException $e)
				// If connect fails, ignore that exception and throw the normal exception.
				{
					// Get the error number and message.
					$this->errorNum = (int) $this->connection->errorCode();
					$this->errorMsg = (string) 'SQL: ' . implode(", ", $this->connection->errorInfo());

					// Throw the normal query exception.
					$this->log(
						Log\LogLevel::ERROR,
						'Database query failed (error #{code}): {message}',
						array('code' => $this->errorNum, 'message' => $this->errorMsg)
					);
					throw new \RuntimeException($this->errorMsg, $this->errorNum);
				}

				// Since we were able to reconnect, run the query again.
				return $this->execute();
			}
			else
			// The server was not disconnected.
			{
				// Get the error number and message from before we tried to reconnect.
				$this->errorNum = $errorNum;
				$this->errorMsg = $errorMsg;

				// Throw the normal query exception.
				$this->log(
					Log\LogLevel::ERROR,
					'Database query failed (error #{code}): {message}',
					array('code' => $this->errorNum, 'message' => $this->errorMsg)
				);
				throw new \RuntimeException($this->errorMsg, $this->errorNum);
			}
		}

		return $this->prepared;
	}
659801
public static function get(string $srcFile = ''): string
    {
        if (File::exists($srcFile) === false) {
            throw new RuntimeException('Source file does not exist: '.$srcFile);
        }

        $tmp = @\getimagesize($srcFile);
        if (empty($tmp)) {
            throw new RuntimeException('Invalid source file: '.$srcFile);
        }

        return \sprintf('%s:%s', $tmp[0], $tmp[1]);
    }
467611
protected function shutdown(string $runlevel)
    {
        $this->bootstrap->shutdown($runlevel);
        if ($runlevel === Bootstrap::RUNLEVEL_COMPILETIME) {
            $this->objectManager->get(LockManager::class)->unlockSite();
        }
        exit($this->response->getExitCode());
    }
282357
protected function loadFromCache() : void
    {
        $data = include $this->cacheFile;
        if (!is_array($data) ||
            !isset($data['routes']) ||
            !is_array($data['routes']) ||
            !isset($data['dispatch_data']) ||
            !is_array($data['dispatch_data'])
        ) {
            throw new \RuntimeException(sprintf(
                'Invalid cache file "%s"',
                $this->cacheFile
            ));
        }

        $this->routes = $data['routes'];
        $this->dispatchData = $data['dispatch_data'];
    }
350776
public function init()
    {
        $stream = @fopen($this->config['url'], 'a');
        if (!$stream) {
            throw new \RuntimeException(sprintf("Couldn't open resource '%s'", $this->config['url']));
        }

        $this->stream = $stream;

        if (!empty($this->config['lock']) && $this->config['lock'] === true && stream_supports_lock($this->stream)) {
            $this->useLocks = true;
        }
    }
963799
public function run()
    {
        if(version_compare(SWOOLE_VERSION, '4.1', '>='))
        {
            \Swoole\Runtime::enableCoroutine(true);
        }
        if(file_exists($this->socketFile))
        {
            unlink($this->socketFile);
        }
        go(function(){
            $this->socket = stream_socket_server('unix://' . $this->socketFile, $errno, $errstr);
            if(false === $this->socket)
            {
                throw new \RuntimeException(sprintf('Create unix socket server failed, errno: %s, errstr: %s', $errno, $errstr));
            }
            while(true)
            {
                $conn = stream_socket_accept($this->socket, 0);
                if(false === $conn)
                {
                    continue;
                }
                go(function() use($conn){
                    $this->parseConn($conn);
                });
            }
        });
    }