fix: order and bound the revisions query in WikiPage.get_context - #1
fix: order and bound the revisions query in WikiPage.get_context#1Aanzan426 wants to merge 2 commits into
Conversation
`get_context` loads every revision of a page, with full `content` on each, then uses only `revisions[0]` and `revisions[1]`. Correctness first: there is no `ORDER BY`, so `revisions[0]` is whatever the database happens to return first. It is not guaranteed to be the newest revision, which is what `context.current_revision` is used as. Today it is usually right by insertion order; that is luck, not a guarantee, and it can change with storage engine, replication or a table rebuild. Adding `order_by="creation desc"` makes it correct, and once the order is defined, `limit_page_length=2` makes it cheap. Measured on a page with 107 revisions: 32.7 ms to 5.7 ms, and 3.37 MB of revision content loaded to use 130 KB of it. The saving scales with edit history, so the pages that cost the most are the most-edited ones. No behaviour change for callers: the two values assigned are the same two, and the `len(revisions) > 1` branch still distinguishes a page with one revision.
Two tests in `test_wiki_page.py`: - `test_get_context_orders_revisions_by_creation_not_modified` gives three revisions a `modified` order opposite to their `creation` order, so the doctype's default `modified DESC` sort and chronological order disagree, then asserts `current_revision` and `previous_revision` are the two newest *by creation*. Verified to fail without the fix and pass with it. - `test_get_context_handles_a_page_with_one_revision` pins the single-revision case, where `previous_revision` must remain the "No Revisions" placeholder -- the branch most easily broken by adding a limit. Note for reviewers: my original description claimed the query had no `ORDER BY`. That was wrong. Frappe injects one from the doctype's `sort_field`, so the unpatched query emits `ORDER BY \`tabWiki Page Revision\`.\`modified\` DESC`. The ordering is therefore deterministic today, just sorted by the wrong column -- `modified` is when a row was last written, not when the revision was made, so touching an old revision presents it as the current one. The missing `LIMIT` is unaffected by that correction and remains the larger practical win.
Code Review - PR #1Reviewer: OpenClaw Bot SummaryThis is a small, targeted fix to What's Done Well
IssuesNo blocking issues found. File-by-File Summary
Note: GitHub reports no checks on this branch, so I reviewed the code and test intent but did not see CI results here.
|
|
Closing this — not because the fix is wrong, but because the delivery path costs more than the fix is worth. Recording the reasoning so it can be re-opened on evidence rather than re-litigated from scratch. It does not help the work it was raised for
The measured benefit is narrower than the PR impliesRe-measured on the walnut bench, all 1,169 pages that have revisions:
The 107-revision page quoted above (3.37 MB read to use 130 KB) is real, and it is the second-worst page on the site. For 71% of pages the query returns a single row either way — nothing to bound, and no ordering to get wrong. This is a genuine tail fix, not a median one, and the PR body says as much; the point here is only that the tail is ~71 pages, none of them parent-facing. Correcting one claim in the description above
On the walnut dev bench that decision is already made — On doing it as an override insteadPer @badal8381's suggestion — worth writing down what is actually possible, because the answer is "half of it". The query is inline in
So an override can buy correctness but not performance. If the The fix stays on recordfrappe#742 remains open and is the right home for it. Note What would justify re-opening
|
Bounds and orders the revisions query in
WikiPage.get_context. This is the Unity-owned copy of the change — mergeable by us, on the branch we actually deploy (master,2372f859f6).The problem
get_contextloads every revision of a page, with the fullcontentblob on each, then uses onlyrevisions[0]andrevisions[1]:Two problems, one large and one small.
1. There is no
LIMIT. Only two rows are ever used. On a page with 107 revisions that is 3.37 MB read to use 130 KB, and it grows with edit history — so the most-edited pages, usually also the most-read, pay the most.2. The ordering is by the wrong column. There is an implicit
ORDER BY— Frappe supplies one from the doctype'ssort_field, so the query emits:modifiedis when the row was last written, not when the revision was made. They coincide while revisions are only appended, but any write touching an older revision's row moves it to the front, and it is then handed to the template ascurrent_revision.The fix
Impact
Measured on a page with 107 revisions:
On a single-revision page the difference is negligible either way — this is not a median-case win, it is an outlier and correctness win.
Tests
test_get_context_orders_revisions_by_creation_not_modified— gives three revisions amodifiedorder deliberately opposite to theircreationorder, so the default sort and chronological order disagree, then assertscurrent_revision/previous_revisionare the two newest by creation. Verified to fail onmasterand pass with this change.test_get_context_handles_a_page_with_one_revision— pins the single-revision case, whereprevious_revisionmust stay the"No Revisions"placeholder. That is the branch aLIMITis most likely to break.Full
test_wiki_page.pysuite: 4 tests, all passing.Compatibility
No behaviour change for callers. The same two values are assigned, and
len(revisions) > 1still distinguishes a one-revision page: the query returns one row, so the placeholder path is preserved.Deployment note
Merging this puts the fix in the Unity fork. It only reaches walnut if the bench is pointed at the fork for
wiki— a separate decision, and one that cuts against the overrides-first approach used forwalnut_customizations#114. Merging here is still worth it: it means the fix exists somewhere we control rather than only in an upstream PR that may sit indefinitely.Ref: WalnutAppSuite/walnut_customizations#114