This commit is contained in:
as2252258@163.com
2021-05-02 13:52:28 +08:00
11 changed files with 803 additions and 907 deletions
+9 -104
View File
@@ -235,10 +235,7 @@ class Loader extends BaseObject
$path = '/' . trim($path, '/'); $path = '/' . trim($path, '/');
foreach ($this->_directory as $key => $_path) { foreach ($this->_directory as $key => $_path) {
$key = '/' . trim($key, '/'); $key = '/' . trim($key, '/');
if (!str_starts_with($key, $path)) { if (!str_starts_with($key, $path) || in_array($key, $outPath)) {
continue;
}
if (in_array($key, $outPath)) {
continue; continue;
} }
$this->execute($_path); $this->execute($_path);
@@ -279,98 +276,6 @@ class Loader extends BaseObject
$array = '/' . trim(implode('/', $array), '/'); $array = '/' . trim(implode('/', $array), '/');
$this->_directory[$array][] = $className; $this->_directory[$array][] = $className;
// $directory = $this->splitDirectory($filePath);
// array_pop($directory);
//
// $tree = null;
// foreach ($directory as $value) {
// $tree = $this->getTree($tree, $value);
// }
//
// if ($tree instanceof FileTree) {
// $tree->addFile($className, $filePath);
// }
}
/**
* @param string $filePath
* @param string|null $outPath
* @return $this
* @throws Exception
*/
private function each(string $filePath, ?string $outPath): static
{
$tree = null;
$directory = $this->splitDirectory($filePath);
$_tmp = '';
if (!empty($outPath)) {
$outPath = rtrim($outPath, '/');
}
foreach ($directory as $key => $value) {
$_tmp .= DIRECTORY_SEPARATOR . $value;
if (!empty($outPath) && str_contains($_tmp, $outPath)) {
break;
}
$tree = $this->getTree($tree, $value);
}
if ($tree instanceof FileTree) {
$this->eachNode($tree->getChildes(), $outPath);
$this->execute($tree->getFiles());
}
return $this;
}
/**
* @param string $filePath
* @return false|string[]
*/
private function splitDirectory(string $filePath): array|bool
{
$DIRECTORY = explode(DIRECTORY_SEPARATOR, $filePath);
return array_filter($DIRECTORY, function ($value) {
return !empty($value);
});
}
/**
* @param $tree
* @param $value
* @return FileTree
*/
private function getTree($tree, $value): FileTree
{
if ($tree === null) {
$tree = $this->files->getChild($value);
} else {
$tree = $tree->getChild($value);
}
return $tree;
}
/**
* @param FileTree[] $nodes
* @param string|null $outPath
* @throws Exception
*/
private function eachNode(array $nodes, ?string $outPath = '')
{
foreach ($nodes as $node) {
$this->execute($node->getFiles());
if (!empty($outPath) && str_contains($node->getDirPath(), $outPath)) {
continue;
}
$childes = $node->getChildes();
if (!empty($childes)) {
$this->eachNode($childes, $outPath);
}
}
} }
@@ -395,31 +300,31 @@ class Loader extends BaseObject
if (empty($classes)) { if (empty($classes)) {
return; return;
} }
$annotation = Snowflake::app()->getAnnotation(); $annotation = Snowflake::getAnnotation();
foreach ($classes as $className) { foreach ($classes as $className) {
$annotations = $this->_classes[$className] ?? null; $annotations = $this->_classes[$className] ?? null;
if ($annotations === null) { if ($annotations === null) {
continue; continue;
} }
$class = clone $annotations['handler'];
foreach ($annotations['target'] ?? [] as $value) { foreach ($annotations['target'] ?? [] as $value) {
$value->execute([$annotations['handler']]); $value->execute([$class]);
} }
$_className = $annotations['handler']::class;
foreach ($annotations['methods'] as $name => $attribute) { foreach ($annotations['methods'] as $name => $attribute) {
foreach ($attribute as $value) { foreach ($attribute as $value) {
if ($value instanceof Relation) { if ($value instanceof Relation) {
$annotation->addRelate($_className, $value->name, $name); $annotation->addRelate($class::class, $value->name, $name);
} else if ($value instanceof Get) { } else if ($value instanceof Get) {
$annotation->addGets($_className, $value->name, $name); $annotation->addGets($class::class, $value->name, $name);
} else if ($value instanceof Set) { } else if ($value instanceof Set) {
$annotation->addSets($_className, $value->name, $name); $annotation->addSets($class::class, $value->name, $name);
} else { } else {
$value->execute([$annotations['handler'], $name]); $value->execute([$class, $name]);
} }
} }
} }
} }
} }
} }
+355 -363
View File
@@ -32,418 +32,410 @@ defined('FIND_OR_CREATE_MESSAGE') or define('FIND_OR_CREATE_MESSAGE', 'Create a
class ActiveRecord extends BaseActiveRecord class ActiveRecord extends BaseActiveRecord
{ {
const DECR = 'decr'; const DECR = 'decr';
const INCR = 'incr'; const INCR = 'incr';
/** /**
* @return array * @return array
*/ */
public function rules(): array public function rules(): array
{ {
return []; return [];
} }
/** /**
* @param string $column * @param string $column
* @param int $value * @param int $value
* @return ActiveRecord|false * @return ActiveRecord|false
* @throws Exception * @throws Exception
*/ */
public function increment(string $column, int $value): bool|ActiveRecord public function increment(string $column, int $value): bool|ActiveRecord
{ {
if (!$this->mathematics([$column => $value], '+')) { if (!$this->mathematics([$column => $value], '+')) {
return false; return false;
} }
$this->{$column} += $value; $this->{$column} += $value;
return $this->refresh(); return $this->refresh();
} }
/** /**
* @param string $column * @param string $column
* @param int $value * @param int $value
* @return ActiveRecord|false * @return ActiveRecord|false
* @throws Exception * @throws Exception
*/ */
public function decrement(string $column, int $value): bool|ActiveRecord public function decrement(string $column, int $value): bool|ActiveRecord
{ {
if (!$this->mathematics([$column => $value], '-')) { if (!$this->mathematics([$column => $value], '-')) {
return false; return false;
} }
$this->{$column} -= $value; $this->{$column} -= $value;
return $this->refresh(); return $this->refresh();
} }
/** /**
* @param array $columns * @param array $columns
* @return ActiveRecord|false * @return ActiveRecord|false
* @throws Exception * @throws Exception
*/ */
public function increments(array $columns): bool|static public function increments(array $columns): bool|static
{ {
if (!$this->mathematics($columns, '+')) { if (!$this->mathematics($columns, '+')) {
return false; return false;
} }
foreach ($columns as $key => $attribute) { foreach ($columns as $key => $attribute) {
$this->$key += $attribute; $this->$key += $attribute;
} }
return $this; return $this;
} }
/** /**
* @param array $columns * @param array $columns
* @return ActiveRecord|false * @return ActiveRecord|false
* @throws Exception * @throws Exception
*/ */
public function decrements(array $columns): bool|static public function decrements(array $columns): bool|static
{ {
if (!$this->mathematics($columns, '-')) { if (!$this->mathematics($columns, '-')) {
return false; return false;
} }
foreach ($columns as $key => $attribute) { foreach ($columns as $key => $attribute) {
$this->$key -= $attribute; $this->$key -= $attribute;
} }
return $this; return $this;
} }
/** /**
* @param array $condition * @param array $condition
* @param array $attributes * @param array $attributes
* @return bool|ActiveRecord * @return bool|ActiveRecord
* @throws ReflectionException * @throws ReflectionException
* @throws NotFindClassException * @throws NotFindClassException
* @throws Exception * @throws Exception
*/ */
public static function findOrCreate(array $condition, array $attributes = []): bool|static public static function findOrCreate(array $condition, array $attributes = []): bool|static
{ {
$logger = Snowflake::app()->getLogger(); $logger = Snowflake::app()->getLogger();
/** @var static $select */ /** @var static $select */
$select = static::find()->where($condition)->first(); $select = static::find()->where($condition)->first();
if (!empty($select)) { if (!empty($select)) {
return $select; return $select;
} }
if (empty($attributes)) { if (empty($attributes)) {
return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql');
} }
$select = self::getModelClass(); $select = self::getModelClass();
$select->attributes = $attributes; $select->attributes = $attributes;
if (!$select->save()) { if (!$select->save()) {
return $logger->addError($select->getLastError(), 'mysql'); return $logger->addError($select->getLastError(), 'mysql');
} }
return $select; return $select;
} }
/** /**
* @param array $condition * @param array $condition
* @param array $attributes * @param array $attributes
* @return bool|static * @return bool|static
* @throws Exception * @throws Exception
*/ */
public static function createOrUpdate(array $condition, array $attributes = []): bool|static public static function createOrUpdate(array $condition, array $attributes = []): bool|static
{ {
$logger = Snowflake::app()->getLogger(); $logger = Snowflake::app()->getLogger();
if (empty($attributes)) { if (empty($attributes)) {
return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql'); return $logger->addError(FIND_OR_CREATE_MESSAGE, 'mysql');
} }
/** @var static $select */ /** @var static $select */
$select = static::find()->where($condition)->first(); $select = static::find()->where($condition)->first();
if (empty($select)) { if (empty($select)) {
$select = self::getModelClass(); $select = self::getModelClass();
} }
$select->attributes = $attributes; $select->attributes = $attributes;
if (!$select->save()) { if (!$select->save()) {
return $logger->addError($select->getLastError(), 'mysql'); return $logger->addError($select->getLastError(), 'mysql');
} }
return $select; return $select;
} }
/** /**
* @return static * @return static
* @throws Exception * @throws Exception
*/ */
private static function getModelClass(): static private static function getModelClass(): static
{ {
/** @var Channel $channel */ /** @var Channel $channel */
$channel = Snowflake::app()->get('channel'); $channel = Snowflake::app()->get('channel');
return $channel->pop(static::class, function () { return $channel->pop(static::class, function () {
return new static(); return new static();
}); });
} }
/** /**
* @param $action * @param $action
* @param $columns * @param $columns
* @param array $condition * @param array $condition
* @return array|bool|int|string|null * @return array|bool|int|string|null
* @throws Exception * @throws Exception
*/ */
private function mathematics($columns, $action, $condition = []): int|bool|array|string|null private function mathematics($columns, $action, $condition = []): int|bool|array|string|null
{ {
if (empty($condition)) { if (empty($condition)) {
$condition = [$this->getPrimary() => $this->getPrimaryValue()]; $condition = [$this->getPrimary() => $this->getPrimaryValue()];
} }
$activeQuery = static::find()->where($condition); $activeQuery = static::find()->where($condition);
$create = SqlBuilder::builder($activeQuery)->mathematics($columns, $action); $create = SqlBuilder::builder($activeQuery)->mathematics($columns, $action);
if (is_bool($create)) { if (is_bool($create)) {
return false; return false;
} }
return static::getDb()->createCommand($create[0], $create[1])->exec(); return static::getDb()->createCommand($create[0], $create[1])->exec();
} }
/** /**
* @param array $fields * @param array $fields
* @return ActiveRecord|bool * @return ActiveRecord|bool
* @throws Exception * @throws Exception
*/ */
public function update(array $fields): static|bool public function update(array $fields): static|bool
{ {
return $this->save($fields); return $this->save($fields);
} }
/** /**
* @param array $data * @param array $data
* @return bool * @return bool
* @throws Exception * @throws Exception
*/ */
public static function inserts(array $data): bool public static function inserts(array $data): bool
{ {
/** @var static $class */ /** @var static $class */
$class = Snowflake::createObject(['class' => static::class]); $class = Snowflake::createObject(['class' => static::class]);
if (empty($data)) { if (empty($data)) {
return $class->addError('Insert data empty.', 'mysql'); return $class->addError('Insert data empty.', 'mysql');
} }
return $class::find()->batchInsert($data); return $class::find()->batchInsert($data);
} }
/** /**
* @return bool * @return bool
* @throws Exception * @throws Exception
*/ */
public function delete(): bool public function delete(): bool
{ {
$conditions = $this->_oldAttributes; $conditions = $this->_oldAttributes;
if (empty($conditions)) { if (empty($conditions)) {
return $this->addError("Delete condition do not empty.", 'mysql'); return $this->addError("Delete condition do not empty.", 'mysql');
} }
$primary = $this->getPrimary(); $primary = $this->getPrimary();
if (!empty($primary)) { if (!empty($primary)) {
$conditions = [$primary => $this->getAttribute($primary)]; $conditions = [$primary => $this->getAttribute($primary)];
} }
return static::deleteByCondition($conditions); return static::deleteByCondition($conditions);
} }
/** /**
* @param $condition * @param $condition
* @param array $attributes * @param array $attributes
* *
* @return bool * @return bool
* @throws Exception * @throws Exception
*/ */
public static function updateAll(mixed $condition, $attributes = []): bool public static function updateAll(mixed $condition, $attributes = []): bool
{ {
$condition = static::find()->where($condition); $condition = static::find()->where($condition);
return $condition->batchUpdate($attributes); return $condition->batchUpdate($attributes);
} }
/** /**
* @param $condition * @param $condition
* @param array $attributes * @param array $attributes
* *
* @return array|Collection * @return array|Collection
* @throws Exception * @throws Exception
*/ */
public static function findAll($condition, $attributes = []): array|Collection public static function findAll($condition, $attributes = []): array|Collection
{ {
$query = static::find()->where($condition); $query = static::find()->where($condition);
if (!empty($attributes)) { if (!empty($attributes)) {
$query->bindParams($attributes); $query->bindParams($attributes);
} }
return $query->all(); return $query->all();
} }
/** /**
* @param $method * @param $method
* @return mixed * @return mixed
* @throws Exception * @throws Exception
*/ */
private function resolveObject($method): mixed private function resolveObject($method): mixed
{ {
$resolve = $this->{$this->getRelate($method)}(); $resolve = $this->{$this->getRelate($method)}();
if ($resolve instanceof HasBase) { if ($resolve instanceof HasBase) {
$resolve = $resolve->get(); $resolve = $resolve->get();
} }
if ($resolve instanceof Collection) { if ($resolve instanceof Collection) {
return $resolve->toArray(); return $resolve->toArray();
} else if ($resolve instanceof ActiveRecord) { } else if ($resolve instanceof ActiveRecord) {
return $resolve->toArray(); return $resolve->toArray();
} else if (is_object($resolve)) { } else if (is_object($resolve)) {
return get_object_vars($resolve); return get_object_vars($resolve);
} else { } else {
return $resolve; return $resolve;
} }
} }
/** /**
* @return array * @return array
* @throws Exception * @throws Exception
*/ */
public function toArray(): array public function toArray(): array
{ {
$data = $this->_attributes; $data = $this->_attributes;
$lists = Snowflake::getAnnotation()->getGets(static::class); $lists = Snowflake::getAnnotation()->getGets(static::class);
foreach ($lists as $key => $item) { foreach ($lists as $key => $item) {
$data[$key] = $this->{$item}($data[$key] ?? null); $data[$key] = $this->{$item}($data[$key] ?? null);
} }
$data = array_merge($data, $this->runRelate()); $data = array_merge($data, $this->runRelate());
$class = Snowflake::app()->getChannel(); $class = Snowflake::app()->getChannel();
$class->push($this, static::class); $class->push($this, static::class);
return $data; return $data;
} }
/** /**
* @return array * @return array
* @throws Exception * @throws Exception
*/ */
private function runRelate(): array private function runRelate(): array
{ {
$relates = []; $relates = [];
if (empty($with = $this->getWith())) { if (empty($with = $this->getWith())) {
return $relates; return $relates;
} }
foreach ($with as $val) { foreach ($with as $val) {
$relates[$val] = $this->resolveObject($val); $relates[$val] = $this->resolveObject($val);
} }
return $relates; return $relates;
} }
/** /**
* @param string $modelName * @param string $modelName
* @param $foreignKey * @param $foreignKey
* @param $localKey * @param $localKey
* @return HasOne|ActiveQuery * @return HasOne|ActiveQuery
* @throws Exception * @throws Exception
*/ */
public function hasOne(string $modelName, $foreignKey, $localKey): HasOne|ActiveQuery public function hasOne(string $modelName, $foreignKey, $localKey): HasOne|ActiveQuery
{ {
if (!$this->has($localKey)) { if (($value = $this->getAttribute($localKey)) === null) {
throw new Exception("Need join table primary key."); throw new Exception("Need join table primary key.");
} }
$value = $this->getAttribute($localKey); $relation = $this->getRelation();
$relation = $this->getRelation(); return new HasOne($modelName, $foreignKey, $value, $relation);
}
return new HasOne($modelName, $foreignKey, $value, $relation);
}
/** /**
* @param $modelName * @param $modelName
* @param $foreignKey * @param $foreignKey
* @param $localKey * @param $localKey
* @return ActiveQuery * @return ActiveQuery
* @throws Exception * @throws Exception
*/ */
public function hasCount($modelName, $foreignKey, $localKey): mixed public function hasCount($modelName, $foreignKey, $localKey): mixed
{ {
if (!$this->has($localKey)) { if (($value = $this->getAttribute($localKey)) === null) {
throw new Exception("Need join table primary key."); throw new Exception("Need join table primary key.");
} }
$value = $this->getAttribute($localKey); $relation = $this->getRelation();
$relation = $this->getRelation(); return new HasCount($modelName, $foreignKey, $value, $relation);
}
return new HasCount($modelName, $foreignKey, $value, $relation);
}
/** /**
* @param $modelName * @param $modelName
* @param $foreignKey * @param $foreignKey
* @param $localKey * @param $localKey
* @return ActiveQuery * @return ActiveQuery
* @throws Exception * @throws Exception
*/ */
public function hasMany($modelName, $foreignKey, $localKey): mixed public function hasMany($modelName, $foreignKey, $localKey): mixed
{ {
if (!$this->has($localKey)) { if (($value = $this->getAttribute($localKey)) === null) {
throw new Exception("Need join table primary key."); throw new Exception("Need join table primary key.");
} }
$value = $this->getAttribute($localKey); $relation = $this->getRelation();
$relation = $this->getRelation(); return new HasMany($modelName, $foreignKey, $value, $relation);
}
return new HasMany($modelName, $foreignKey, $value, $relation); /**
} * @param $modelName
* @param $foreignKey
* @param $localKey
* @return ActiveQuery
* @throws Exception
*/
public function hasIn($modelName, $foreignKey, $localKey): mixed
{
if (($value = $this->getAttribute($localKey)) === null) {
throw new Exception("Need join table primary key.");
}
/** $relation = $this->getRelation();
* @param $modelName
* @param $foreignKey
* @param $localKey
* @return ActiveQuery
* @throws Exception
*/
public function hasIn($modelName, $foreignKey, $localKey): mixed
{
if (!$this->has($localKey)) {
throw new Exception("Need join table primary key.");
}
$value = $this->getAttribute($localKey); return new HasMany($modelName, $foreignKey, $value, $relation);
}
$relation = $this->getRelation(); /**
* @return bool
* @throws Exception
*/
public function afterDelete(): bool
{
if (!$this->hasPrimary()) {
return TRUE;
}
$value = $this->getPrimaryValue();
if (empty($value)) {
return TRUE;
}
return TRUE;
}
return new HasMany($modelName, $foreignKey, $value, $relation); /**
} * @return bool
* @throws Exception
/** */
* @return bool public function beforeDelete(): bool
* @throws Exception {
*/ if (!$this->hasPrimary()) {
public function afterDelete(): bool return TRUE;
{ }
if (!$this->hasPrimary()) { $value = $this->getPrimaryValue();
return TRUE; if (empty($value)) {
} return TRUE;
$value = $this->getPrimaryValue(); }
if (empty($value)) { return TRUE;
return TRUE; }
}
return TRUE;
}
/**
* @return bool
* @throws Exception
*/
public function beforeDelete(): bool
{
if (!$this->hasPrimary()) {
return TRUE;
}
$value = $this->getPrimaryValue();
if (empty($value)) {
return TRUE;
}
return TRUE;
}
} }
+3 -2
View File
@@ -968,7 +968,7 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess
*/ */
public function offsetExists(mixed $offset): bool public function offsetExists(mixed $offset): bool
{ {
return $this->has($offset); return isset($this->_attributes[$offset]) || isset($this->_oldAttributes[$offset]);
} }
/** /**
@@ -997,7 +997,8 @@ abstract class BaseActiveRecord extends Component implements IOrm, ArrayAccess
*/ */
public function offsetUnset(mixed $offset) public function offsetUnset(mixed $offset)
{ {
if (!$this->has($offset)) { if (!isset($this->_attributes[$offset])
&& !isset($this->_oldAttributes[$offset])) {
return; return;
} }
unset($this->_attributes[$offset]); unset($this->_attributes[$offset]);
-8
View File
@@ -121,15 +121,11 @@ class Command extends Component
private function execute($type, $isInsert = null, $hasAutoIncrement = null): int|bool|array|string|null private function execute($type, $isInsert = null, $hasAutoIncrement = null): int|bool|array|string|null
{ {
try { try {
$time = microtime(true);
if ($type === static::EXECUTE) { if ($type === static::EXECUTE) {
$result = $this->insert_or_change($isInsert, $hasAutoIncrement); $result = $this->insert_or_change($isInsert, $hasAutoIncrement);
} else { } else {
$result = $this->search($type); $result = $this->search($type);
} }
if (microtime(true) - $time >= 0.03) {
$this->warning('execute sql Worker.' . env('worker') . '.' . Coroutine::getCid() . '`' . $this->sql . '` use time ' . (microtime(true) - $time));
}
return $result; return $result;
} catch (\Throwable $exception) { } catch (\Throwable $exception) {
return $this->addError($this->sql . '. error: ' . $exception->getMessage(), 'mysql'); return $this->addError($this->sql . '. error: ' . $exception->getMessage(), 'mysql');
@@ -144,11 +140,7 @@ class Command extends Component
*/ */
private function search($type): mixed private function search($type): mixed
{ {
$time = microtime(true);
$connect = $this->db->getConnect($this->sql); $connect = $this->db->getConnect($this->sql);
if (microtime(true) - $time > 0.02) {
$this->error('get connect time:' . $this->sql . '; ' . (microtime(true) - $time));
}
if (!($query = $connect?->query($this->sql))) { if (!($query = $connect?->query($this->sql))) {
return $this->addError($connect->errorInfo()[2] ?? '数据库异常, 请稍后再试.'); return $this->addError($connect->errorInfo()[2] ?? '数据库异常, 请稍后再试.');
} }
+17 -4
View File
@@ -9,6 +9,7 @@ use HttpServer\Abstracts\Callback;
use Snowflake\Event; use Snowflake\Event;
use Snowflake\Exception\ConfigException; use Snowflake\Exception\ConfigException;
use Snowflake\Snowflake; use Snowflake\Snowflake;
use Swoole\Coroutine;
use Swoole\Coroutine\System; use Swoole\Coroutine\System;
use Swoole\Server; use Swoole\Server;
@@ -32,10 +33,7 @@ class OnWorkerStart extends Callback
putenv('state=start'); putenv('state=start');
putenv('worker=' . $worker_id); putenv('worker=' . $worker_id);
$content = System::readFile(storage('runtime.php')); $annotation = $this->settings();
$annotation = Snowflake::app()->getAnnotation();
$annotation->setLoader(unserialize($content));
if ($worker_id < $server->setting['worker_num']) { if ($worker_id < $server->setting['worker_num']) {
$this->onWorker($server, $annotation); $this->onWorker($server, $annotation);
} else { } else {
@@ -44,6 +42,21 @@ class OnWorkerStart extends Callback
} }
/**
* @return \Annotation\Annotation
* @throws \Exception
*/
private function settings(): Annotation
{
$content = System::readFile(storage('runtime.php'));
$annotation = Snowflake::app()->getAnnotation();
$annotation->setLoader(unserialize($content));
return $annotation;
}
/** /**
* @param Server $server * @param Server $server
* @param int $worker_id * @param int $worker_id
+206 -212
View File
@@ -13,239 +13,233 @@ use Swoole\Coroutine;
class Context extends BaseContext class Context extends BaseContext
{ {
protected static array $_contents = []; protected static array $_contents = [];
/**
* @param $id
* @param $context
* @param null $key
* @return mixed
*/
public static function setContext($id, $context, $key = null): mixed
{
if (!static::inCoroutine()) {
return static::setStatic($id, $context, $key);
}
return self::setCoroutine($id, $context, $key);
}
/** /**
* @param $id * @param $id
* @param $context * @param $context
* @param null $key * @param null $key
* @return mixed * @return array
*/ */
public static function setContext($id, $context, $key = null): mixed private static function setStatic($id, $context, $key = null): mixed
{ {
if (static::inCoroutine()) { if (empty($key)) {
return self::setCoroutine($id, $context, $key); return static::$_contents[$id] = $context;
} else { }
return self::setStatic($id, $context, $key); if (!is_array(static::$_contents[$id])) {
} static::$_contents[$id] = [$key => $context];
} } else {
static::$_contents[$id][$key] = $context;
}
return $context;
}
/** /**
* @param $id * @param $id
* @param $context * @param $context
* @param null $key * @param null $key
* @return array * @return mixed
*/ */
private static function setStatic($id, $context, $key = null): mixed private static function setCoroutine($id, $context, $key = null): mixed
{ {
if (empty($key)) { if (empty($key)) {
return static::$_contents[$id] = $context; return Coroutine::getContext()[$id] = $context;
} }
if (!is_array(static::$_contents[$id])) { if (!is_array(Coroutine::getContext()[$id])) {
static::$_contents[$id] = [$key => $context]; Coroutine::getContext()[$id] = [$key => $context];
} else { } else {
static::$_contents[$id][$key] = $context; Coroutine::getContext()[$id][$key] = $context;
} }
return $context; return $context;
} }
/** /**
* @param $id * @param $id
* @param $context * @param null $key
* @param null $key * @param int $value
* @return mixed * @return bool|int
*/ */
private static function setCoroutine($id, $context, $key = null): mixed public static function increment($id, $key = null, $value = 1): bool|int
{ {
if (empty($key)) { if (!isset(Coroutine::getContext()[$id][$key])) {
return Coroutine::getContext()[$id] = $context; return false;
} }
if (!is_array(Coroutine::getContext()[$id])) { return Coroutine::getContext()[$id][$key] += $value;
Coroutine::getContext()[$id] = [$key => $context]; }
} else {
Coroutine::getContext()[$id][$key] = $context;
}
return $context;
}
/** /**
* @param $id * @param $id
* @param null $key * @param null $key
* @param int $value * @param int $value
* @return bool|int * @return bool|int
*/ */
public static function increment($id, $key = null, $value = 1): bool|int public static function decrement($id, $key = null, $value = 1): bool|int
{ {
if (!static::inCoroutine()) { if (!static::hasContext($id)) {
return false; return false;
} }
if (!isset(Coroutine::getContext()[$id][$key])) { if (!isset(Coroutine::getContext()[$id][$key])) {
return false; return false;
} }
return Coroutine::getContext()[$id][$key] += $value; return Coroutine::getContext()[$id][$key] -= $value;
} }
/** /**
* @param $id * @param $id
* @param null $key * @param null $key
* @param int $value * @return mixed
* @return bool|int */
*/ public static function getContext($id, $key = null): mixed
public static function decrement($id, $key = null, $value = 1): bool|int {
{ if (!static::inCoroutine()) {
if (!static::inCoroutine() || !static::hasContext($id)) { return static::loadByStatic($id, $key);
return false; }
} return static::loadByContext($id, $key);
if (!isset(Coroutine::getContext()[$id][$key])) { }
return false;
}
return Coroutine::getContext()[$id][$key] -= $value;
}
/**
* @param $id
* @param null $key
* @return mixed
*/
public static function getContext($id, $key = null): mixed
{
if (!static::hasContext($id)) {
return null;
}
if (static::inCoroutine()) {
return static::loadByContext($id, $key);
} else {
return static::loadByStatic($id, $key);
}
}
/** /**
* @param $id * @param $id
* @param null $key * @param null $key
* @return mixed * @return mixed
*/ */
private static function loadByContext($id, $key = null): mixed private static function loadByContext($id, $key = null): mixed
{ {
$data = Coroutine::getContext()[$id] ?? null; $data = Coroutine::getContext()[$id] ?? null;
if ($data === null) { if ($data === null) {
return null; return null;
} }
if ($key !== null) { if ($key !== null) {
return $data[$key] ?? null; return $data[$key] ?? null;
} }
return $data; return $data;
} }
/** /**
* @param $id * @param $id
* @param null $key * @param null $key
* @return mixed * @return mixed
*/ */
private static function loadByStatic($id, $key = null): mixed private static function loadByStatic($id, $key = null): mixed
{ {
$data = static::$_contents[$id] ?? null; $data = static::$_contents[$id] ?? null;
if ($data === null) { if ($data === null) {
return null; return null;
} }
if ($key !== null) { if ($key !== null) {
return $data[$key] ?? null; return $data[$key] ?? null;
} }
return $data; return $data;
} }
/** /**
* @return mixed * @return mixed
*/ */
public static function getAllContext(): mixed public static function getAllContext(): mixed
{ {
if (static::inCoroutine()) { if (static::inCoroutine()) {
return Coroutine::getContext() ?? []; return Coroutine::getContext() ?? [];
} else { } else {
return static::$_contents ?? []; return static::$_contents ?? [];
} }
} }
/** /**
* @param string $id * @param string $id
* @param string|null $key * @param string|null $key
*/ */
public static function remove(string $id, string $key = null) public static function remove(string $id, string $key = null)
{ {
if (!static::hasContext($id, $key)) { if (!static::hasContext($id, $key)) {
return; return;
} }
if (static::inCoroutine()) { if (!static::inCoroutine()) {
unset(static::$_contents[$id]); if (!empty($key)) {
return; unset(static::$_contents[$id][$key]);
} } else {
if (!empty($key)) { unset(static::$_contents[$id]);
unset(Coroutine::getContext()[$id][$key]); }
} else { } else {
unset(Coroutine::getContext()[$id]); if (!empty($key)) {
} unset(Coroutine::getContext()[$id][$key]);
} } else {
unset(Coroutine::getContext()[$id]);
}
}
}
/** /**
* @param $id * @param $id
* @param null $key * @param null $key
* @return bool * @return bool
*/ */
public static function hasContext($id, $key = null): bool public static function hasContext($id, $key = null): bool
{ {
if (!static::inCoroutine()) { if (!static::inCoroutine()) {
return static::searchByStatic($id, $key); return static::searchByStatic($id, $key);
} else { }
return static::searchByCoroutine($id, $key); return static::searchByCoroutine($id, $key);
} }
}
/** /**
* @param $id * @param $id
* @param null $key * @param null $key
* @return bool * @return bool
*/ */
private static function searchByStatic($id, $key = null): bool private static function searchByStatic($id, $key = null): bool
{ {
if (!isset(static::$_contents[$id])) { if (!isset(static::$_contents[$id])) {
return false; return false;
} }
if (!empty($key) && !isset(static::$_contents[$id][$key])) { if (!empty($key) && !isset(static::$_contents[$id][$key])) {
return false; return false;
} }
return true; return true;
} }
/** /**
* @param $id * @param $id
* @param null $key * @param null $key
* @return bool * @return bool
*/ */
private static function searchByCoroutine($id, $key = null): bool private static function searchByCoroutine($id, $key = null): bool
{ {
if (!isset(Coroutine::getContext()[$id])) { if (!isset(Coroutine::getContext()[$id])) {
return false; return false;
} }
if ($key !== null) { if ($key !== null) {
return isset((Coroutine::getContext()[$id] ?? [])[$key]); return isset((Coroutine::getContext()[$id] ?? [])[$key]);
} }
return true; return true;
} }
/** /**
* @return bool * @return bool
*/ */
public static function inCoroutine(): bool public static function inCoroutine(): bool
{ {
return Coroutine::getCid() > 0; return Coroutine::getCid() !== -1;
} }
} }
+5 -1
View File
@@ -115,7 +115,11 @@ class Server extends HttpService
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_BLOCKING_FUNCTION); Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_BLOCKING_FUNCTION);
Coroutine::set(['enable_deadlock_check' => false]); $settings['enable_deadlock_check'] = false;
$settings['exit_condition'] = function () {
return Coroutine::stats()['coroutine_num'] === 0;
};
Coroutine::set($settings);
return $this->execute($baseServer); return $this->execute($baseServer);
} }
-4
View File
@@ -174,11 +174,7 @@ abstract class Pool extends Component
if ($this->_items[$name]->isEmpty()) { if ($this->_items[$name]->isEmpty()) {
$this->createByCallback($name, $callback); $this->createByCallback($name, $callback);
} }
$time = microtime(true);
$connection = $this->_items[$name]->pop(0.002); $connection = $this->_items[$name]->pop(0.002);
if (($end = microtime(true) - $time) >= 0.01) {
$this->error('waite channel connect use time.' . $end);
}
if (!$this->checkCanUse($name, $connection)) { if (!$this->checkCanUse($name, $connection)) {
return $this->createClient($name, $callback); return $this->createClient($name, $callback);
} else { } else {
+8 -13
View File
@@ -29,6 +29,9 @@ class Channel extends Component
public function push(mixed $value, string $name = ''): void public function push(mixed $value, string $name = ''): void
{ {
$channel = $this->channelInit($name); $channel = $this->channelInit($name);
if ($channel->count() >= 100) {
return;
}
$channel->enqueue($value); $channel->enqueue($value);
} }
@@ -71,21 +74,13 @@ class Channel extends Component
* @return mixed * @return mixed
* @throws Exception * @throws Exception
*/ */
public function pop(string $name, Closure $closure, int|float $timeout = null): mixed public function pop(string $name, Closure $closure): mixed
{ {
if (($channel = $this->channelInit($name)) == false) { $channel = $this->channelInit($name);
return $this->addError('Channel is full.'); if ($channel->isEmpty()) {
return call_user_func($closure);
} }
if (!$channel->isEmpty()) { return $channel->dequeue();
return $channel->shift();
}
if ($timeout !== null) {
$data = $channel->dequeue();
}
if (empty($data)) {
$data = call_user_func($closure);
}
return $data;
} }
+3
View File
@@ -467,6 +467,9 @@ mlAZUEjsoaT9vjvjGTxl3uCm0TX5KTgtSJIt2kA1tYVjQef+/iZTHxY=
if (!empty($source)) { if (!empty($source)) {
$this->data['source'] = $source; $this->data['source'] = $source;
} }
if (!isset($this->data['token'])) {
return;
}
$key = $this->authKey($this->getSource(), $this->data['token']); $key = $this->authKey($this->getSource(), $this->data['token']);
$this->getRedis()->expire($key, $this->timeout); $this->getRedis()->expire($key, $this->timeout);
} }
+197 -196
View File
@@ -19,225 +19,226 @@ class Connection extends Pool
{ {
public int $timeout = 1900; public int $timeout = 1900;
/** /**
* @param $timeout * @param $timeout
*/ */
public function setTimeout($timeout) public function setTimeout($timeout)
{ {
$this->timeout = $timeout; $this->timeout = $timeout;
} }
/** /**
* @param $value * @param $value
*/ */
public function setLength($value) public function setLength($value)
{ {
$this->max = $value; $this->max = $value;
} }
/** /**
* @param $cds * @param $cds
* @return bool * @return bool
* *
* db is in transaction * db is in transaction
*/ */
public function inTransaction($cds): bool public function inTransaction($cds): bool
{ {
return Context::getContext('begin_' . $this->name('mysql', $cds, true)) == 0; return Context::getContext('begin_' . $this->name('mysql', $cds, true)) == 0;
} }
/** /**
* @param $coroutineName * @param $coroutineName
*/ */
public function beginTransaction($coroutineName) public function beginTransaction($coroutineName)
{ {
$coroutineName = $this->name('mysql', $coroutineName, true); $coroutineName = $this->name('mysql', $coroutineName, true);
if (!Context::hasContext('begin_' . $coroutineName)) { if (!Context::hasContext('begin_' . $coroutineName)) {
Context::setContext('begin_' . $coroutineName, 0); Context::setContext('begin_' . $coroutineName, 0);
} }
Context::increment('begin_' . $coroutineName); Context::increment('begin_' . $coroutineName);
if (!Context::getContext('begin_' . $coroutineName) !== 0) { if (!Context::getContext('begin_' . $coroutineName) !== 0) {
return; return;
} }
$connection = Context::getContext($coroutineName); $connection = Context::getContext($coroutineName);
if ($connection instanceof PDO && !$connection->inTransaction()) { if ($connection instanceof PDO && !$connection->inTransaction()) {
$connection->beginTransaction(); $connection->beginTransaction();
} }
} }
/** /**
* @param $coroutineName * @param $coroutineName
*/ */
public function commit($coroutineName) public function commit($coroutineName)
{ {
$coroutineName = $this->name('mysql', $coroutineName, true); $coroutineName = $this->name('mysql', $coroutineName, true);
if (!Context::hasContext('begin_' . $coroutineName)) { if (!Context::hasContext('begin_' . $coroutineName)) {
return; return;
} }
if (Context::decrement('begin_' . $coroutineName) > 0) { if (Context::decrement('begin_' . $coroutineName) > 0) {
return; return;
} }
$connection = Context::getContext($coroutineName); $connection = Context::getContext($coroutineName);
if (!($connection instanceof PDO)) { if (!($connection instanceof PDO)) {
return; return;
} }
Context::setContext('begin_' . $coroutineName, 0); Context::setContext('begin_' . $coroutineName, 0);
if ($connection->inTransaction()) { if ($connection->inTransaction()) {
$connection->commit(); $connection->commit();
} }
} }
/** /**
* @param $name * @param $name
* @param false $isMaster * @param false $isMaster
* @return array * @return array
*/ */
private function getIndex($name, $isMaster = false): array private function getIndex($name, $isMaster = false): array
{ {
return [Coroutine::getCid(), $this->name('mysql', $name, $isMaster)]; return [Coroutine::getCid(), $this->name('mysql', $name, $isMaster)];
} }
/** /**
* @param $coroutineName * @param $coroutineName
*/ */
public function rollback($coroutineName) public function rollback($coroutineName)
{ {
$coroutineName = $this->name('mysql', $coroutineName, true); $coroutineName = $this->name('mysql', $coroutineName, true);
if (!Context::hasContext('begin_' . $coroutineName)) { if (!Context::hasContext('begin_' . $coroutineName)) {
return; return;
} }
if (Context::decrement('begin_' . $coroutineName) > 0) { if (Context::decrement('begin_' . $coroutineName) > 0) {
return; return;
} }
if (($connection = Context::getContext($coroutineName)) instanceof PDO) { if (($connection = Context::getContext($coroutineName)) instanceof PDO) {
if ($connection->inTransaction()) { if ($connection->inTransaction()) {
$connection->rollBack(); $connection->rollBack();
} }
} }
Context::setContext('begin_' . $coroutineName, 0); Context::setContext('begin_' . $coroutineName, 0);
} }
/** /**
* @param mixed $config * @param mixed $config
* @param bool $isMaster * @param bool $isMaster
* @return mixed * @return mixed
* @throws Exception * @throws Exception
*/ */
public function get(mixed $config, $isMaster = false): mixed public function get(mixed $config, $isMaster = false): mixed
{ {
$coroutineName = $this->name('mysql', $config['cds'], $isMaster); $coroutineName = $this->name('mysql', $config['cds'], $isMaster);
if (($pdo = Context::getContext($coroutineName)) instanceof PDO) { if (($pdo = Context::getContext($coroutineName)) instanceof PDO) {
return $pdo; return $pdo;
} }
$connections = $this->getFromChannel($coroutineName, $config); $connections = $this->getFromChannel($coroutineName, $config);
if ($number = Context::getContext('begin_' . $coroutineName, Coroutine::getCid())) { if ($number = Context::getContext('begin_' . $coroutineName, Coroutine::getCid())) {
$number > 0 && $connections->beginTransaction(); $number > 0 && $connections->beginTransaction();
} }
return Context::setContext($coroutineName, $connections); return Context::setContext($coroutineName, $connections);
} }
/** /**
* @param string $name * @param string $name
* @param mixed $config * @param mixed $config
* @return PDO * @return PDO
* @throws Exception * @throws Exception
*/ */
public function createClient(string $name, mixed $config): PDO public function createClient(string $name, mixed $config): PDO
{ {
$link = new PDO($config['cds'], $config['username'], $config['password'], [ $link = new PDO($config['cds'], $config['username'], $config['password'], [
PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_CASE => PDO::CASE_NATURAL, PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_TIMEOUT => $this->timeout, PDO::ATTR_TIMEOUT => $this->timeout,
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . ($config['charset'] ?? 'utf8mb4') PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
]); PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ' . ($config['charset'] ?? 'utf8mb4')
$link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); ]);
$link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); $link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$link->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING); $link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
return $link; $link->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_EMPTY_STRING);
} return $link;
}
/** /**
* @param $coroutineName * @param $coroutineName
* @param $isMaster * @param $isMaster
* @throws Exception * @throws Exception
*/ */
public function release($coroutineName, $isMaster) public function release($coroutineName, $isMaster)
{ {
$coroutineName = $this->name('mysql', $coroutineName, $isMaster); $coroutineName = $this->name('mysql', $coroutineName, $isMaster);
/** @var PDO $client */ /** @var PDO $client */
if (!($client = Context::getContext($coroutineName)) instanceof PDO) { if (!($client = Context::getContext($coroutineName)) instanceof PDO) {
return; return;
} }
if ($client->inTransaction()) { if ($client->inTransaction()) {
$client->commit(); $client->commit();
} }
$this->push($coroutineName, $client); $this->push($coroutineName, $client);
$this->lastTime = time(); $this->lastTime = time();
} }
/** /**
* @param $coroutineName * @param $coroutineName
* @return bool * @return bool
*/ */
private function hasClient($coroutineName): bool private function hasClient($coroutineName): bool
{ {
return Context::hasContext($coroutineName); return Context::hasContext($coroutineName);
} }
/** /**
* batch release * batch release
* @throws Exception * @throws Exception
*/ */
public function connection_clear() public function connection_clear()
{ {
$this->flush(0); $this->flush(0);
} }
/** /**
* @param string $name * @param string $name
* @param mixed $client * @param mixed $client
* @return bool * @return bool
* @throws Exception * @throws Exception
*/ */
public function checkCanUse(string $name, mixed $client): bool public function checkCanUse(string $name, mixed $client): bool
{ {
try { try {
if (empty($client) || !($client instanceof PDO)) { if (empty($client) || !($client instanceof PDO)) {
$result = false; $result = false;
} else { } else {
$result = true; $result = true;
} }
} catch (Error | Throwable $exception) { } catch (Error | Throwable $exception) {
$result = $this->addError($exception, 'mysql'); $result = $this->addError($exception, 'mysql');
} finally { } finally {
if (!$result) { if (!$result) {
$this->decrement($name); $this->decrement($name);
} }
return $result; return $result;
} }
} }
/** /**
* @param $coroutineName * @param $coroutineName
* @param bool $isMaster * @param bool $isMaster
* @throws Exception * @throws Exception
*/ */
public function disconnect($coroutineName, $isMaster = false) public function disconnect($coroutineName, $isMaster = false)
{ {
$coroutineName = $this->name($coroutineName, $isMaster); $coroutineName = $this->name($coroutineName, $isMaster);
$this->clean($coroutineName); $this->clean($coroutineName);
} }
} }