Bug 606353 - History sync: use mozIAsyncHistory::updatePlaces. r=rnewman

This commit is contained in:
Philipp von Weitershausen 2011-01-28 09:39:35 -08:00
Родитель de2eb34de6
Коммит 320733ecaf
2 изменённых файлов: 145 добавлений и 12 удалений

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

@ -90,6 +90,7 @@ MOBILE_BATCH_SIZE: 50,
// Default batch size for applying incoming records.
DEFAULT_STORE_BATCH_SIZE: 1,
HISTORY_STORE_BATCH_SIZE: 50, // same as MOBILE_BATCH_SIZE
// score thresholds for early syncs
SINGLE_USER_THRESHOLD: 1000,

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

@ -46,6 +46,7 @@ const Cr = Components.results;
const GUID_ANNO = "sync/guid";
const HISTORY_TTL = 5184000; // 60 days
const TOPIC_UPDATEPLACES_COMPLETE = "places-updatePlaces-complete";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://services-sync/constants.js");
@ -53,6 +54,7 @@ Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/log4moz.js");
Cu.import("resource://services-sync/ext/Sync.js");
function HistoryRec(collection, id) {
CryptoWrapper.call(this, collection, id);
@ -75,7 +77,9 @@ HistoryEngine.prototype = {
_storeObj: HistoryStore,
_trackerObj: HistoryTracker,
downloadLimit: MAX_HISTORY_DOWNLOAD,
applyIncomingBatchSize: HISTORY_STORE_BATCH_SIZE,
// For Gecko <2.0
_sync: Utils.batchSync("History", SyncEngine),
_findDupe: function _findDupe(item) {
@ -108,6 +112,15 @@ HistoryStore.prototype = {
return this.__hsvc;
},
__asyncHistory: null,
get _asyncHistory() {
if (!this.__asyncHistory && "mozIAsyncHistory" in Components.interfaces) {
this.__asyncHistory = Cc["@mozilla.org/browser/history;1"]
.getService(Ci.mozIAsyncHistory);
}
return this.__asyncHistory;
},
get _db() {
return this._hsvc.DBConnection;
},
@ -405,6 +418,129 @@ HistoryStore.prototype = {
}, {});
},
applyIncomingBatch: function applyIncomingBatch(records) {
// Gecko <2.0
if (!this._asyncHistory) {
return Store.prototype.applyIncomingBatch.apply(this, arguments);
}
// Gecko 2.0
let failed = [];
// Convert incoming records to mozIPlaceInfo objects.
let placeInfos = records.map(function (record) {
// This is still synchronous I/O for now.
if (record.deleted) {
try {
// Consider using nsIBrowserHistory::removePages() here.
this.remove(record);
} catch (ex) {
this._log.warn("Failed to delete record " + record.id);
failed.push(record.id);
}
return null;
}
try {
return this._recordToPlaceInfo(record);
} catch(ex) {
failed.push(record.id);
return null;
}
}, this);
// Filter out the places that can't be added (they're null)
function identity(obj) {
return obj;
}
placeInfos = placeInfos.filter(identity);
// Nothing to do.
if (!placeInfos.length) {
return failed;
}
let [updatePlaces, cb] = Sync.withCb(this._asyncHistory.updatePlaces,
this._asyncHistory);
let onPlace = function onPlace(result, placeInfo) {
if (!Components.isSuccessCode(result)) {
failed.push(placeInfo.guid);
}
};
let onComplete = function onComplete(subject, topic, data) {
Svc.Obs.remove(TOPIC_UPDATEPLACES_COMPLETE, onComplete);
cb();
};
Svc.Obs.add(TOPIC_UPDATEPLACES_COMPLETE, onComplete);
updatePlaces(placeInfos, onPlace);
return failed;
},
/**
* Converts a Sync history record to a mozIPlaceInfo.
*
* Throws if an invalid record is encountered (invalid URI, etc.)
* and returns null if the record is to be ignored (no visits to add, etc.)
*/
_recordToPlaceInfo: function _recordToPlaceInfo(record) {
// Sort out invalid URIs and ones Places just simply doesn't want.
let uri = Utils.makeURI(record.histUri);
if (!uri) {
this._log.warn("Attempted to process invalid URI, skipping.");
throw "Invalid URI in record";
}
if (!Utils.checkGUID(record.id)) {
this._log.warn("Encountered record with invalid GUID: " + record.id);
return null;
}
if (!this._hsvc.canAddURI(uri)) {
this._log.trace("Ignoring record " + record.id +
" with URI " + uri.spec + ": can't add this URI.");
return null;
}
// We dupe visits by date and type. So an incoming visit that has
// the same timestamp and type as a local one won't get applied.
let curVisitsByDate = {};
for each (let {date, type} in this._getVisits(record.histUri)) {
curVisitsByDate[date] = type;
}
let visits = record.visits.filter(function (visit) {
if (!visit.date || typeof visit.date != "number") {
this._log.warn("Encountered record with invalid visit date: "
+ visit.date);
throw "Visit has no date!";
}
// TRANSITION_FRAMED_LINK = TRANSITION_DOWNLOAD + 1 is new in Gecko 2.0
if (!visit.type || !(visit.type >= Svc.History.TRANSITION_LINK &&
visit.type <= Svc.History.TRANSITION_DOWNLOAD + 1)) {
this._log.warn("Encountered record with invalid visit type: "
+ visit.type);
throw "Invalid visit type!";
}
// Dates need to be integers
visit.date = Math.round(visit.date);
return curVisitsByDate[visit.date] != visit.type;
});
// No update if there aren't any visits to apply.
// mozIAsyncHistory::updatePlaces() wants at least one visit.
// In any case, the only thing we could change would be the title
// and that shouldn't change without a visit.
if (!visits.length) {
this._log.trace("Ignoring record " + record.id +
" with URI " + uri.spec + ": no visits to add.");
return null;
}
return {uri: uri,
guid: record.id,
title: record.title,
visits: [{visitDate: visit.date, transitionType: visit.type}
for each (visit in visits)]};
},
create: function HistStore_create(record) {
// Add the url and set the GUID
this.update(record);
@ -426,23 +562,19 @@ HistoryStore.prototype = {
update: function HistStore_update(record) {
this._log.trace(" -> processing history entry: " + record.histUri);
let uri = Utils.makeURI(record.histUri);
if (!uri) {
this._log.warn("Attempted to process invalid URI, skipping");
throw "invalid URI in record";
let placeInfo = this._recordToPlaceInfo(record);
if (!placeInfo) {
return;
}
let curvisits = [];
if (this.urlExists(uri))
curvisits = this._getVisits(record.histUri);
// Add visits if there's no local visit with the same date
for each (let {date, type} in record.visits)
if (curvisits.every(function(cur) cur.date != date))
Svc.History.addVisit(uri, date, null, type, type == 5 || type == 6, 0);
for each (let {visitDate, transitionType} in placeInfo.visits) {
Svc.History.addVisit(placeInfo.uri, visitDate, null, transitionType,
transitionType == 5 || transitionType == 6, 0);
}
if (record.title) {
try {
this._hsvc.setPageTitle(uri, record.title);
this._hsvc.setPageTitle(placeInfo.uri, record.title);
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) {
// There's no entry for the given URI, either because it's a
// URI that Places ignores (e.g. javascript:) or there were no