Bug 731274 - Make reloadLivemarks optionally force reloads and use it to speed up livemarks population.

r=dietrich sr=gavin
This commit is contained in:
Marco Bonardo 2012-03-08 11:14:59 +01:00
Родитель 115059e908
Коммит baf76b6247
8 изменённых файлов: 201 добавлений и 8 удалений

Просмотреть файл

@ -657,7 +657,9 @@ PlacesViewBase.prototype = {
aPlacesNode._siteURI = aLivemark.siteURI; aPlacesNode._siteURI = aLivemark.siteURI;
if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) { if (aNewState == Ci.nsINavHistoryContainerResultNode.STATE_OPENED) {
aLivemark.registerForUpdates(aPlacesNode, this); aLivemark.registerForUpdates(aPlacesNode, this);
// Prioritize the current livemark.
aLivemark.reload(); aLivemark.reload();
PlacesUtils.livemarks.reloadLivemarks();
if (shouldInvalidate) if (shouldInvalidate)
this.invalidateContainer(aPlacesNode); this.invalidateContainer(aPlacesNode);
} }

Просмотреть файл

@ -896,7 +896,9 @@ PlacesTreeView.prototype = {
aNode._feedURI = aLivemark.feedURI; aNode._feedURI = aLivemark.feedURI;
if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) { if (aNewState == Components.interfaces.nsINavHistoryContainerResultNode.STATE_OPENED) {
aLivemark.registerForUpdates(aNode, this); aLivemark.registerForUpdates(aNode, this);
// Prioritize the current livemark.
aLivemark.reload(); aLivemark.reload();
PlacesUtils.livemarks.reloadLivemarks();
if (shouldInvalidate) if (shouldInvalidate)
this.invalidateContainer(aNode); this.invalidateContainer(aNode);
} }

Просмотреть файл

@ -16,7 +16,7 @@ interface mozILivemark;
interface nsINavHistoryResultObserver; interface nsINavHistoryResultObserver;
[scriptable, uuid(addaa7c5-bd85-4c83-9c21-81c8a825c358)] [scriptable, uuid(1dbf174c-696e-4d9b-af0f-350da50d2249)]
interface mozIAsyncLivemarks : nsISupports interface mozIAsyncLivemarks : nsISupports
{ {
/** /**
@ -67,9 +67,15 @@ interface mozIAsyncLivemarks : nsISupports
in mozILivemarkCallback aCallback); in mozILivemarkCallback aCallback);
/** /**
* Forces a reload of all livemarks, whether or not they've expired. * Reloads all livemarks if they are expired or if forced to do so.
*
* @param [optional]aForceUpdate
* If set to true forces a reload even if contents are still valid.
*
* @note The update process is asynchronous, observers registered through
* registerForUpdates will be notified of updated contents.
*/ */
void reloadLivemarks(); void reloadLivemarks([optional]in boolean aForceUpdate);
}; };
[scriptable, function, uuid(62a426f9-39a6-42f0-ad48-b7404d48188f)] [scriptable, function, uuid(62a426f9-39a6-42f0-ad48-b7404d48188f)]

Просмотреть файл

