зеркало из https://github.com/mozilla/pjs.git
Bug 606353 - History sync: use mozIAsyncHistory::updatePlaces. r=rnewman
This commit is contained in:
Родитель
de2eb34de6
Коммит
320733ecaf
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче