mkdir() race condition in cache warmers
andrey-tech opened this issue · 1 comments
andrey-tech commented
DoctrineMongoDBBundle version(s) affected
3.5.3, up to 4.6.x
Description
The race condition is appears when several processes are attempting to create a same Doctrine Proxy/Hydrator directory which does not yet exist and \RuntimeException
is thrown:
\Doctrine\Bundle\MongoDBBundle\CacheWarmer\ProxyCacheWarmer
50 if (!file_exists($proxyCacheDir)) {
51 if (false === @mkdir($proxyCacheDir, 0775, true)) {
52 throw new \RuntimeException(sprintf('Unable to create the Doctrine Proxy directory (%s)', dirname($proxyCacheDir)));
53 }
\Doctrine\Bundle\MongoDBBundle\CacheWarmer\PersistentCollectionCacheWarmer
47 if (! file_exists($collCacheDir)) {
48 if (false === @mkdir($collCacheDir, 0775, true)) {
49 throw new \RuntimeException(sprintf('Unable to create the Doctrine persistent collection directory (%s)', dirname($collCacheDir)));
50 }
\Doctrine\Bundle\MongoDBBundle\CacheWarmer\HydratorCacheWarmer
48 if (!file_exists($hydratorCacheDir)) {
49 if (false === @mkdir($hydratorCacheDir, 0775, true)) {
50 throw new \RuntimeException(sprintf('Unable to create the Doctrine Hydrator directory (%s)', dirname($hydratorCacheDir)));
51 }
\Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\CreateProxyDirectoryPass
22 if (!is_dir($proxyCacheDir)) {
23 if (false === @mkdir($proxyCacheDir, 0775, true)) {
24 exit(sprintf('Unable to create the Doctrine Proxy directory (%s)', dirname($proxyCacheDir)));
25 }
\Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\CreateHydratorDirectoryPass
22 if (!is_dir($hydratorCacheDir)) {
23 if (false === @mkdir($hydratorCacheDir, 0775, true)) {
24 exit(sprintf('Unable to create the Doctrine Hydrator directory (%s)', dirname($hydratorCacheDir)));
25 }
How to reproduce
This issue is difficult to reproduce, as any concurrency-related issues are. It appears when several processes are attempting to create a directory which does not yet exist. Specifically, when one process is between !file_exists()
and @mkdir()
after another process has already managed to create the directory.
Possible Solution
Add an extra check !file_exists()
. Example:
\Doctrine\Bundle\MongoDBBundle\CacheWarmer\ProxyCacheWarmer
50 if (!file_exists($proxyCacheDir)) {
51 if (false === @mkdir($proxyCacheDir, 0775, true) && !file_exists($proxyCacheDir)) {
52 throw new \RuntimeException(sprintf('Unable to create the Doctrine Proxy directory (%s)', dirname($proxyCacheDir)));
53 }
Additional Context
Same problem in symfony/symfony already was fixed - see issue #47489.