From e367ecc948502157d9d1000130f92d32575024db Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Mon, 2 Feb 2015 20:30:00 -0800 Subject: [PATCH] Make API module's LinkCache data transmission format more efficient We used to send data like { title: { missing: true|false } } With this change, we send data like { missing: [titles], existing: true|[titles] } where 'existing' is set to true (assume all non-missing titles exist) for current revisions and to an array of existing titles for old revisions. This is because we always output this data for links in the current revision, even when loading an old revision: in that case we rely on the client to request the omitted information, so there we can't assume that all pages we don't have information about exist. Bug: T88259 Change-Id: I7b58b3f669cc78fd81b60859cf76928a9087066f --- ApiVisualEditor.php | 28 ++++++++++++++++------ modules/ve-mw/init/ve.init.mw.LinkCache.js | 26 ++++++++++++++++++++ modules/ve-mw/init/ve.init.mw.Target.js | 21 ++++++++++++++-- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/ApiVisualEditor.php b/ApiVisualEditor.php index cc4c468763..ed3ca8b5ee 100644 --- a/ApiVisualEditor.php +++ b/ApiVisualEditor.php @@ -467,19 +467,33 @@ class ApiVisualEditor extends ApiBase { $wikipage = WikiPage::factory( $page ); $popts = $wikipage->makeParserOptions( 'canonical' ); $cached = ParserCache::singleton()->get( $article, $popts, true ); + $isOldRevision = isset( $params['oldid'] ) && $params['oldid'] != 0 && + $params['oldid'] != $page->getLatestRevID(); + $links = array( + // Array of linked pages that are missing + 'missing' => array(), + // For current revisions: true (treat all non-missing pages as existing) + // For old revisions: array of linked pages that exist + 'extant' => $isOldRevision ? array() : true, + ); if ( $cached ) { foreach ( $cached->getLinks() as $ns => $dbks ) { foreach ( $dbks as $dbk => $id ) { - $links[ Title::makeTitle( $ns, $dbk )->getPrefixedText() ] = array( - 'missing' => $id == 0 - ); + $pft = Title::makeTitle( $ns, $dbk )->getPrefixedText(); + if ( $id == 0 ) { + $links['missing'][] = $pft; + } elseif ( $isOldRevision ) { + $links['extant'][] = $pft; + } } } } - - $links[$page->getPrefixedText()] = array( - 'missing' => !$page->exists() - ); + // Add information about current page + if ( !$page->exists() ) { + $links['missing'][] = $page->getPrefixedText(); + } elseif ( $isOldRevision ) { + $links['extant'][] = $page->getPrefixedText(); + } // On parser cache miss, just don't bother populating red link data diff --git a/modules/ve-mw/init/ve.init.mw.LinkCache.js b/modules/ve-mw/init/ve.init.mw.LinkCache.js index 98a619d5eb..5abb7df09d 100644 --- a/modules/ve-mw/init/ve.init.mw.LinkCache.js +++ b/modules/ve-mw/init/ve.init.mw.LinkCache.js @@ -47,6 +47,32 @@ } ); }; + /** + * Enable or disable automatic assumption of existence. + * + * While enabled, any get() for a title that's not already in the cache will return + * { missing: false } and write that to the cache. + * + * @param {boolean} assume Assume all uncached titles exist + */ + ve.init.mw.LinkCache.prototype.setAssumeExistence = function ( assume ) { + this.assumeExistence = !!assume; + }; + + /** + * @inheritdoc + */ + ve.init.mw.LinkCache.prototype.get = function ( title ) { + var data = {}; + if ( this.assumeExistence ) { + data[this.normalizeTitle( title )] = { missing: false }; + this.set( data ); + } + + // Parent method + return ve.init.mw.LinkCache.super.prototype.get.call( this, title ); + }; + /** * @inheritdoc */ diff --git a/modules/ve-mw/init/ve.init.mw.Target.js b/modules/ve-mw/init/ve.init.mw.Target.js index 6cc1ffc4e4..9e54e591d4 100644 --- a/modules/ve-mw/init/ve.init.mw.Target.js +++ b/modules/ve-mw/init/ve.init.mw.Target.js @@ -408,7 +408,8 @@ ve.init.mw.Target.onModulesReady = function () { * @fires loadError */ ve.init.mw.Target.onLoad = function ( response ) { - var data = response ? response.visualeditor : null; + var i, len, linkData, + data = response ? response.visualeditor : null; if ( !data && !response.error ) { ve.init.mw.Target.onLoadError.call( @@ -451,7 +452,21 @@ ve.init.mw.Target.onLoad = function ( response ) { // Populate link cache if ( data.links ) { - ve.init.platform.linkCache.set( data.links ); + // Format from the API: { missing: [titles], extant: true|[titles] } + // Format expected by LinkCache: { title: { missing: true|false } } + linkData = {}; + for ( i = 0, len = data.links.missing.length; i < len; i++ ) { + linkData[data.links.missing[i]] = { missing: true }; + } + if ( data.links.extant === true ) { + // Set back to false by onReady() + ve.init.platform.linkCache.setAssumeExistence( true ); + } else { + for ( i = 0, len = data.links.extant.length; i < len; i++ ) { + linkData[data.links.extant[i]] = { missing: false }; + } + } + ve.init.platform.linkCache.set( linkData ); } // Everything worked, the page was loaded, continue as soon as the modules are loaded @@ -521,6 +536,8 @@ ve.init.mw.Target.prototype.onReady = function () { this.loading = false; this.edited = false; this.setupSurface( this.doc, function () { + // onLoad() may have called setAssumeExistence( true ); + ve.init.platform.linkCache.setAssumeExistence( false ); target.startSanityCheck(); target.emit( 'surfaceReady' ); } );