com_courses: fix outline editor exhausting memory on newer courses - #1920
Open
denphi wants to merge 1 commit into
Open
com_courses: fix outline editor exhausting memory on newer courses#1920denphi wants to merge 1 commit into
denphi wants to merge 1 commit into
Conversation
Section::access() wrote the section's own id into the shared permissions `offering_id`, so Permissions::_calculate() then asked Course::offering() for an offering whose id is really a section id. When no offering row carries that id, Course::offering() discards the correctly-cached offering and caches an id-less one in its place -- Tables\Offering::load() ignores course_id for a numeric id, so it simply finds nothing. Every later $course->offering() returned that empty model, so Offering::units() passed offering_id => 0 to the units query. The _buildQuery() guards read a falsy scope id as "no filter" rather than "match nothing", dropping the WHERE clause entirely, so the query returned every unit on the hub -- then every asset group, then every asset. That is ~14,500 asset models, each with its own table object and SHOW FULL COLUMNS round trip, exhausting a 256MB limit in about six seconds. Only the editasset/editwiki/edittool layouts die; the outline builder survives because it reads units before the permissions calculation has poisoned the cached offering. Courses whose section id happens to equal their offering id are unaffected, which is why this only shows up on courses recent enough for the two id sequences to have drifted apart. Corrects the offering_id, and hardens the three scope-id guards so a zero can no longer widen a scoped query into a full table scan. admin/controllers/assets.php passed 0 to mean "every scope", so it now omits the key rather than relying on that ambiguity. Also guards edittool.php against calling files() on a handler that does not implement it -- a url/link asset reaches that layout with a Models\Assets\Url handler and fatals. Ticket: https://nanohub.org/support/ticket/513503 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Section::access() wrote the section's own id into the shared permissions
offering_id, so Permissions::_calculate() then asked Course::offering() for an offering whose id is really a section id. When no offering row carries that id, Course::offering() discards the correctly-cached offering and caches an id-less one in its place -- Tables\Offering::load() ignores course_id for a numeric id, so it simply finds nothing.Every later $course->offering() returned that empty model, so Offering::units() passed offering_id => 0 to the units query. The _buildQuery() guards read a falsy scope id as "no filter" rather than "match nothing", dropping the WHERE clause entirely, so the query returned every unit on the hub -- then every asset group, then every asset. That is ~14,500 asset models, each with its own table object and SHOW FULL COLUMNS round trip, exhausting a 256MB limit in about six seconds.
Only the editasset/editwiki/edittool layouts die; the outline builder survives because it reads units before the permissions calculation has poisoned the cached offering.
Courses whose section id happens to equal their offering id are unaffected, which is why this only shows up on courses recent enough for the two id sequences to have drifted apart.
Corrects the offering_id, and hardens the three scope-id guards so a zero can no longer widen a scoped query into a full table scan. admin/controllers/assets.php passed 0 to mean "every scope", so it now omits the key rather than relying on that ambiguity.
Also guards edittool.php against calling files() on a handler that does not implement it -- a url/link asset reaches that layout with a Models\Assets\Url handler and fatals.
Ticket: https://nanohub.org/support/ticket/513503