diff --git a/cache/classes/loaders.php b/cache/classes/loaders.php index ebc23edd367..3893e92e864 100644 --- a/cache/classes/loaders.php +++ b/cache/classes/loaders.php @@ -621,11 +621,11 @@ class cache implements cache_loader { // store; parent method will have set it to all stores if needed. if ($setaftervalidation) { $lock = false; + try { if (!empty($this->requirelockingbeforewrite) && !$this->check_lock_state($key)) { $this->acquire_lock($key); $lock = true; } - try { if ($requiredversion === self::VERSION_NONE) { $this->set_implementation($key, self::VERSION_NONE, $result, false); } else { @@ -744,11 +744,11 @@ class cache implements cache_loader { foreach ($resultmissing as $key => $value) { $result[$keysparsed[$key]] = $value; $lock = false; + try { if (!empty($this->requirelockingbeforewrite)) { $this->acquire_lock($key); $lock = true; } - try { if ($value !== false) { $this->set($key, $value); } @@ -1683,8 +1683,12 @@ class cache_application extends cache implements cache_loader_with_locking { * @throws moodle_exception If the lock cannot be obtained */ public function acquire_lock($key) { + $releaseparent = false; + try { if ($this->get_loader() !== false) { $this->get_loader()->acquire_lock($key); + // If something goes wrong we should release the parent. + $releaseparent = true; } $key = cache_helper::hash_key($key, $this->get_definition()); $before = microtime(true); @@ -1701,11 +1705,18 @@ class cache_application extends cache implements cache_loader_with_locking { \core\lock\timing_wrapper_lock_factory::record_lock_data($after, $before, $this->get_definition()->get_id(), $key, $lock, $this->get_identifier() . $key); } + $releaseparent = false; return true; } else { throw new moodle_exception('ex_unabletolock', 'cache', '', null, 'store: ' . get_class($this->get_store()) . ', lock: ' . $key); } + } finally { + // Release the parent lock if we acquired it, then threw an exception. + if ($releaseparent) { + $this->get_loader()->release_lock($key); + } + } } /**