refactor: store article and category meta cache in separate files - #6675
Merged
Merged
Conversation
Since categories live in their own tables, the shared flat cache row is the last place that mixes both entities. It forced the `art_`/`cat_` prefixes to act as a separator, explicit `catname`/`catpriority`/`catcreatedate` aliases for the colliding core columns, and a hardcoded core-column blocklist in `categoryMetaColumns()` to pick up the remaining category columns. The cache now holds one file per entity and language, `<id>.<lang>.article` and `<id>.<lang>.category`, the latter only for start articles. Both are read through the new `cacheFileSuffix()`, so `Category::fromCache()` no longer needs the `startarticle` check: a missing file means "not a category". `parent_id`, `path` and `status` belong to the start article and are copied into the category file so a category can be built from its own file alone. This also stops `Category::get()` from deserializing the full article payload (including every `art_` meta field) only to discard it, which happens once per element in category-heavy loops such as navigations.
gharlan
force-pushed
the
structure-cache-split
branch
from
September 18, 2026 00:26
c6041dc to
5e272ce
Compare
gharlan
force-pushed
the
structure-cache-split
branch
from
September 18, 2026 00:28
a5dba70 to
22f3d15
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to the category split: the structure meta cache was still one flat row per article and language, holding the article and (for a start article) the category columns of that language.
That shared row was the last place mixing both entities, and it needed three workarounds to stay readable:
art_/cat_prefixes had to act as the separator between article and category meta fields, so both constructors stripped the other entity's fields with anunsetloopcatname,catpriority,catcreatedate, …)categoryMetaColumns()picked up the remaining category columns by excluding a hardcoded list of core column namesIt also saved nothing:
File::getCache()has no memoization, soArticle::get()andCategory::get()for the same id already read the file twice — andCategory::get()deserialized everyart_meta field only to discard it, once per element in category-heavy loops such as navigations.What changed
The cache now holds one file per entity and language:
ArticleCache::generateMeta()reads both tables through a smallselectRows()helper instead of one joined query with aliases;categoryMetaColumns()and the aliases are gone, as are bothunsetloopsStructureElement::get()picks the file via the newcacheFileSuffix(), soCategory::fromCache()no longer needs thestartarticlecheck — a missing file means "not a category" — andfromCache()is non-nullable nowparent_id,pathandstatusbelong to the start article, not torex_category; they are copied into the category file so a category can be built from its own file aloneArticleCache::deleteMeta()removes both filesNothing about the public API changes:
getValue()/hasValue()including thecatname/catpriorityaliases and the prefix-less meta field access behave exactly as before.Note
Category::get()on an id that is not a category finds no file and therefore regenerates the cache on every call, becauseInstancePoolTrait::getInstance()guards withisset()and never remembers anull. #6674 fixes that on5.x; once it is merged up, this is covered. In practice the case is rare — anything coming frompath,.clistorcategoryIdis always a real category.Testing
name,status,priority,path,parentId,startArticle,categoryId,getParentTree(),getChildren(),isOnlineIncludingParents()against the previous implementation: identical outputcomposer checkclean, no new baseline entries