Index: modules/image/image.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/image/image.module,v
retrieving revision 1.7
diff -u -9 -p -r1.7 image.module
--- modules/image/image.module	17 Aug 2009 19:14:40 -0000	1.7
+++ modules/image/image.module	19 Aug 2009 19:09:29 -0000
@@ -434,45 +434,43 @@ function image_style_generate() {
   $destination = image_style_path($style['name'], $path);
 
   // Check that it's a defined style and that access was granted by
   // image_style_url().
   if (!$style || !cache_get('access:' . $style_name . ':' . $path_md5, 'cache_image')) {
     drupal_access_denied();
     exit();
   }
 
-  // Don't start generating the image if it is already in progress.
-  $cid = 'generate:' . $style_name . ':' . $path_md5;
-  if (cache_get($cid, 'cache_image')) {
+  // Don't start generating the image if the derivate already exists or if
+  // generation is in progress in another thread.
+  $lock_name = 'image_style_generate:' . $style_name . ':' . $path_md5;
+  if (!file_exists($destination) && !($lock_acquired = lock_acquire($lock_name))) {
     // Tell client to retry again in 3 seconds. Currently no browsers are known
     // to support Retry-After.
     drupal_set_header('503 Service Unavailable');
     drupal_set_header('Retry-After', 3);
     print t('Image generation in progress, please try again shortly.');
     exit();
   }
 
-  // If the image has already been generated then send it.
-  if ($image = image_load($destination)) {
-    file_transfer($image->source, array('Content-Type' => $image->info['mime_type'], 'Content-Length' => $image->info['file_size']));
-  }
+  // Try to generate the image, unless another thread just did it while we were
+  // acquiring the lock.
+  $success = file_exists($destination) || image_style_create_derivative($style, $path, $destination);
 
-  // Set a cache entry designating this image as being in-process.
-  cache_set($cid, $destination, 'cache_image');
+  if ($lock_acquired) {
+    lock_release($lock_name);
+  }
 
-  // Try to generate the image.
-  if (image_style_create_derivative($style, $path, $destination)) {
+  if ($success) {
     $image = image_load($destination);
-    cache_clear_all($cid, 'cache_image');
     file_transfer($image->source, array('Content-Type' => $image->info['mime_type'], 'Content-Length' => $image->info['file_size']));
   }
   else {
-    cache_clear_all($cid, 'cache_image');
     watchdog('image', 'Unable to generate the derived image located at %path.', $destination);
     drupal_set_header('500 Internal Server Error');
     print t('Error generating image.');
     exit();
   }
 }
 
 /**
  * Create a new image based on an image style.
Index: modules/image/image.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/image/image.test,v
retrieving revision 1.6
diff -u -9 -p -r1.6 image.test
--- modules/image/image.test	17 Aug 2009 19:14:40 -0000	1.6
+++ modules/image/image.test	19 Aug 2009 19:09:29 -0000
@@ -81,33 +81,34 @@ class ImageStylesPathAndUrlUnitTest exte
     $expected_generate_url = url('image/generate/' . $this->style_name . '/' . $this->scheme . '/' . basename($this->image_filepath), array('absolute' => TRUE));
     $this->drupalGet($expected_generate_url);
     $this->assertResponse(403, t('Access to generate URL was denied.'));
 
     // Check that a generate URL is returned.
     $actual_generate_url = image_style_url($this->style_name, $this->image_filepath);
     $this->assertEqual($actual_generate_url, $expected_generate_url, t('Got the generate URL for a non-existent file.'));
 
     // Fetch the URL that generates the file while another process appears to
-    // be generating the same file (this is signaled using cache_image).
-    $cid = 'generate:' . $this->style_name . ':' . md5($this->image_filepath);
-    cache_set($cid, $generated_path, 'cache_image');
+    // be generating the same file (this is signaled using a lock).
+    $lock_name = 'image_style_generate:' . $this->style_name . ':' . md5($this->image_filepath);
+    $this->assertTrue(lock_acquire($lock_name), t('Lock was acquired.'));
     $this->drupalGet($expected_generate_url);
     $this->assertResponse(503, t('Service Unavailable response received.'));
     $this->assertTrue($this->drupalGetHeader('Retry-After'), t('Retry-After header received.'));
-    cache_clear_all($cid, 'cache_image');
+    lock_release($lock_name);
 
     // Fetch the URL that generates the file.
     $this->drupalGet($expected_generate_url);
     $this->assertTrue(file_exists($generated_path), t('Generated file was created.'));
     $this->assertRaw(file_get_contents($generated_path), t('URL returns expected file.'));
     $generated_image_info = image_get_info($generated_path);
     $this->assertEqual($this->drupalGetHeader('Content-Type'), $generated_image_info['mime_type'], t('Expected Content-Type was reported.'));
     $this->assertEqual($this->drupalGetHeader('Content-Length'), $generated_image_info['file_size'], t('Expected Content-Length was reported.'));
+    $this->assertTrue(lock_may_be_available($lock_name), t('Lock was released.'));
 
     // Check that the URL points directly to the generated file.
     $expected_generated_url = file_create_url($generated_path);
     $actual_generated_url = image_style_url($this->style_name, $this->image_filepath);
     $this->drupalGet($expected_generated_url);
     $this->assertEqual($actual_generated_url, $expected_generated_url, t('Got the download URL for an existing file.'));
     $this->assertRaw(file_get_contents($generated_path), t('URL returns expected file.'));
     $this->assertEqual($this->drupalGetHeader('Content-Type'), $this->image_info['mime_type'], t('Expected Content-Type was reported.'));
     $this->assertEqual($this->drupalGetHeader('Content-Length'), $this->image_info['file_size'], t('Expected Content-Length was reported.'));
