diff --git a/includes/cache.inc b/includes/cache.inc index 590592d..70bbbb0 100644 --- a/includes/cache.inc +++ b/includes/cache.inc @@ -97,55 +97,103 @@ function _views_fetch_plugin_data($type = NULL, $plugin = NULL, $reset = FALSE) */ function _views_discover_default_views($reset = FALSE) { static $cache = NULL; + $lock_name = __FUNCTION__; - if (!isset($cache) || $reset) { + if (!$reset && !isset($cache)) { $index = views_cache_get('views_default_views_index', TRUE); + $rebuild_cache = TRUE; // Retrieve each cached default view - if (!$reset && isset($index->data) && is_array($index->data)) { + if (isset($index->data) && is_array($index->data)) { + $rebuild_cache = FALSE; $cache = array(); foreach ($index->data as $view_name) { - $data = views_cache_get('views_default:' . $view_name, TRUE); - if (isset($data->data) && is_object($data->data)) { - $cache[$view_name] = $data->data; + $cid = 'views_default:' . $view_name; + if ($cached = views_cache_get($cid, TRUE)) { + $cache[$view_name] = $cached->data; + } + else { + // As soon as there is a cache miss on one item, try to acquire a + // lock. + if (!$lock_acquired = lock_acquire($lock_name)) { + lock_wait($lock_name, 2); + // After waiting, try to fetch the default view from cache again. + // If available another process may have rebuilt it, so do not + // attempt to rebuild the cache. + if ($cached = views_cache_get($cid, TRUE)) { + $cache[$view_name] = $cached->data; + } + // If the item is still not in the cache, try to acquire the lock + // again and rebuild the cache. + else { + $lock_acquired = lock_acquire($lock_name); + $rebuild_cache = TRUE; + break; + } + } + // If the lock was acquired, always rebuild the cache. + else { + $rebuild_cache = TRUE; + break; + } } } } - // If missing index, rebuild the cache else { - views_include_default_views(); - $cache = array(); - - foreach (module_implements('views_default_views') as $module) { - $results = call_user_func($module . "_views_default_views"); - if (!empty($results) && is_array($results)) { - foreach($results as $name => $view) { - // Only views with a sufficiently high api version are eligible. - if (!empty($view->api_version) && $view->api_version >= 2) { - // Do not cache dead handlers. - $view->destroy(); - if (!isset($cache[$name])) { - $cache[$name] = $view; - } - else { - watchdog('view', "View name '@name' is already taken", array('@name' => $name), WATCHDOG_ERROR); - } + if (!$lock_acquired = lock_acquire($lock_name)) { + lock_wait($lock_name, 2); + if ($cached = views_cache_get('views_default_views_index', TRUE)) { + // Another process has rebuilt the cache while we waited. Re-run the + // function to avoid a full cache rebuild. + $cache = _views_discover_default_views(); + $rebuild_cache = FALSE; + } + else { + // Continue with the rebuild. + $rebuild_cache = TRUE; + } + } + } + } + if ($reset || $rebuild_cache) { + views_include_default_views(); + $cache = array(); + + foreach(module_implements('views_default_views') as $module) { + $results = call_user_func($module . "_views_default_views"); + if (!empty($results) && is_array($results)) { + foreach($results as $name => $view) { + // Only views with a sufficiently high api version are eligible. + if (!empty($view->api_version) && $view->api_version >= 2) { + // Do not cache dead handlers. + $view->destroy(); + if (!isset($cache[$name])) { + $cache[$name] = $view; + } + else { + watchdog('view', "View name '@name' is already taken", array('@name' => $name), WATCHDOG_ERROR); } } } } + } + + // Allow modules to modify default views before they are cached. + drupal_alter('views_default_views', $cache); - // Allow modules to modify default views before they are cached. - drupal_alter('views_default_views', $cache); + // Only set the cache if we already have a lock, are able to acquire one, or + // if a reset was explicitly requested. - // Cache the index + if (!empty($lock_acquired) || lock_acquire($lock_name) || $reset) { + // Cache the index. $index = array_keys($cache); views_cache_set('views_default_views_index', $index, TRUE); - // Cache each view + // Cache each view. foreach ($cache as $name => $view) { views_cache_set('views_default:' . $name, $view, TRUE); } + lock_release($lock_name); } }