Skip to content

Commit

Permalink
Merge pull request #9261 from Toflar/pooloptimizer
Browse files Browse the repository at this point in the history
Implemented PoolOptimizer
  • Loading branch information
Seldaek committed Nov 11, 2021
2 parents 7eca450 + c06be08 commit 4589b9b
Show file tree
Hide file tree
Showing 32 changed files with 1,728 additions and 66 deletions.
1 change: 0 additions & 1 deletion .github/workflows/continuous-integration.yml
Expand Up @@ -11,7 +11,6 @@ on:
env:
COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist"
COMPOSER_UPDATE_FLAGS: ""
COMPOSER_TESTS_ARE_RUNNING: "1"

jobs:
tests:
Expand Down
24 changes: 24 additions & 0 deletions doc/articles/troubleshooting.md
Expand Up @@ -353,3 +353,27 @@ See also https://github.com/composer/composer/issues/4180 for more information.
Composer can unpack zipballs using either a system-provided `unzip` or `7z` (7-Zip) utility, or PHP's
native `ZipArchive` class. On OSes where ZIP files can contain permissions and symlinks, we recommend
installing `unzip` or `7z` as these features are not supported by `ZipArchive`.


## Disabling the pool optimizer

In Composer, the `Pool` class contains all the packages that are relevant for the dependency
resolving process. That is what is used to generate all the rules which are then
passed on to the dependency solver.
In order to improve performance, Composer tries to optimize this `Pool` by removing useless
package information early on.

If all goes well, you should never notice any issues with it but in case you run into
an unexpected result such as an unresolvable set of dependencies or conflicts where you
think Composer is wrong, you might want to disable the optimizer by using the environment
variable `COMPOSER_POOL_OPTIMIZER` and run the update again like so:

```bash
COMPOSER_POOL_OPTIMIZER=0 php composer.phar update
```

Now double check if the result is still the same. It will take significantly longer and use
a lot more memory to run the dependency resolving process.

If the result is different, you likely hit a problem in the pool optimizer.
Please [report this issue](https://github.com/composer/composer/issues) so it can be fixed.
51 changes: 50 additions & 1 deletion src/Composer/DependencyResolver/Pool.php
Expand Up @@ -36,16 +36,57 @@ class Pool implements \Countable
protected $providerCache = array();
/** @var BasePackage[] */
protected $unacceptableFixedOrLockedPackages;
/** @var array<string, array<string, string>> Map of package name => normalized version => pretty version */
protected $removedVersions = array();
/** @var array<string, array<string, string>> Map of package object hash => removed normalized versions => removed pretty version */
protected $removedVersionsByPackage = array();

/**
* @param BasePackage[] $packages
* @param BasePackage[] $unacceptableFixedOrLockedPackages
* @param array<string, array<string, string>> $removedVersions
* @param array<string, array<string, string>> $removedVersionsByPackage
*/
public function __construct(array $packages = array(), array $unacceptableFixedOrLockedPackages = array())
public function __construct(array $packages = array(), array $unacceptableFixedOrLockedPackages = array(), array $removedVersions = array(), array $removedVersionsByPackage = array())
{
$this->versionParser = new VersionParser;
$this->setPackages($packages);
$this->unacceptableFixedOrLockedPackages = $unacceptableFixedOrLockedPackages;
$this->removedVersions = $removedVersions;
$this->removedVersionsByPackage = $removedVersionsByPackage;
}

/**
* @param string $name
* @return array<string, string>
*/
public function getRemovedVersions($name, ConstraintInterface $constraint)
{
if (!isset($this->removedVersions[$name])) {
return array();
}

$result = array();
foreach ($this->removedVersions[$name] as $version => $prettyVersion) {
if ($constraint->matches(new Constraint('==', $version))) {
$result[$version] = $prettyVersion;
}
}

return $result;
}

/**
* @param string $objectHash
* @return array<string, string>
*/
public function getRemovedVersionsByPackage($objectHash)
{
if (!isset($this->removedVersionsByPackage[$objectHash])) {
return array();
}

return $this->removedVersionsByPackage[$objectHash];
}

/**
Expand Down Expand Up @@ -221,6 +262,14 @@ public function isUnacceptableFixedOrLockedPackage(BasePackage $package)
return \in_array($package, $this->unacceptableFixedOrLockedPackages, true);
}

/**
* @return BasePackage[]
*/
public function getUnacceptableFixedOrLockedPackages()
{
return $this->unacceptableFixedOrLockedPackages;
}

public function __toString()
{
$str = "Pool:\n";
Expand Down
38 changes: 37 additions & 1 deletion src/Composer/DependencyResolver/PoolBuilder.php
Expand Up @@ -61,6 +61,10 @@ class PoolBuilder
* @var ?EventDispatcher
*/
private $eventDispatcher;
/**
* @var PoolOptimizer|null
*/
private $poolOptimizer;
/**
* @var IOInterface
*/
Expand Down Expand Up @@ -128,13 +132,14 @@ class PoolBuilder
* @param string[] $rootReferences an array of package name => source reference
* @phpstan-param array<string, string> $rootReferences
*/
public function __construct(array $acceptableStabilities, array $stabilityFlags, array $rootAliases, array $rootReferences, IOInterface $io, EventDispatcher $eventDispatcher = null)
public function __construct(array $acceptableStabilities, array $stabilityFlags, array $rootAliases, array $rootReferences, IOInterface $io, EventDispatcher $eventDispatcher = null, PoolOptimizer $poolOptimizer = null)
{
$this->acceptableStabilities = $acceptableStabilities;
$this->stabilityFlags = $stabilityFlags;
$this->rootAliases = $rootAliases;
$this->rootReferences = $rootReferences;
$this->eventDispatcher = $eventDispatcher;
$this->poolOptimizer = $poolOptimizer;
$this->io = $io;
}

Expand Down Expand Up @@ -259,6 +264,8 @@ public function buildPool(array $repositories, Request $request)
$this->skippedLoad = array();
$this->indexCounter = 0;

$pool = $this->runOptimizer($request, $pool);

Intervals::clear();

return $pool;
Expand Down Expand Up @@ -572,4 +579,33 @@ private function removeLoadedPackage(Request $request, BasePackage $package, $in
unset($this->aliasMap[spl_object_hash($package)]);
}
}

/**
* @return Pool
*/
private function runOptimizer(Request $request, Pool $pool)
{
if (null === $this->poolOptimizer) {
return $pool;
}

$total = \count($pool->getPackages());

$pool = $this->poolOptimizer->optimize($request, $pool);

$filtered = $total - \count($pool->getPackages());

if (0 === $filtered) {
return $pool;
}

$this->io->write(sprintf(
'<info>Found %s package versions referenced in your dependency graph. %s (%d%%) were optimized away.</info>',
number_format($total),
number_format($filtered),
round(100/$total*$filtered)
), true, IOInterface::VERY_VERBOSE);

return $pool;
}
}

0 comments on commit 4589b9b

Please sign in to comment.