@@ -411,36 +411,51 @@ public function setTempDirectory(string $dir): self
411411 private function loadCache (): void
412412 {
413413 $ file = $ this ->getCacheFile ();
414- [$ this ->classes , $ this ->missing ] = @include $ file ; // @ file may not exist
415- if (is_array ($ this ->classes )) {
414+ $ handle = fopen ($ file , 'cb+ ' );
415+ if (!$ handle || !flock ($ handle , LOCK_SH )) {
416+ throw new \RuntimeException ("Unable to create or acquire shared lock on file ' $ file'. " );
417+ }
418+
419+ $ data = include $ file ;
420+ if (is_array ($ data )) {
421+ [$ this ->classes , $ this ->missing ] = $ data ;
416422 return ;
417423 }
418424
419- $ handle = fopen ("$ file.lock " , 'cb+ ' );
420- if (!$ handle || !flock ($ handle , LOCK_EX )) {
421- throw new \RuntimeException ("Unable to create or acquire exclusive lock on file ' $ file.lock'. " );
425+ if (!flock ($ handle , LOCK_EX )) {
426+ throw new \RuntimeException ("Unable to create or acquire exclusive lock on file ' $ file'. " );
422427 }
423428
424- [$ this ->classes , $ this ->missing ] = @include $ file ; // @ file may not exist
425- if (!is_array ($ this ->classes )) {
426- $ this ->rebuild ();
429+ // while waiting for the lock, someone might have already created the cache
430+ if (fstat ($ handle )['size ' ]) {
431+ flock ($ handle , LOCK_SH );
432+ $ data = include $ file ;
433+ if (is_array ($ data )) {
434+ [$ this ->classes , $ this ->missing ] = $ data ;
435+ return ;
436+ }
427437 }
428438
429- flock ( $ handle , LOCK_UN ) ;
430- fclose ( $ handle );
431- @ unlink ( " $ file .lock " ); // @ file may become locked on Windows
439+ $ this -> classes = $ this -> missing = [] ;
440+ $ this -> refreshClasses ( );
441+ $ this -> saveCache ( $ handle );
432442 }
433443
434444
435445 /**
436446 * Writes class list to cache.
437447 */
438- private function saveCache (): void
448+ private function saveCache ($ handle = null ): void
439449 {
440450 $ file = $ this ->getCacheFile ();
451+ $ handle = $ handle ?: fopen ($ file , 'cb+ ' );
452+ if (!$ handle || !flock ($ handle , LOCK_EX )) {
453+ throw new \RuntimeException ("Unable to create or acquire exclusive lock on file ' $ file'. " );
454+ }
455+
441456 $ code = "<?php \nreturn " . var_export ([$ this ->classes , $ this ->missing ], true ) . "; \n" ;
442- if (file_put_contents ( " $ file .tmp " , $ code ) !== strlen ($ code) || ! rename ( " $ file .tmp " , $ file )) {
443- @unlink (" $ file.tmp " ); // @ - file may not exist
457+ if (! ftruncate ( $ handle , 0 ) || fwrite ( $ handle , $ code ) !== strlen ($ code )) {
458+ @unlink ($ file ); // @ - the locked file may not be deleted
444459 throw new \RuntimeException ("Unable to create ' $ file'. " );
445460 }
446461 if (function_exists ('opcache_invalidate ' )) {
0 commit comments