author | Philipp von Weitershausen <philipp@weitershausen.de> |
Thu, 07 Apr 2011 15:30:44 -0700 | |
changeset 67774 | 20ab4d32a215b9112ebe239946942eefdaea2ee7 |
parent 67773 | f73ae964d03329cb86fae0c12004c68e425f845c |
child 67775 | 7249a475841963025662109455c1ba4cbda88a48 |
push id | 19427 |
push user | pweitershausen@mozilla.com |
push date | Sun, 10 Apr 2011 18:54:44 +0000 |
treeherder | mozilla-central@21ce62e6aebe [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | rnewman |
bugs | 648338 |
milestone | 2.2a1pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/services/sync/modules/engines/history.js +++ b/services/sync/modules/engines/history.js @@ -73,19 +73,16 @@ function HistoryEngine() { HistoryEngine.prototype = { __proto__: SyncEngine.prototype, _recordObj: HistoryRec, _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) { return this._store.GUIDForUri(item.histUri); } }; function HistoryStore(name) { Store.call(this, name); @@ -108,200 +105,59 @@ HistoryStore.prototype = { QueryInterface(Ci.nsIGlobalHistory2). QueryInterface(Ci.nsIBrowserHistory). QueryInterface(Ci.nsPIPlacesDatabase); return this.__hsvc; }, __asyncHistory: null, get _asyncHistory() { - if (!this.__asyncHistory && "mozIAsyncHistory" in Components.interfaces) { + if (!this.__asyncHistory) { this.__asyncHistory = Cc["@mozilla.org/browser/history;1"] .getService(Ci.mozIAsyncHistory); } return this.__asyncHistory; }, - get _db() { - return this._hsvc.DBConnection; - }, - _stmts: {}, _getStmt: function(query) { if (query in this._stmts) return this._stmts[query]; this._log.trace("Creating SQL statement: " + query); - return this._stmts[query] = Utils.createStatement(this._db, query); - }, - - get _haveTempTablesStm() { - return this._getStmt( - "SELECT name FROM sqlite_temp_master " + - "WHERE name IN ('moz_places_temp', 'moz_historyvisits_temp')"); - }, - _haveTempTablesCols: ["name"], - - __haveTempTables: null, - get _haveTempTables() { - if (this.__haveTempTables === null) { - this.__haveTempTables = !!Utils.queryAsync( - this._haveTempTablesStm, this._haveTempTablesCols).length; - } - return this.__haveTempTables; - }, - - __haveGUIDColumn: null, - get _haveGUIDColumn() { - if (this.__haveGUIDColumn !== null) { - return this.__haveGUIDColumn; - } - let stmt; - try { - stmt = this._db.createStatement("SELECT guid FROM moz_places"); - stmt.finalize(); - return this.__haveGUIDColumn = true; - } catch(ex) { - return this.__haveGUIDColumn = false; - } - }, - - get _addGUIDAnnotationNameStm() { - // Gecko <2.0 only - let stmt = this._getStmt( - "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)"); - stmt.params.anno_name = GUID_ANNO; - return stmt; + return this._stmts[query] = this._hsvc.DBConnection + .createAsyncStatement(query); }, - get _checkGUIDPageAnnotationStm() { - // Gecko <2.0 only - let stmt = this._getStmt( - "SELECT h.id AS place_id, " + - "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS name_id, " + - "a.id AS anno_id, a.dateAdded AS anno_date " + - "FROM (SELECT id FROM moz_places_temp WHERE url = :page_url " + - "UNION " + - "SELECT id FROM moz_places WHERE url = :page_url) AS h " + - "LEFT JOIN moz_annos a ON a.place_id = h.id " + - "AND a.anno_attribute_id = name_id"); - stmt.params.anno_name = GUID_ANNO; - return stmt; - }, - _checkGUIDPageAnnotationCols: ["place_id", "name_id", "anno_id", - "anno_date"], - - get _addPageAnnotationStm() { - // Gecko <2.0 only + get _setGUIDStm() { return this._getStmt( - "INSERT OR REPLACE INTO moz_annos " + - "(id, place_id, anno_attribute_id, mime_type, content, flags, " + - "expiration, type, dateAdded, lastModified) " + - "VALUES (:id, :place_id, :name_id, :mime_type, :content, :flags, " + - ":expiration, :type, :date_added, :last_modified)"); - }, - - __setGUIDStm: null, - get _setGUIDStm() { - if (this.__setGUIDStm !== null) { - return this.__setGUIDStm; - } - - // Obtains a statement to set the guid iff the guid column exists. - let stmt; - if (this._haveGUIDColumn) { - stmt = this._getStmt( - "UPDATE moz_places " + - "SET guid = :guid " + - "WHERE url = :page_url"); - } else { - stmt = false; - } - - return this.__setGUIDStm = stmt; + "UPDATE moz_places " + + "SET guid = :guid " + + "WHERE url = :page_url"); }, // Some helper functions to handle GUIDs setGUID: function setGUID(uri, guid) { uri = uri.spec ? uri.spec : uri; if (!guid) guid = Utils.makeGUID(); - // If we can, set the GUID on moz_places and do not do any other work. - let (stmt = this._setGUIDStm) { - if (stmt) { - stmt.params.guid = guid; - stmt.params.page_url = uri; - Utils.queryAsync(stmt); - return guid; - } - } - - // Ensure annotation name exists - Utils.queryAsync(this._addGUIDAnnotationNameStm); - - let stmt = this._checkGUIDPageAnnotationStm; + let stmt = this._setGUIDStm; + stmt.params.guid = guid; stmt.params.page_url = uri; - let result = Utils.queryAsync(stmt, this._checkGUIDPageAnnotationCols)[0]; - if (!result) { - let log = Log4Moz.repository.getLogger("Engine.History"); - log.warn("Couldn't annotate URI " + uri); - return guid; - } - - stmt = this._addPageAnnotationStm; - if (result.anno_id) { - stmt.params.id = result.anno_id; - stmt.params.date_added = result.anno_date; - } else { - stmt.params.id = null; - stmt.params.date_added = Date.now() * 1000; - } - stmt.params.place_id = result.place_id; - stmt.params.name_id = result.name_id; - stmt.params.content = guid; - stmt.params.flags = 0; - stmt.params.expiration = Ci.nsIAnnotationService.EXPIRE_WITH_HISTORY; - stmt.params.type = Ci.nsIAnnotationService.TYPE_STRING; - stmt.params.last_modified = Date.now() * 1000; Utils.queryAsync(stmt); - return guid; }, - __guidStm: null, get _guidStm() { - if (this.__guidStm) { - return this.__guidStm; - } - - // Try to first read from moz_places. Creating the statement will throw - // if the column doesn't exist, though so fallback to just reading from - // the annotation table. - let stmt; - if (this._haveGUIDColumn) { - stmt = this._getStmt( - "SELECT guid " + - "FROM moz_places " + - "WHERE url = :page_url"); - } else { - stmt = this._getStmt( - "SELECT a.content AS guid " + - "FROM moz_annos a " + - "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " + - "JOIN ( " + - "SELECT id FROM moz_places_temp WHERE url = :page_url " + - "UNION " + - "SELECT id FROM moz_places WHERE url = :page_url " + - ") AS h ON h.id = a.place_id " + - "WHERE n.name = '" + GUID_ANNO + "'"); - } - - return this.__guidStmt = stmt; + return this._getStmt( + "SELECT guid " + + "FROM moz_places " + + "WHERE url = :page_url"); }, _guidCols: ["guid"], GUIDForUri: function GUIDForUri(uri, create) { let stm = this._guidStm; stm.params.page_url = uri.spec ? uri.spec : uri; // Use the existing GUID if it exists @@ -310,86 +166,33 @@ HistoryStore.prototype = { return result.guid; // Give the uri a GUID if it doesn't have one if (create) return this.setGUID(uri); }, get _visitStm() { - // Gecko <2.0 - if (this._haveTempTables) { - let where = - "WHERE place_id = IFNULL( " + - "(SELECT id FROM moz_places_temp WHERE url = :url), " + - "(SELECT id FROM moz_places WHERE url = :url) " + - ") "; - return this._getStmt( - "SELECT visit_type type, visit_date date " + - "FROM moz_historyvisits_temp " + where + "UNION " + - "SELECT visit_type type, visit_date date " + - "FROM moz_historyvisits " + where + - "ORDER BY date DESC LIMIT 10 "); - } - // Gecko 2.0 return this._getStmt( "SELECT visit_type type, visit_date date " + "FROM moz_historyvisits " + "WHERE place_id = (SELECT id FROM moz_places WHERE url = :url) " + "ORDER BY date DESC LIMIT 10"); }, _visitCols: ["date", "type"], - __urlStmt: null, get _urlStm() { - if (this.__urlStmt) { - return this.__urlStmt; - } - - // Try to first read from moz_places. Creating the statement will throw - // if the column doesn't exist, though so fallback to just reading from - // the annotation table. - let stmt; - if (this._haveGUIDColumn) { - stmt = this._getStmt( - "SELECT url, title, frecency " + - "FROM moz_places " + - "WHERE guid = :guid"); - } else { - let where = - "WHERE id = (" + - "SELECT place_id " + - "FROM moz_annos " + - "WHERE content = :guid AND anno_attribute_id = (" + - "SELECT id " + - "FROM moz_anno_attributes " + - "WHERE name = '" + GUID_ANNO + "')) "; - stmt = this._getStmt( - "SELECT url, title, frecency FROM moz_places_temp " + where + - "UNION ALL " + - "SELECT url, title, frecency FROM moz_places " + where + "LIMIT 1"); - } - - return this.__urlStmt = stmt; + return this._getStmt( + "SELECT url, title, frecency " + + "FROM moz_places " + + "WHERE guid = :guid"); }, _urlCols: ["url", "title", "frecency"], get _allUrlStm() { - // Gecko <2.0 - if (this._haveTempTables) - return this._getStmt( - "SELECT url, frecency FROM moz_places_temp " + - "WHERE last_visit_date > :cutoff_date " + - "UNION " + - "SELECT url, frecency FROM moz_places " + - "WHERE last_visit_date > :cutoff_date " + - "ORDER BY 2 DESC " + - "LIMIT :max_results"); - - // Gecko 2.0 return this._getStmt( "SELECT url " + "FROM moz_places " + "WHERE last_visit_date > :cutoff_date " + "ORDER BY frecency DESC " + "LIMIT :max_results"); }, _allUrlCols: ["url"], @@ -420,22 +223,16 @@ HistoryStore.prototype = { let self = this; return urls.reduce(function(ids, item) { ids[self.GUIDForUri(item.url, true)] = item.url; return ids; }, {}); }, applyIncomingBatch: function applyIncomingBatch(records) { - // Gecko <2.0 - if (!this._asyncHistory) { - return Store.prototype.applyIncomingBatch.call(this, records); - } - - // Gecko 2.0 let failed = []; // Convert incoming records to mozIPlaceInfo objects. Some records can be // ignored or handled directly, so we're rewriting the array in-place. let i, k; for (i = 0, k = 0; i < records.length; i++) { let record = records[k] = records[i]; let shouldApply; @@ -524,19 +321,18 @@ HistoryStore.prototype = { for (i = 0, k = 0; i < record.visits.length; i++) { let visit = record.visits[k] = record.visits[i]; 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)) { + visit.type <= Svc.History.TRANSITION_FRAMED_LINK)) { 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); if (curVisits.indexOf(visit.date + "," + visit.type) != -1) { @@ -558,57 +354,28 @@ HistoryStore.prototype = { this._log.trace("Ignoring record " + record.id + " with URI " + record.uri.spec + ": no visits to add."); return false; } return true; }, - create: function HistStore_create(record) { - // Add the url and set the GUID - this.update(record); - this.setGUID(record.histUri, record.id); - }, - remove: function HistStore_remove(record) { let page = this._findURLByGUID(record.id); if (page == null) { this._log.debug("Page already removed: " + record.id); return; } let uri = Utils.makeURI(page.url); Svc.History.removePage(uri); this._log.trace("Removed page: " + [record.id, page.url, page.title]); }, - update: function HistStore_update(record) { - this._log.trace(" -> processing history entry: " + record.histUri); - - if (!this._recordToPlaceInfo(record)) { - return; - } - - for each (let {visitDate, transitionType} in record.visits) { - Svc.History.addVisit(record.uri, visitDate, null, transitionType, - transitionType == 5 || transitionType == 6, 0); - } - - if (record.title) { - try { - this._hsvc.setPageTitle(record.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 - // visits. We can just ignore those cases. - } - } - }, - itemExists: function HistStore_itemExists(id) { if (this._findURLByGUID(id)) return true; return false; }, urlExists: function HistStore_urlExists(url) { if (typeof(url) == "string")
--- a/services/sync/tests/unit/test_history_store.js +++ b/services/sync/tests/unit/test_history_store.js @@ -155,21 +155,20 @@ function run_test() { let queryres = queryHistoryVisits(resuri); do_check_eq(queryres.length, 1); do_check_eq(queryres[0].time, TIMESTAMP3); next(); }, function (next) { _("Make sure we handle invalid URLs in places databases gracefully."); - let table = store._haveTempTables ? "moz_places_temp" : "moz_places"; - let query = "INSERT INTO " + table + " " + let query = "INSERT INTO moz_places " + "(url, title, rev_host, visit_count, last_visit_date) " + "VALUES ('invalid-uri', 'Invalid URI', '.', 1, " + TIMESTAMP3 + ")"; - let stmt = Utils.createStatement(Svc.History.DBConnection, query); + let stmt = Svc.History.DBConnection.createAsyncStatement(query); let result = Utils.queryAsync(stmt); do_check_eq([id for (id in store.getAllIDs())].length, 4); _("Make sure we report records with invalid URIs."); let invalid_uri_guid = Utils.makeGUID(); let failed = store.applyIncomingBatch([{ id: invalid_uri_guid, histUri: ":::::::::::::::",
--- a/services/sync/tests/unit/test_places_guid_downgrade.js +++ b/services/sync/tests/unit/test_places_guid_downgrade.js @@ -90,31 +90,29 @@ function test_history_guids() { Svc.Bookmark.toolbarFolder, uri, Svc.Bookmark.DEFAULT_INDEX, "Mozilla"); let fxguid = store.GUIDForUri(fxuri, true); let tbguid = store.GUIDForUri(tburi, true); dump("fxguid: " + fxguid + "\n"); dump("tbguid: " + tbguid + "\n"); _("History: Verify GUIDs are added to the guid column."); - let stmt = Utils.createStatement( - Svc.History.DBConnection, + let stmt = Svc.History.DBConnection.createAsyncStatement( "SELECT id FROM moz_places WHERE guid = :guid"); stmt.params.guid = fxguid; let result = Utils.queryAsync(stmt, ["id"]); do_check_eq(result.length, 1); stmt.params.guid = tbguid; result = Utils.queryAsync(stmt, ["id"]); do_check_eq(result.length, 1); _("History: Verify GUIDs weren't added to annotations."); - stmt = Utils.createStatement( - Svc.History.DBConnection, + stmt = Svc.History.DBConnection.createAsyncStatement( "SELECT a.content AS guid FROM moz_annos a WHERE guid = :guid"); stmt.params.guid = fxguid; result = Utils.queryAsync(stmt, ["guid"]); do_check_eq(result.length, 0); stmt.params.guid = tbguid; result = Utils.queryAsync(stmt, ["guid"]); @@ -131,33 +129,31 @@ function test_bookmark_guids() { let tbid = Svc.Bookmark.insertBookmark( Svc.Bookmark.toolbarFolder, tburi, Svc.Bookmark.DEFAULT_INDEX, "Get Thunderbird!"); let fxguid = store.GUIDForId(fxid); let tbguid = store.GUIDForId(tbid); _("Bookmarks: Verify GUIDs are added to the guid column."); - let stmt = Utils.createStatement( - Svc.History.DBConnection, + let stmt = Svc.History.DBConnection.createAsyncStatement( "SELECT id FROM moz_bookmarks WHERE guid = :guid"); stmt.params.guid = fxguid; let result = Utils.queryAsync(stmt, ["id"]); do_check_eq(result.length, 1); do_check_eq(result[0].id, fxid); stmt.params.guid = tbguid; result = Utils.queryAsync(stmt, ["id"]); do_check_eq(result.length, 1); do_check_eq(result[0].id, tbid); _("Bookmarks: Verify GUIDs weren't added to annotations."); - stmt = Utils.createStatement( - Svc.History.DBConnection, + stmt = Svc.History.DBConnection.createAsyncStatement( "SELECT a.content AS guid FROM moz_items_annos a WHERE guid = :guid"); stmt.params.guid = fxguid; result = Utils.queryAsync(stmt, ["guid"]); do_check_eq(result.length, 0); stmt.params.guid = tbguid; result = Utils.queryAsync(stmt, ["guid"]);