@ -151,6 +151,7 @@ LivemarkService.prototype = {
} }
}, },
_reloading: false,
_startReloadTimer: function LS__startReloadTimer() _startReloadTimer: function LS__startReloadTimer()
{ {
if (this._reloadTimer) { if (this._reloadTimer) {
@ -160,6 +161,7 @@ LivemarkService.prototype = {
this._reloadTimer = Cc["@mozilla.org/timer;1"] this._reloadTimer = Cc["@mozilla.org/timer;1"]
.createInstance(Ci.nsITimer); .createInstance(Ci.nsITimer);
} }
this._reloading = true;
this._reloadTimer.initWithCallback(this._reloadNextLivemark.bind(this), this._reloadTimer.initWithCallback(this._reloadNextLivemark.bind(this),
RELOAD_DELAY_MS, RELOAD_DELAY_MS,
Ci.nsITimer.TYPE_ONE_SHOT); Ci.nsITimer.TYPE_ONE_SHOT);
@ -179,6 +181,7 @@ LivemarkService.prototype = {
} }
if (this._reloadTimer) { if (this._reloadTimer) {
this._reloading = false;
this._reloadTimer.cancel(); this._reloadTimer.cancel();
delete this._reloadTimer; delete this._reloadTimer;
} }
@ -363,7 +366,7 @@ LivemarkService.prototype = {
{ {
this._reportDeprecatedMethod(); this._reportDeprecatedMethod();
this._reloadLivemarks(); this._reloadLivemarks(true);
}, },
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -393,7 +396,15 @@ LivemarkService.prototype = {
throw new Components.Exception("", Cr.NS_ERROR_INVALID_ARG); throw new Components.Exception("", Cr.NS_ERROR_INVALID_ARG);
} }
livemark = new Livemark(aLivemarkInfo); // Don't pass unexpected input data to the livemark constructor.
livemark = new Livemark({ title: aLivemarkInfo.title
, parentId: aLivemarkInfo.parentId
, index: aLivemarkInfo.index
, feedURI: aLivemarkInfo.feedURI
, siteURI: aLivemarkInfo.siteURI
, guid: aLivemarkInfo.guid
, lastModified: aLivemarkInfo.lastModified
});
if (this._itemAdded && this._itemAdded.id == livemark.id) { if (this._itemAdded && this._itemAdded.id == livemark.id) {
livemark.index = this._itemAdded.index; livemark.index = this._itemAdded.index;
if (!aLivemarkInfo.guid) { if (!aLivemarkInfo.guid) {
@ -469,20 +480,31 @@ LivemarkService.prototype = {
_reloaded: [], _reloaded: [],
_reloadNextLivemark: function LS__reloadNextLivemark() _reloadNextLivemark: function LS__reloadNextLivemark()
{ {
this._reloading = false;
// Find first livemark to be reloaded. // Find first livemark to be reloaded.
for (let id in this._livemarks) { for (let id in this._livemarks) {
if (this._reloaded.indexOf(id) == -1) { if (this._reloaded.indexOf(id) == -1) {
this._reloaded.push(id); this._reloaded.push(id);
this._livemarks[id].reload(); this._livemarks[id].reload(this._forceUpdate);
this._startReloadTimer(); this._startReloadTimer();
break; break;
} }
} }
}, },
reloadLivemarks: function LS_reloadLivemarks() reloadLivemarks: function LS_reloadLivemarks(aForceUpdate)
{ {
// Check if there's a currently running reload, to save some useless work.
let notWorthRestarting =
this._forceUpdate || // We're already forceUpdating.
!aForceUpdate; // The caller didn't request a forced update.
if (this._reloading && notWorthRestarting) {
// Ignore this call.
return;
}
this._onCacheReady((function LS_reloadAllLivemarks_ETAT() { this._onCacheReady((function LS_reloadAllLivemarks_ETAT() {
this._forceUpdate = !!aForceUpdate;
this._reloaded = []; this._reloaded = [];
// Livemarks reloads happen on a timer, and are delayed for performance // Livemarks reloads happen on a timer, and are delayed for performance
// reasons. // reasons.
@ -841,6 +863,10 @@ Livemark.prototype = {
this.status = Ci.mozILivemark.STATUS_LOADING; this.status = Ci.mozILivemark.STATUS_LOADING;
// Setting the status notifies observers that may remove the livemark.
if (this._terminated)
return;
try { try {
// Create a load group for the request. This will allow us to // Create a load group for the request. This will allow us to
// automatically keep track of redirects, so we can always // automatically keep track of redirects, so we can always
@ -1003,6 +1029,8 @@ Livemark.prototype = {
*/ */
terminate: function LM_terminate() terminate: function LM_terminate()
{ {
// Avoid handling any updateChildren request from now on.
this._terminated = true;
// Clear the list before aborting, since abort() would try to set the // Clear the list before aborting, since abort() would try to set the
// status and notify about it, but that's not really useful at this point. // status and notify about it, but that's not really useful at this point.
this._resultObserversList = []; this._resultObserversList = [];

Просмотреть файл

@ -61,6 +61,7 @@ _CHROME_FILES = \
test_favicon_annotations.xul \ test_favicon_annotations.xul \
test_303567.xul \ test_303567.xul \
test_381357.xul \ test_381357.xul \
test_reloadLivemarks.xul \
$(NULL) $(NULL)
libs:: $(_HTTP_FILES) libs:: $(_HTTP_FILES)

Просмотреть файл

@ -0,0 +1,136 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet
href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
<window title="Reload Livemarks"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="runTest()">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<body xmlns="http://www.w3.org/1999/xhtml" />
<script type="application/javascript">
<![CDATA[
// Test that for concurrent reload of livemarks.
SimpleTest.waitForExplicitFinish();
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/PlacesUtils.jsm");
let gLivemarks = [
{ id: -1,
title: "foo",
parentId: PlacesUtils.toolbarFolderId,
index: PlacesUtils.bookmarks.DEFAULT_INDEX,
feedURI: NetUtil.newURI("http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/link-less-items.rss")
},
{ id: -1,
title: "bar",
parentId: PlacesUtils.toolbarFolderId,
index: PlacesUtils.bookmarks.DEFAULT_INDEX,
feedURI: NetUtil.newURI("http://mochi.test:8888/tests/toolkit/components/places/tests/chrome/link-less-items-no-site-uri.rss")
},
];
function runTest()
{
addLivemarks(function () {
reloadLivemarks(false, function () {
reloadLivemarks(true, function () {
removeLivemarks(SimpleTest.finish);
});
});
// Ensure this normal reload doesn't overwrite the forced one.
PlacesUtils.livemarks.reloadLivemarks();
});
}
function addLivemarks(aCallback) {
info("Adding livemarks");
let count = gLivemarks.length;
gLivemarks.forEach(function(aLivemarkData) {
PlacesUtils.livemarks.addLivemark(aLivemarkData,
function (aStatus, aLivemark) {
ok(Components.isSuccessCode(aStatus), "Add livemark should succeed");
aLivemarkData.id = aLivemark.id;
if (--count == 0) {
aCallback();
}
}
);
});
}
function reloadLivemarks(aForceUpdate, aCallback) {
info("Reloading livemarks with forceUpdate: " + aForceUpdate);
let count = gLivemarks.length;
gLivemarks.forEach(function(aLivemarkData) {
PlacesUtils.livemarks.getLivemark(aLivemarkData,
function (aStatus, aLivemark) {
ok(Components.isSuccessCode(aStatus), "Get livemark should succeed");
aLivemarkData._observer = new resultObserver(aLivemark, function() {
if (++count == gLivemarks.length) {
aCallback();
}
});
if (--count == 0) {
PlacesUtils.livemarks.reloadLivemarks(aForceUpdate);
}
}
);
});
}
function removeLivemarks(aCallback) {
info("Removing livemarks");
let count = gLivemarks.length;
gLivemarks.forEach(function(aLivemarkData) {
PlacesUtils.livemarks.removeLivemark(aLivemarkData,
function (aStatus, aLivemark) {
ok(Components.isSuccessCode(aStatus), "Remove livemark should succeed");
if (--count == 0) {
aCallback();
}
}
);
});
}
function resultObserver(aLivemark, aCallback) {
this._node = {};
this._livemark = aLivemark;
this._callback = aCallback;
this._livemark.registerForUpdates(this._node, this);
}
resultObserver.prototype = {
nodeInserted: function() {},
nodeRemoved: function() {},
nodeAnnotationChanged: function() {},
nodeTitleChanged: function() {},
nodeHistoryDetailsChanged: function() {},
nodeReplaced: function() {},
nodeMoved: function() {},
ontainerStateChanged: function () {},
sortingChanged: function() {},
batching: function() {},
invalidateContainer: function(aContainer) {
// Wait for load finish.
if (this._livemark.status == Ci.mozILivemark.STATUS_LOADING)
return;
this._livemark.unregisterForUpdates(this._node);
this._callback();
}
};
]]>
</script>
</window>

Просмотреть файл

@ -243,6 +243,24 @@ add_test(function test_addLivemark_callback_succeeds()
}); });
}); });
add_test(function test_addLivemark_bogusid_callback_succeeds()
{
PlacesUtils.livemarks.addLivemark({ id: 100 // Should be ignored.
, title: "test"
, parentId: PlacesUtils.unfiledBookmarksFolderId
, index: PlacesUtils.bookmarks.DEFAULT_INDEX
, feedURI: FEED_URI
, siteURI: SITE_URI
}, function (aStatus, aLivemark)
{
do_check_true(Components.isSuccessCode(aStatus));
do_check_true(aLivemark.id > 0);
do_check_neq(aLivemark.id, 100);
run_next_test();
});
});
add_test(function test_addLivemark_bogusParent_callback_fails() add_test(function test_addLivemark_bogusParent_callback_fails()
{ {
PlacesUtils.livemarks.addLivemark({ title: "test" PlacesUtils.livemarks.addLivemark({ title: "test"

Просмотреть файл

@ -56,7 +56,7 @@ let testServices = [
["browser/nav-bookmarks-service;1","nsINavBookmarksService", ["browser/nav-bookmarks-service;1","nsINavBookmarksService",
["createFolder", "getItemIdForGUID"]], ["createFolder", "getItemIdForGUID"]],
["browser/livemark-service;2","nsILivemarkService", []], ["browser/livemark-service;2","nsILivemarkService", []],
["browser/livemark-service;2","mozIAsyncLivemarks", []], ["browser/livemark-service;2","mozIAsyncLivemarks", ["reloadLivemarks"]],
["browser/annotation-service;1","nsIAnnotationService", []], ["browser/annotation-service;1","nsIAnnotationService", []],
["browser/favicon-service;1","nsIFaviconService", []], ["browser/favicon-service;1","nsIFaviconService", []],
["browser/tagging-service;1","nsITaggingService", []], ["browser/tagging-service;1","nsITaggingService", []],