Problem/Motivation
Drupal\Core\Extension\ExtensionList::getPathnames() attempts to store and retrieve path names in both cache and state values; however, it does so inconsitently. If the cache value is cleared, then the state value will be returned. Clearing cache will have no affect.
Here's a human-reabable version of the logic:
- Does a cache value exist?
- If yes, then return the cache value.
- Else, does a state value exist?
- If yes, then return the state value.
- If no, then recalculate path names
- Save recalculated path names to cache and state.
- Return recalculated path names
Here's the code in question:
/**
* Returns a list of extension file paths keyed by machine name.
*
* @return string[]
*/
public function getPathnames() {
if ($this->pathNames === NULL) {
$cache_id = $this->getPathnamesCacheId();
if ($cache = $this->cache->get($cache_id)) {
$path_names = $cache->data;
}
// We use $file_names below.
elseif (!$path_names = $this->state->get($cache_id)) {
$path_names = $this->recalculatePathnames();
// Store filenames to allow static::getPathname() to retrieve them
// without having to rebuild or scan the filesystem.
$this->state->set($cache_id, $path_names);
$this->cache->set($cache_id, $path_names);
}
$this->pathNames = $path_names;
}
return $this->pathNames;
}
Cache vs state is discussed in #2208429: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList where this code originated. See below:
#2208429-62: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList by Mile23:
But it should be in the cache, instead. I don't think we have a way to clear state from the UI, and having a filesystem problem and a non-clearable cache is bad news for users.
#2208429-63: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList by almaudoh:
Totally agree it should be in cache, not state, but I guess the main consideration was maintaining BC, since we don't know how many contrib modules out there are using
\Drupal::state()directly to get module info.
#2208429-70: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList by almaudoh:
As a matter of fact, we cannot use State to store extension lists and info because State depends on the system module, and the system module needs module lists for installation -> a circular dependency. So we have no choice but to use cache.
#2208429-88: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList by catch:
That's OK to change in a minor version. Module info happening to be in state isn't part of the public API, per https://www.drupal.org/core/d8-bc-policy
Also what is the situation where the cache will be cleared but the state entry won't be (except for say a memcache eviction)?
#2208429-330: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList by dawehner:
Well yes this was the idea. Avoid disc IO as much as possible.
I'm not sure about this, it means that it will persist past a bin flush. For example what happens if you move a module from modules/custom to modules/contrib?
#2208429-334: Extension System, Part III: ExtensionList, ModuleExtensionList and ProfileExtensionList by dawehner:
Well, in this case
\Drupal\Core\Extension\ExtensionList::resetis called, which removes the state entry. Given that it is totally able to move modules.
Also keep in mind, we do haveset('system.module.files', $files);already in core as it is. We are "just" moving it around basically. Does that makes sense?
Unfortunately, \Drupal\Core\Extension\ExtensionList::reset() is not called in all circumstances.
Proposed resolution
Switch to storing exclusively in cache. (I'm not seeing the benefit of the current behavior. How does it reduce IO?)
Remaining tasks
- Community feedback
- Open an MR and update tests
User interface changes
None.
API changes
None.
Data model changes
None.
Release notes snippet
TBD.
| Comment | File | Size | Author |
|---|---|---|---|
| #7 | 3240928-nr-bot.txt | 150 bytes | needs-review-queue-bot |
Issue fork drupal-3240928
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
chris burge commentedOpened a MR. Let's see what happens with tests.
Comment #7
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #9
mile23Given that state is optionally cached in 10.3+ (and always on in 11.x), if you have a giant collection of modules you're filling up the state table with a list of info files on the file system. This means the state table can then become too large to fit into your caching backend such as memcache.
Relevant CR: https://www.drupal.org/node/3177901
And given that the file system can change, and also that we have no way of emptying the state records for these files, we should only cache the paths and not put them in the state system.
The PR here seems to do the right thing, AFAICT, but needs updating for D11 (and eventual back port to 10.3.x).
I'd tag with 'needs reroll' but I'm not sure whether that's the right tag in the time of gitlab.
Comment #15
nicxvan commentedThis needs some updates for what is mentioned in 9.
What is mentioned in the issue summary no longer describes the code flow.
I'm wondering if we close this and open a new issue targeting what you mentioned @mile23
Comment #17
guptahemant commentedComment #18
guptahemant commentedComment #19
nicxvan commentedWhy is that issue related to this?