forked from open-telemetry/opentelemetry-php
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve fiber bound context storage (open-telemetry#1270)
* Improve fiber bound context storage Now works properly in fibers once initial context is attached. * Change `Context::storage()` return type to `ContextStorageInterface` `ExecutionContextAwareInterface` should not be relevant for end-users / it was mainly exposed for the FFI fiber handler; calling any of its method with enabled fiber handler would have broken the storage. Swoole context storage README creates a new storage instead of wrapping `Context::storage()`: `Context::setStorage(new SwooleContextStorage(new ContextStorage()));`. * Add BC layer for execution context aware fiber storage * Fix BC layer inactive execution context detection for {main}
- Loading branch information
Showing
16 changed files
with
303 additions
and
149 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\Context; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
interface ContextStorageHeadAware | ||
{ | ||
public function head(): ?ContextStorageHead; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,79 @@ | ||
<?php | ||
|
||
/** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\Context; | ||
|
||
use function assert; | ||
use function class_exists; | ||
use const E_USER_WARNING; | ||
use Fiber; | ||
use function spl_object_id; | ||
use function sprintf; | ||
use function trigger_error; | ||
use WeakMap; | ||
|
||
/** | ||
* @internal | ||
* | ||
* @phan-file-suppress PhanUndeclaredClassReference | ||
* @phan-file-suppress PhanUndeclaredClassMethod | ||
*/ | ||
final class FiberBoundContextStorage implements ContextStorageInterface, ExecutionContextAwareInterface | ||
final class FiberBoundContextStorage implements ContextStorageInterface, ContextStorageHeadAware | ||
{ | ||
public function __construct(private readonly ContextStorageInterface&ExecutionContextAwareInterface $storage) | ||
{ | ||
} | ||
|
||
public function fork(int|string $id): void | ||
{ | ||
$this->storage->fork($id); | ||
} | ||
/** @var WeakMap<object, ContextStorageHead> */ | ||
private WeakMap $heads; | ||
|
||
public function switch(int|string $id): void | ||
public function __construct() | ||
{ | ||
$this->storage->switch($id); | ||
$this->heads = new WeakMap(); | ||
$this->heads[$this] = new ContextStorageHead($this); | ||
} | ||
|
||
public function destroy(int|string $id): void | ||
public function head(): ?ContextStorageHead | ||
{ | ||
$this->storage->destroy($id); | ||
return $this->heads[Fiber::getCurrent() ?? $this] ?? null; | ||
} | ||
|
||
public function scope(): ?ContextStorageScopeInterface | ||
{ | ||
$this->checkFiberMismatch(); | ||
$head = $this->heads[Fiber::getCurrent() ?? $this] ?? null; | ||
|
||
if (!$head?->node && Fiber::getCurrent()) { | ||
self::triggerNotInitializedFiberContextWarning(); | ||
|
||
if (($scope = $this->storage->scope()) === null) { | ||
return null; | ||
} | ||
|
||
return new FiberBoundContextStorageScope($scope); | ||
// Starts with empty head instead of cloned parent -> no need to check for head mismatch | ||
return $head->node; | ||
} | ||
|
||
public function current(): ContextInterface | ||
{ | ||
$this->checkFiberMismatch(); | ||
$head = $this->heads[Fiber::getCurrent() ?? $this] ?? null; | ||
|
||
if (!$head?->node && Fiber::getCurrent()) { | ||
self::triggerNotInitializedFiberContextWarning(); | ||
|
||
// Fallback to {main} to preserve BC | ||
$head = $this->heads[$this]; | ||
} | ||
|
||
return $this->storage->current(); | ||
return $head->node->context ?? Context::getRoot(); | ||
} | ||
|
||
public function attach(ContextInterface $context): ContextStorageScopeInterface | ||
{ | ||
$scope = $this->storage->attach($context); | ||
assert(class_exists(Fiber::class, false)); | ||
$scope[Fiber::class] = Fiber::getCurrent(); | ||
$head = $this->heads[Fiber::getCurrent() ?? $this] ??= new ContextStorageHead($this); | ||
|
||
return new FiberBoundContextStorageScope($scope); | ||
return $head->node = new ContextStorageNode($context, $head, $head->node); | ||
} | ||
|
||
private function checkFiberMismatch(): void | ||
private static function triggerNotInitializedFiberContextWarning(): void | ||
{ | ||
$scope = $this->storage->scope(); | ||
assert(class_exists(Fiber::class, false)); | ||
if ($scope && $scope[Fiber::class] !== Fiber::getCurrent()) { | ||
trigger_error('Fiber context switching not supported', E_USER_WARNING); | ||
} | ||
$fiber = Fiber::getCurrent(); | ||
assert($fiber !== null); | ||
|
||
trigger_error(sprintf( | ||
'Access to not initialized OpenTelemetry context in fiber (id: %d), automatic forking not supported, must attach initial fiber context manually', | ||
spl_object_id($fiber), | ||
), E_USER_WARNING); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace OpenTelemetry\Context; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
final class FiberBoundContextStorageExecutionAwareBC implements ContextStorageInterface, ExecutionContextAwareInterface | ||
{ | ||
private readonly FiberBoundContextStorage $storage; | ||
private ?ContextStorage $bc = null; | ||
|
||
public function __construct() | ||
{ | ||
$this->storage = new FiberBoundContextStorage(); | ||
} | ||
|
||
public function fork(int|string $id): void | ||
{ | ||
$this->bcStorage()->fork($id); | ||
} | ||
|
||
public function switch(int|string $id): void | ||
{ | ||
$this->bcStorage()->switch($id); | ||
} | ||
|
||
public function destroy(int|string $id): void | ||
{ | ||
$this->bcStorage()->destroy($id); | ||
} | ||
|
||
private function bcStorage(): ContextStorage | ||
{ | ||
if ($this->bc === null) { | ||
$this->bc = new ContextStorage(); | ||
|
||
// Copy head into $this->bc storage to preserve already attached scopes | ||
/** @psalm-suppress PossiblyNullFunctionCall */ | ||
$head = (static fn ($storage) => $storage->heads[$storage]) | ||
->bindTo(null, FiberBoundContextStorage::class)($this->storage); | ||
$head->storage = $this->bc; | ||
|
||
/** @psalm-suppress PossiblyNullFunctionCall */ | ||
(static fn ($storage) => $storage->current = $storage->main = $head) | ||
->bindTo(null, ContextStorage::class)($this->bc); | ||
} | ||
|
||
return $this->bc; | ||
} | ||
|
||
public function scope(): ?ContextStorageScopeInterface | ||
{ | ||
return $this->bc | ||
? $this->bc->scope() | ||
: $this->storage->scope(); | ||
} | ||
|
||
public function current(): ContextInterface | ||
{ | ||
return $this->bc | ||
? $this->bc->current() | ||
: $this->storage->current(); | ||
} | ||
|
||
public function attach(ContextInterface $context): ContextStorageScopeInterface | ||
{ | ||
return $this->bc | ||
? $this->bc->attach($context) | ||
: $this->storage->attach($context); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.