-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Performance optimizations and caching (#698)
* Combine addTypeNamespace() and addControllerNamespace() into addNamespace() * Refactor CachedDocBlockFactory to use existing caching infrastructure * Refactor field name * Refactor code to use ClassFinder instead of separating namespaces * Make caches only recompute on file changes * Refactor EnumTypeMapper to use cached doc block factory * Fix FileModificationClassFinderBoundCache * Use Kcs ClassFinder cache * One more tiny optimization for unchanged cache * Change name of ClassFinderBoundCache * Code style * PHPStan * Some fixes and renames * Fix broken class bound cache after merge * Fix some tests and PHPStan * Fix all failing tests * Fix one failing test on CI * Fix one failing test on CI, again * Fix --prefer-lowest tests * Some simplifications and tests * Simplify cached doc blocks * Simplify cached doc blocks * More tests for doc block factories * Tests for the Discovery namespace * Fix the docs build on CI and broken links * Add a changelog entry * Deprecate setGlobTTL() instead of removing it * Code style
- Loading branch information
1 parent
069d62a
commit 592568c
Showing
72 changed files
with
1,700 additions
and
1,415 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
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,24 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace TheCodingMachine\GraphQLite\Cache; | ||
|
||
use ReflectionClass; | ||
|
||
interface ClassBoundCache | ||
{ | ||
/** | ||
* @param callable(): TReturn $resolver | ||
* | ||
* @return TReturn | ||
* | ||
* @template TReturn | ||
*/ | ||
public function get( | ||
ReflectionClass $reflectionClass, | ||
callable $resolver, | ||
string $key, | ||
bool $withInheritance = false, | ||
): mixed; | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace TheCodingMachine\GraphQLite\Cache; | ||
|
||
use ReflectionClass; | ||
|
||
use function array_unique; | ||
use function Safe\filemtime; | ||
|
||
class FilesSnapshot | ||
{ | ||
/** @param array<string, int> $dependencies */ | ||
private function __construct( | ||
private readonly array $dependencies, | ||
) | ||
{ | ||
} | ||
|
||
/** @param list<string> $files */ | ||
public static function for(array $files): self | ||
{ | ||
$dependencies = []; | ||
|
||
foreach (array_unique($files) as $file) { | ||
$dependencies[$file] = filemtime($file); | ||
} | ||
|
||
return new self($dependencies); | ||
} | ||
|
||
public static function forClass(ReflectionClass $class, bool $withInheritance = false): self | ||
{ | ||
return self::for( | ||
self::dependencies($class, $withInheritance), | ||
); | ||
} | ||
|
||
public static function alwaysUnchanged(): self | ||
{ | ||
return new self([]); | ||
} | ||
|
||
/** @return list<string> */ | ||
private static function dependencies(ReflectionClass $class, bool $withInheritance = false): array | ||
{ | ||
$filename = $class->getFileName(); | ||
|
||
// Internal classes are treated as always the same, e.g. you'll have to drop the cache between PHP versions. | ||
if ($filename === false) { | ||
return []; | ||
} | ||
|
||
$files = [$filename]; | ||
|
||
if (! $withInheritance) { | ||
return $files; | ||
} | ||
|
||
if ($class->getParentClass() !== false) { | ||
$files = [...$files, ...self::dependencies($class->getParentClass(), $withInheritance)]; | ||
} | ||
|
||
foreach ($class->getTraits() as $trait) { | ||
$files = [...$files, ...self::dependencies($trait, $withInheritance)]; | ||
} | ||
|
||
foreach ($class->getInterfaces() as $interface) { | ||
$files = [...$files, ...self::dependencies($interface, $withInheritance)]; | ||
} | ||
|
||
return $files; | ||
} | ||
|
||
public function changed(): bool | ||
{ | ||
foreach ($this->dependencies as $filename => $modificationTime) { | ||
if ($modificationTime !== filemtime($filename)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
} |
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,41 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace TheCodingMachine\GraphQLite\Cache; | ||
|
||
use Psr\SimpleCache\CacheInterface; | ||
use ReflectionClass; | ||
|
||
use function str_replace; | ||
|
||
class SnapshotClassBoundCache implements ClassBoundCache | ||
{ | ||
/** @param callable(ReflectionClass, bool $withInheritance): FilesSnapshot $filesSnapshotFactory */ | ||
public function __construct( | ||
private readonly CacheInterface $cache, | ||
private readonly mixed $filesSnapshotFactory, | ||
) { | ||
} | ||
|
||
public function get(ReflectionClass $reflectionClass, callable $resolver, string $key = '', bool $withInheritance = false): mixed | ||
{ | ||
$cacheKey = $reflectionClass->getName() . '__' . $key; | ||
$cacheKey = str_replace(['\\', '{', '}', '(', ')', '/', '@', ':'], '_', $cacheKey); | ||
|
||
$item = $this->cache->get($cacheKey); | ||
|
||
if ($item !== null && ! $item['snapshot']->changed()) { | ||
return $item['data']; | ||
} | ||
|
||
$item = [ | ||
'data' => $resolver(), | ||
'snapshot' => ($this->filesSnapshotFactory)($reflectionClass, $withInheritance), | ||
]; | ||
|
||
$this->cache->set($cacheKey, $item); | ||
|
||
return $item['data']; | ||
} | ||
} |
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,41 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace TheCodingMachine\GraphQLite\Discovery\Cache; | ||
|
||
use ReflectionClass; | ||
use TheCodingMachine\GraphQLite\Discovery\ClassFinder; | ||
|
||
/** | ||
* Cache that computes a final value based on class that exist in the application found with | ||
* the {@see ClassFinder}, and one that allows invalidating only parts of the cache when those | ||
* classes change, instead of having to invalidate the whole cache on every change. | ||
*/ | ||
interface ClassFinderComputedCache | ||
{ | ||
/** | ||
* Compute the value of the cache. The $finder and $key are self-explanatory; the $map and $reduce need | ||
* a bit of an explanation: $map is called with each reflection found by $finder, and expects any value to be returned. | ||
* It will then be stored in a Map<string (filename), TEntry (return from $map)>. Once all classes are iterated, | ||
* $reduce will then be called with that map, and it's final result is returned. | ||
* | ||
* Now the point of this is now whenever file A changes, we can automatically remove entries generated for it | ||
* and simply call $map only for classes from file A, leaving all other entries untouched and not having to | ||
* waste resources on the rest of them. We then only need to call the cheap $reduce and have the final result :) | ||
* | ||
* @param callable(ReflectionClass<object>): TEntry $map | ||
* @param callable(array<string, TEntry>): TReturn $reduce | ||
* | ||
* @return TReturn | ||
* | ||
* @template TEntry of mixed | ||
* @template TReturn of mixed | ||
*/ | ||
public function compute( | ||
ClassFinder $classFinder, | ||
string $key, | ||
callable $map, | ||
callable $reduce, | ||
): mixed; | ||
} |
Oops, something went wrong.