Browse Source

Unlock file before relinquishing control.

pull/660/head
Adam Vessey 8 years ago
parent
commit
734c71db54
  1. 33
      includes/datastream.inc

33
includes/datastream.inc

@ -437,6 +437,9 @@ function islandora_view_datastream_deliver_chunks(AbstractDatastream $datastream
/** /**
* Creates/returns the file URI for the content of a datastream for chunking. * Creates/returns the file URI for the content of a datastream for chunking.
* *
* File locks are used to ensure the datastream is completely downloaded before
* attempting to serve up chunks from the file.
*
* @param AbstractDatastream $datastream * @param AbstractDatastream $datastream
* An AbstractDatastream representing a datastream on a Fedora object. * An AbstractDatastream representing a datastream on a Fedora object.
* *
@ -451,16 +454,26 @@ function islandora_view_datastream_retrieve_file_uri(AbstractDatastream $datastr
$file_uri = 'temporary://chunk_' . $datastream->parent->id . '_' . $datastream->id . '_' . $datastream->createdDate->getTimestamp() . '.' . $extension; $file_uri = 'temporary://chunk_' . $datastream->parent->id . '_' . $datastream->id . '_' . $datastream->createdDate->getTimestamp() . '.' . $extension;
touch(drupal_realpath($file_uri)); touch(drupal_realpath($file_uri));
$fp = fopen($file_uri, 'r+b'); $fp = fopen($file_uri, 'r+b');
drupal_register_shutdown_function('fclose', $fp);
if (flock($fp, LOCK_SH)) { if (flock($fp, LOCK_SH)) {
try {
if (feof($fp) && $datastream->size > 0) { if (feof($fp) && $datastream->size > 0) {
// Just opened at beginning of file, if beginning == EOF, need to grab it. // Just opened at beginning of file, if beginning == EOF, need to grab
// it.
if (!flock($fp, LOCK_EX | LOCK_NB)) {
// Hypothetically, two threads could have a "shared" lock with an
// unpopulated file, so to avoid deadlock on the "exclusive" lock,
// drop the "shared" lock before blocking to obtain the "exclusive"
// lock.
flock($fp, LOCK_UN);
}
if (flock($fp, LOCK_EX)) { if (flock($fp, LOCK_EX)) {
// Upgrade to exclusive lock, write file. // Get exclusive lock, write file.
$file = islandora_temp_file_entry($file_uri, $datastream->mimeType); $file = islandora_temp_file_entry($file_uri, $datastream->mimeType);
if ($file->filesize == $datastream->size) { if ($file->filesize == $datastream->size) {
// Populated in another thread; downgrade lock and return. // Populated in another thread while we were waiting for the
flock($fp, LOCK_SH); // "exclusive" lock; drop lock and return.
flock($fp, LOCK_UN);
fclose($fp);
return $file_uri; return $file_uri;
} }
@ -473,8 +486,6 @@ function islandora_view_datastream_retrieve_file_uri(AbstractDatastream $datastr
'@actual' => $datastream->size, '@actual' => $datastream->size,
))); )));
} }
// Downgrade to shared lock.
flock($fp, LOCK_SH);
} }
catch (RepositoryException $e) { catch (RepositoryException $e) {
file_delete($file); file_delete($file);
@ -488,8 +499,16 @@ function islandora_view_datastream_retrieve_file_uri(AbstractDatastream $datastr
))); )));
} }
} }
flock($fp, LOCK_UN);
fclose($fp);
return $file_uri; return $file_uri;
} }
catch (Exception $e) {
flock($fp, LOCK_UN);
fclose($fp);
throw $e;
}
}
throw new Exception(t('Failed to acquire shared lock when chunking @pid/@dsid.', array( throw new Exception(t('Failed to acquire shared lock when chunking @pid/@dsid.', array(
'@pid' => $datastream->parent->id, '@pid' => $datastream->parent->id,
'@dsid' => $datastream->id, '@dsid' => $datastream->id,

Loading…
Cancel
Save