Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-12-12 14:00:09 +01:00
commit 77659c1b8d
73 changed files with 2142 additions and 1346 deletions

View File

@ -1480,7 +1480,8 @@ nsAccessibilityService::CreateHTMLAccessibleByMarkup(nsIFrame* aFrame,
tag == nsGkAtoms::h6 || tag == nsGkAtoms::h6 ||
tag == nsGkAtoms::nav || tag == nsGkAtoms::nav ||
tag == nsGkAtoms::q || tag == nsGkAtoms::q ||
tag == nsGkAtoms::section) { tag == nsGkAtoms::section ||
tag == nsGkAtoms::time) {
nsRefPtr<Accessible> accessible = nsRefPtr<Accessible> accessible =
new HyperTextAccessibleWrap(aContent, document); new HyperTextAccessibleWrap(aContent, document);
return accessible.forget(); return accessible.forget();

View File

@ -982,6 +982,15 @@ HyperTextAccessible::NativeAttributes()
} else if (tag == nsGkAtoms::main) { } else if (tag == nsGkAtoms::main) {
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles, nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
NS_LITERAL_STRING("main")); NS_LITERAL_STRING("main"));
} else if (tag == nsGkAtoms::time) {
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
NS_LITERAL_STRING("time"));
if (mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::datetime)) {
nsAutoString datetime;
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::datetime, datetime);
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::datetime, datetime);
}
} }
return attributes.forget(); return attributes.forget();

View File

@ -22,8 +22,17 @@
var thisTabDocAcc = getTabDocAccessible(); var thisTabDocAcc = getTabDocAccessible();
var thisDocTabPanelAcc = thisTabDocAcc.parent.parent; var thisDocTabPanelAcc = thisTabDocAcc.parent.parent;
var tabPanelsAcc = thisDocTabPanelAcc.parent; var tabPanelsAcc = thisDocTabPanelAcc.parent;
var newDocTabPanelAcc = tabPanelsAcc.lastChild.firstChild; var newDocTabPanelAcc = tabPanelsAcc.firstChild;
return newDocTabPanelAcc.firstChild; var nextAcc = newDocTabPanelAcc;
while (nextAcc = nextAcc.nextSibling) {
// Find the last accessible for a browser with about:mozilla loaded.
if (nextAcc.firstChild.DOMNode.currentURI.spec == "about:mozilla") {
newDocTabPanelAcc = nextAcc;
}
}
return newDocTabPanelAcc.firstChild.firstChild;
} }
function linkChecker(aID) function linkChecker(aID)

View File

@ -1232,7 +1232,12 @@
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// HTML:time // HTML:time
ok(!isAccessible("time"), "time element is not accessible"); obj = {
role: ROLE_TEXT_CONTAINER,
attributes: { "xml-roles": "time", "datetime": "2001-05-15 19:00" },
interfaces: [ nsIAccessibleText, nsIAccessibleHyperText ]
};
testElm("time", obj);
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// HTML:u contained by paragraph // HTML:u contained by paragraph

View File

@ -15,25 +15,6 @@
src="../role.js"></script> src="../role.js"></script>
<script type="application/javascript" <script type="application/javascript"
src="../states.js"></script> src="../states.js"></script>
<script type="application/javascript">
// Front end stuff sometimes likes to stuff things in the hidden window(s)
// in which case there's accessibles for that content.
Components.utils.import("resource://gre/modules/Services.jsm");
// Force the creation of an accessible for the hidden window's document.
var doc = Services.appShell.hiddenDOMWindow.document;
gAccRetrieval.getAccessibleFor(doc);
// The private hidden window will be lazily created that's why we need to do
// it here *before* loading '../events.js' or else we'll have a duplicate
// reorder event.
var privateDoc = Services.appShell.hiddenPrivateDOMWindow.document;
// Force the creation of an accessible for the private hidden window's doc.
gAccRetrieval.getAccessibleFor(privateDoc);
</script>
<script type="application/javascript" <script type="application/javascript"
src="../events.js"></script> src="../events.js"></script>
@ -193,12 +174,6 @@
var accTree = { var accTree = {
role: ROLE_APP_ROOT, role: ROLE_APP_ROOT,
children: [ children: [
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{ {
role: ROLE_CHROME_WINDOW role: ROLE_CHROME_WINDOW
}, },

View File

@ -31,10 +31,15 @@
is(root.parentDocument, null, is(root.parentDocument, null,
"Wrong parent document of root accessible"); "Wrong parent document of root accessible");
is(root.childDocumentCount, 1, ok(root.childDocumentCount >= 1,
"Wrong child document count of root accessible"); "Wrong child document count of root accessible");
is(root.getChildDocumentAt(0), tabDoc,
"Wrong child document at index 0 of root accessible"); var tabDocumentFound = false;
for (var i = 0; i < root.childDocumentCount && !tabDocumentFound; i++) {
tabDocumentFound = root.getChildDocumentAt(i) == tabDoc;
}
ok(tabDocumentFound,
"Tab document not found in children of the root accessible");
is(tabDoc.parentDocument, root, is(tabDoc.parentDocument, root,
"Wrong parent document of tab document"); "Wrong parent document of tab document");

View File

@ -169,6 +169,23 @@
] ]
} }
] ]
},
{
// notificationbox
role: ROLE_PROPERTYPAGE,
children: [
{
// browser
role: ROLE_INTERNAL_FRAME,
children: [
{
// #document ("about:newtab" preloaded)
role: ROLE_APPLICATION
// children: [ ... ] // Ignore document content.
}
]
}
]
} }
] ]
}; };

View File

@ -11,6 +11,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "fxaMigrator",
const PREF_SYNC_START_DOORHANGER = "services.sync.ui.showSyncStartDoorhanger"; const PREF_SYNC_START_DOORHANGER = "services.sync.ui.showSyncStartDoorhanger";
const DOORHANGER_ACTIVATE_DELAY_MS = 5000; const DOORHANGER_ACTIVATE_DELAY_MS = 5000;
const SYNC_MIGRATION_NOTIFICATION_TITLE = "fxa-migration";
let gFxAccounts = { let gFxAccounts = {
@ -157,7 +158,7 @@ let gFxAccounts = {
setTimeout(() => this.onSyncStart(), DOORHANGER_ACTIVATE_DELAY_MS); setTimeout(() => this.onSyncStart(), DOORHANGER_ACTIVATE_DELAY_MS);
} else { } else {
this._inCustomizationMode = event.type == "customizationstarting"; this._inCustomizationMode = event.type == "customizationstarting";
this.updateUI(); this.updateAppMenuItem();
} }
}, },
@ -182,8 +183,13 @@ let gFxAccounts = {
}, },
updateUI: function () { updateUI: function () {
this.updateAppMenuItem();
this.updateMigrationNotification();
},
updateAppMenuItem: function () {
if (this._migrationInfo) { if (this._migrationInfo) {
this.showMigrationUI(); this.updateAppMenuItemForMigration();
return; return;
} }
@ -241,32 +247,74 @@ let gFxAccounts = {
}); });
}, },
showMigrationUI: Task.async(function* () { updateAppMenuItemForMigration: Task.async(function* () {
let status = null; let status = null;
let label = null; let label = null;
switch (this._migrationInfo.state) { switch (this._migrationInfo.state) {
case fxaMigrator.STATE_USER_FXA: case fxaMigrator.STATE_USER_FXA:
status = "migrate-signup"; status = "migrate-signup";
label = this.strings.formatStringFromName("needUser", label = this.strings.formatStringFromName("needUserShort",
[this.button.getAttribute("fxabrandname")], 1); [this.button.getAttribute("fxabrandname")], 1);
break; break;
case fxaMigrator.STATE_USER_FXA_VERIFIED: case fxaMigrator.STATE_USER_FXA_VERIFIED:
if (this._migrationInfo.email) { status = "migrate-verify";
status = "migrate-verify"; label = this.strings.formatStringFromName("needVerifiedUserShort",
label = this.strings.formatStringFromName("needVerifiedUser", [this._migrationInfo.email],
[this._migrationInfo.email], 1);
1);
}
break; break;
} }
if (label && status) { this.button.label = label;
this.button.label = label; this.button.hidden = false;
this.button.hidden = false; this.button.setAttribute("fxastatus", status);
this.button.setAttribute("fxastatus", status); }),
} else {
Cu.reportError("Could not update menu panel button given migration " + updateMigrationNotification: Task.async(function* () {
"state: " + this._migrationInfo.state); if (!this._migrationInfo) {
Weave.Notifications.removeAll(SYNC_MIGRATION_NOTIFICATION_TITLE);
return;
} }
if (gBrowser.currentURI.spec.split("?")[0] == "about:accounts") {
// If the current tab is about:accounts, assume the user just completed a
// migration step and don't bother them with a redundant notification.
return;
}
let note = null;
switch (this._migrationInfo.state) {
case fxaMigrator.STATE_USER_FXA: {
let msg = this.strings.GetStringFromName("needUserLong");
let upgradeLabel =
this.strings.GetStringFromName("upgradeToFxA.label");
let upgradeAccessKey =
this.strings.GetStringFromName("upgradeToFxA.accessKey");
note = new Weave.Notification(
undefined, msg, undefined, Weave.Notifications.PRIORITY_WARNING, [
new Weave.NotificationButton(upgradeLabel, upgradeAccessKey, () => {
fxaMigrator.createFxAccount(window);
}),
]
);
break;
}
case fxaMigrator.STATE_USER_FXA_VERIFIED: {
let msg =
this.strings.formatStringFromName("needVerifiedUserLong",
[this._migrationInfo.email], 1);
let resendLabel =
this.strings.GetStringFromName("resendVerificationEmail.label");
let resendAccessKey =
this.strings.GetStringFromName("resendVerificationEmail.accessKey");
note = new Weave.Notification(
undefined, msg, undefined, Weave.Notifications.PRIORITY_INFO, [
new Weave.NotificationButton(resendLabel, resendAccessKey, () => {
fxaMigrator.resendVerificationMail();
}),
]
);
break;
}
}
note.title = SYNC_MIGRATION_NOTIFICATION_TITLE;
Weave.Notifications.replaceTitle(note);
}), }),
onMenuPanelCommand: function (event) { onMenuPanelCommand: function (event) {

View File

@ -13,8 +13,6 @@ let CloudSync = null;
// gSyncUI handles updating the tools menu and displaying notifications. // gSyncUI handles updating the tools menu and displaying notifications.
let gSyncUI = { let gSyncUI = {
DEFAULT_EOL_URL: "https://www.mozilla.org/firefox/?utm_source=synceol",
_obs: ["weave:service:sync:start", _obs: ["weave:service:sync:start",
"weave:service:quota:remaining", "weave:service:quota:remaining",
"weave:service:setup-complete", "weave:service:setup-complete",
@ -27,7 +25,6 @@ let gSyncUI = {
"weave:ui:sync:error", "weave:ui:sync:error",
"weave:ui:sync:finish", "weave:ui:sync:finish",
"weave:ui:clear-error", "weave:ui:clear-error",
"weave:eol",
], ],
_unloaded: false, _unloaded: false,
@ -260,32 +257,6 @@ let gSyncUI = {
return brand.get("brandShortName"); return brand.get("brandShortName");
}, },
onEOLNotice: function (data) {
let code = data.code;
let kind = (code == "hard-eol") ? "error" : "warning";
let url = data.url || gSyncUI.DEFAULT_EOL_URL;
let title = this._stringBundle.GetStringFromName(kind + ".sync.eol.label");
let description = this._stringBundle.formatStringFromName(kind + ".sync.eol.description",
[this._getAppName()],
1);
let buttons = [];
buttons.push(new Weave.NotificationButton(
this._stringBundle.GetStringFromName("sync.eol.learnMore.label"),
this._stringBundle.GetStringFromName("sync.eol.learnMore.accesskey"),
function() {
window.openUILinkIn(url, "tab");
return true;
}
));
let priority = (kind == "error") ? Weave.Notifications.PRIORITY_WARNING :
Weave.Notifications.PRIORITY_INFO;
let notification = new Weave.Notification(title, description, null, priority, buttons);
Weave.Notifications.replaceTitle(notification);
},
openServerStatus: function () { openServerStatus: function () {
let statusURL = Services.prefs.getCharPref("services.sync.statusURL"); let statusURL = Services.prefs.getCharPref("services.sync.statusURL");
window.openUILinkIn(statusURL, "tab"); window.openUILinkIn(statusURL, "tab");
@ -551,9 +522,6 @@ let gSyncUI = {
case "weave:ui:clear-error": case "weave:ui:clear-error":
this.clearError(); this.clearError();
break; break;
case "weave:eol":
this.onEOLNotice(subject);
break;
} }
}, },

View File

@ -154,9 +154,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
"resource://gre/modules/SafeBrowsing.jsm"); "resource://gre/modules/SafeBrowsing.jsm");
#endif #endif
XPCOMUtils.defineLazyModuleGetter(this, "gBrowserNewTabPreloader",
"resource:///modules/BrowserNewTabPreloader.jsm", "BrowserNewTabPreloader");
XPCOMUtils.defineLazyModuleGetter(this, "gCustomizationTabPreloader", XPCOMUtils.defineLazyModuleGetter(this, "gCustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm", "CustomizationTabPreloader"); "resource:///modules/CustomizationTabPreloader.jsm", "CustomizationTabPreloader");

View File

@ -669,6 +669,12 @@
if (event.target != otherWin.document) if (event.target != otherWin.document)
return; return;
let detachEvent = new aChatbox.contentWindow.CustomEvent("socialFrameDetached", {
bubbles: true,
cancelable: true,
});
aChatbox.contentDocument.dispatchEvent(detachEvent);
otherWin.removeEventListener("load", _chatLoad, true); otherWin.removeEventListener("load", _chatLoad, true);
let otherChatbox = otherWin.document.getElementById("chatter"); let otherChatbox = otherWin.document.getElementById("chatter");
aChatbox.swapDocShells(otherChatbox); aChatbox.swapDocShells(otherChatbox);

View File

@ -1513,6 +1513,134 @@
</body> </body>
</method> </method>
<field name="_preloadedBrowser">null</field>
<method name="_getPreloadedBrowser">
<body>
<![CDATA[
if (!this._isPreloadingEnabled()) {
return null;
}
// The preloaded browser might be null.
let browser = this._preloadedBrowser;
// Consume the browser.
this._preloadedBrowser = null;
// Attach the nsIFormFillController now that we know the browser
// will be used. If we do that before and the preloaded browser
// won't be consumed until shutdown then we leak a docShell.
if (browser && this.hasAttribute("autocompletepopup")) {
browser.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
browser.attachFormFill();
}
return browser;
]]>
</body>
</method>
<method name="_isPreloadingEnabled">
<body>
<![CDATA[
// Preloading for the newtab page is enabled when the pref is true
// and the URL is "about:newtab". We do not support preloading for
// custom newtab URLs.
return Services.prefs.getBoolPref("browser.newtab.preload") &&
!Services.prefs.prefHasUserValue("browser.newtab.url");
]]>
</body>
</method>
<method name="_createPreloadBrowser">
<body>
<![CDATA[
// Do nothing if we have a preloaded browser already
// or preloading of newtab pages is disabled.
if (this._preloadedBrowser || !this._isPreloadingEnabled()) {
return;
}
let browser = this._createBrowser({isPreloadBrowser: true});
this._preloadedBrowser = browser;
let notificationbox = this.getNotificationBox(browser);
this.mPanelContainer.appendChild(notificationbox);
browser.loadURI(BROWSER_NEW_TAB_URL);
browser.docShellIsActive = false;
]]>
</body>
</method>
<method name="_createBrowser">
<parameter name="aParams"/>
<body>
<![CDATA[
const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
let remote = aParams && aParams.remote;
let uriIsAboutBlank = aParams && aParams.uriIsAboutBlank;
let isPreloadBrowser = aParams && aParams.isPreloadBrowser;
let b = document.createElementNS(NS_XUL, "browser");
b.setAttribute("type", "content-targetable");
b.setAttribute("message", "true");
b.setAttribute("messagemanagergroup", "browsers");
b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
if (remote)
b.setAttribute("remote", "true");
if (window.gShowPageResizers && window.windowState == window.STATE_NORMAL) {
b.setAttribute("showresizer", "true");
}
if (!isPreloadBrowser && this.hasAttribute("autocompletepopup"))
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
if (this.hasAttribute("selectpopup"))
b.setAttribute("selectpopup", this.getAttribute("selectpopup"));
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
// Create the browserStack container
var stack = document.createElementNS(NS_XUL, "stack");
stack.className = "browserStack";
stack.appendChild(b);
stack.setAttribute("flex", "1");
// Create the browserContainer
var browserContainer = document.createElementNS(NS_XUL, "vbox");
browserContainer.className = "browserContainer";
browserContainer.appendChild(stack);
browserContainer.setAttribute("flex", "1");
// Create the sidebar container
var browserSidebarContainer = document.createElementNS(NS_XUL,
"hbox");
browserSidebarContainer.className = "browserSidebarContainer";
browserSidebarContainer.appendChild(browserContainer);
browserSidebarContainer.setAttribute("flex", "1");
// Add the Message and the Browser to the box
var notificationbox = document.createElementNS(NS_XUL,
"notificationbox");
notificationbox.setAttribute("flex", "1");
notificationbox.appendChild(browserSidebarContainer);
// Prevent the superfluous initial load of a blank document
// if we're going to load something other than about:blank.
if (!uriIsAboutBlank) {
b.setAttribute("nodefaultsrc", "true");
}
return b;
]]>
</body>
</method>
<method name="addTab"> <method name="addTab">
<parameter name="aURI"/> <parameter name="aURI"/>
<parameter name="aReferrerURI"/> <parameter name="aReferrerURI"/>
@ -1583,55 +1711,23 @@
if (aOwner) if (aOwner)
t.owner = aOwner; t.owner = aOwner;
var b = document.createElementNS( let b;
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", let usingPreloadedContent = false;
"browser"); let isPrivateWindow = PrivateBrowsingUtils.isWindowPrivate(window);
b.setAttribute("type", "content-targetable");
b.setAttribute("message", "true");
b.setAttribute("messagemanagergroup", "browsers");
b.setAttribute("contextmenu", this.getAttribute("contentcontextmenu"));
b.setAttribute("tooltip", this.getAttribute("contenttooltip"));
if (remote) // If we open a new tab with the newtab URL,
b.setAttribute("remote", "true"); // check if there is a preloaded browser ready.
if (aURI == BROWSER_NEW_TAB_URL && !isPrivateWindow) {
if (window.gShowPageResizers && window.windowState == window.STATE_NORMAL) { b = this._getPreloadedBrowser();
b.setAttribute("showresizer", "true"); usingPreloadedContent = !!b;
} }
if (this.hasAttribute("autocompletepopup")) if (!b) {
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup")); // No preloaded browser found, create one.
b = this._createBrowser({remote, uriIsAboutBlank});
if (this.hasAttribute("selectpopup")) }
b.setAttribute("selectpopup", this.getAttribute("selectpopup"));
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
// Create the browserStack container
var stack = document.createElementNS(NS_XUL, "stack");
stack.className = "browserStack";
stack.appendChild(b);
stack.setAttribute("flex", "1");
// Create the browserContainer
var browserContainer = document.createElementNS(NS_XUL, "vbox");
browserContainer.className = "browserContainer";
browserContainer.appendChild(stack);
browserContainer.setAttribute("flex", "1");
// Create the sidebar container
var browserSidebarContainer = document.createElementNS(NS_XUL,
"hbox");
browserSidebarContainer.className = "browserSidebarContainer";
browserSidebarContainer.appendChild(browserContainer);
browserSidebarContainer.setAttribute("flex", "1");
// Add the Message and the Browser to the box
var notificationbox = document.createElementNS(NS_XUL,
"notificationbox");
notificationbox.setAttribute("flex", "1");
notificationbox.appendChild(browserSidebarContainer);
let notificationbox = this.getNotificationBox(b);
var position = this.tabs.length - 1; var position = this.tabs.length - 1;
var uniqueId = this._generateUniquePanelID(); var uniqueId = this._generateUniquePanelID();
notificationbox.id = uniqueId; notificationbox.id = uniqueId;
@ -1642,19 +1738,16 @@
t.lastAccessed = Date.now(); t.lastAccessed = Date.now();
this.tabContainer._setPositionalAttributes(); this.tabContainer._setPositionalAttributes();
// Prevent the superfluous initial load of a blank document // Inject the <browser> into the DOM if necessary.
// if we're going to load something other than about:blank. if (!notificationbox.parentNode) {
if (!uriIsAboutBlank) { // NB: this appendChild call causes us to run constructors for the
b.setAttribute("nodefaultsrc", "true"); // browser element, which fires off a bunch of notifications. Some
// of those notifications can cause code to run that inspects our
// state, so it is important that the tab element is fully
// initialized by this point.
this.mPanelContainer.appendChild(notificationbox);
} }
// NB: this appendChild call causes us to run constructors for the
// browser element, which fires off a bunch of notifications. Some
// of those notifications can cause code to run that inspects our
// state, so it is important that the tab element is fully
// initialized by this point.
this.mPanelContainer.appendChild(notificationbox);
// We've waited until the tab is in the DOM to set the label. This // We've waited until the tab is in the DOM to set the label. This
// allows the TabLabelModified event to be properly dispatched. // allows the TabLabelModified event to be properly dispatched.
if (!aURI || isBlankPageURL(aURI)) { if (!aURI || isBlankPageURL(aURI)) {
@ -1677,16 +1770,9 @@
b.droppedLinkHandler = handleDroppedLink; b.droppedLinkHandler = handleDroppedLink;
// If we just created a new tab that loads the default // Swap in a preloaded customize tab, if available.
// newtab url, swap in a preloaded page if possible. if (aURI == "about:customizing") {
// Do nothing if we're a private window. usingPreloadedContent = gCustomizationTabPreloader.newTab(t);
let docShellsSwapped = false;
if (aURI == BROWSER_NEW_TAB_URL &&
!PrivateBrowsingUtils.isWindowPrivate(window) &&
!gMultiProcessBrowser) {
docShellsSwapped = gBrowserNewTabPreloader.newTab(t);
} else if (aURI == "about:customizing") {
docShellsSwapped = gCustomizationTabPreloader.newTab(t);
} }
// Dispatch a new tab notification. We do this once we're // Dispatch a new tab notification. We do this once we're
@ -1698,7 +1784,7 @@
// If we didn't swap docShells with a preloaded browser // If we didn't swap docShells with a preloaded browser
// then let's just continue loading the page normally. // then let's just continue loading the page normally.
if (!docShellsSwapped && !uriIsAboutBlank) { if (!usingPreloadedContent && !uriIsAboutBlank) {
// pretend the user typed this so it'll be available till // pretend the user typed this so it'll be available till
// the document successfully loads // the document successfully loads
if (aURI && gInitialPages.indexOf(aURI) == -1) if (aURI && gInitialPages.indexOf(aURI) == -1)
@ -4279,6 +4365,9 @@
// without any scrolling and when the tabbar has already // without any scrolling and when the tabbar has already
// overflowed. // overflowed.
this.mTabstrip._updateScrollButtonsDisabledState(); this.mTabstrip._updateScrollButtonsDisabledState();
// Preload the next about:newtab if there isn't one already.
this.tabbrowser._createPreloadBrowser();
]]></body> ]]></body>
</method> </method>

View File

@ -2,6 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */ * http://creativecommons.org/publicdomain/zero/1.0/ */
const STATE_CHANGED_TOPIC = "fxa-migration:state-changed"; const STATE_CHANGED_TOPIC = "fxa-migration:state-changed";
const NOTIFICATION_TITLE = "fxa-migration";
let imports = {}; let imports = {};
Cu.import("resource://services-sync/FxaMigrator.jsm", imports); Cu.import("resource://services-sync/FxaMigrator.jsm", imports);
@ -9,30 +10,42 @@ Cu.import("resource://services-sync/FxaMigrator.jsm", imports);
add_task(function* test() { add_task(function* test() {
// Fake the state where we need an FxA user. // Fake the state where we need an FxA user.
let buttonPromise = promiseButtonMutation(); let buttonPromise = promiseButtonMutation();
Services.obs.notifyObservers(null, "fxa-migration:state-changed", Services.obs.notifyObservers(null, STATE_CHANGED_TOPIC,
fxaMigrator.STATE_USER_FXA); fxaMigrator.STATE_USER_FXA);
let buttonState = yield buttonPromise; let buttonState = yield buttonPromise;
assertButtonState(buttonState, "migrate-signup", true); assertButtonState(buttonState, "migrate-signup", true);
Assert.ok(Weave.Notifications.notifications.some(n => {
return n.title == NOTIFICATION_TITLE;
}), "Needs-user notification should be present");
// Fake the state where we need a verified FxA user. // Fake the state where we need a verified FxA user.
buttonPromise = promiseButtonMutation(); buttonPromise = promiseButtonMutation();
let email = Cc["@mozilla.org/supports-string;1"]. let email = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString); createInstance(Ci.nsISupportsString);
email.data = "foo@example.com"; email.data = "foo@example.com";
Services.obs.notifyObservers(email, "fxa-migration:state-changed", Services.obs.notifyObservers(email, STATE_CHANGED_TOPIC,
fxaMigrator.STATE_USER_FXA_VERIFIED); fxaMigrator.STATE_USER_FXA_VERIFIED);
buttonState = yield buttonPromise; buttonState = yield buttonPromise;
assertButtonState(buttonState, "migrate-verify", true, assertButtonState(buttonState, "migrate-verify", true,
"foo@example.com not verified"); "foo@example.com not verified");
let note = Weave.Notifications.notifications.find(n => {
return n.title == NOTIFICATION_TITLE;
});
Assert.ok(!!note, "Needs-verification notification should be present");
Assert.ok(note.description.contains(email.data),
"Needs-verification notification should include email");
// Fake the state where no migration is needed. // Fake the state where no migration is needed.
buttonPromise = promiseButtonMutation(); buttonPromise = promiseButtonMutation();
Services.obs.notifyObservers(null, "fxa-migration:state-changed", null); Services.obs.notifyObservers(null, STATE_CHANGED_TOPIC, null);
buttonState = yield buttonPromise; buttonState = yield buttonPromise;
// In this case, the front end has called fxAccounts.getSignedInUser() to // In this case, the front end has called fxAccounts.getSignedInUser() to
// update the button label and status. But since there isn't actually a user, // update the button label and status. But since there isn't actually a user,
// the button is left with no fxastatus. // the button is left with no fxastatus.
assertButtonState(buttonState, "", true); assertButtonState(buttonState, "", true);
Assert.ok(!Weave.Notifications.notifications.some(n => {
return n.title == NOTIFICATION_TITLE;
}), "Migration notifications should no longer be present");
}); });
function assertButtonState(buttonState, expectedStatus, expectedVisible, function assertButtonState(buttonState, expectedStatus, expectedVisible,

View File

@ -11,7 +11,6 @@ const CAPTURE_PREF = "browser.pagethumbnails.capturing_disabled";
function runTests() { function runTests() {
let imports = {}; let imports = {};
Cu.import("resource://gre/modules/PageThumbs.jsm", imports); Cu.import("resource://gre/modules/PageThumbs.jsm", imports);
Cu.import("resource:///modules/BrowserNewTabPreloader.jsm", imports);
// Disable captures. // Disable captures.
let originalDisabledState = Services.prefs.getBoolPref(CAPTURE_PREF); let originalDisabledState = Services.prefs.getBoolPref(CAPTURE_PREF);
@ -31,32 +30,15 @@ function runTests() {
yield setLinks("-1"); yield setLinks("-1");
// We need a handle to a hidden, pre-loaded newtab so we can verify that it // We need a handle to a hidden, pre-loaded newtab so we can verify that it
// doesn't allow background captures. Add a newtab, which triggers creation // doesn't allow background captures. Ensure we have a preloaded browser.
// of a hidden newtab, and then keep calling BrowserNewTabPreloader.newTab gBrowser._createPreloadBrowser();
// until it returns true, meaning that it swapped the passed-in tab's docshell
// for the hidden newtab docshell.
let tab = gWindow.gBrowser.addTab("about:blank");
yield addNewTabPageTab();
// When newtab is loaded very quickly (which is what happens in 99% of cases) // Wait for the preloaded browser to load.
// there is no need to wait so no tests are run. Because each test requires yield waitForBrowserLoad(gBrowser._preloadedBrowser);
// either a pass, fail or todo we run a dummy test here.
ok(true, "Each test requires at least one pass, fail or todo so here is a pass.");
let swapWaitCount = 0; // We're now ready to use the preloaded browser.
let swapped = imports.BrowserNewTabPreloader.newTab(tab); BrowserOpenTab();
while (!swapped) { let tab = gBrowser.selectedTab;
if (++swapWaitCount == 10) {
ok(false, "Timed out waiting for newtab docshell swap.");
return;
}
// Give the hidden newtab some time to finish loading.
yield wait(2000);
info("Checking newtab swap " + swapWaitCount);
swapped = imports.BrowserNewTabPreloader.newTab(tab);
}
// The tab's docshell is now the previously hidden newtab docshell.
let doc = tab.linkedBrowser.contentDocument; let doc = tab.linkedBrowser.contentDocument;
// Enable captures. // Enable captures.
@ -67,8 +49,11 @@ function runTests() {
if (data != url) if (data != url)
return; return;
Services.obs.removeObserver(onCreate, "page-thumbnail:create"); Services.obs.removeObserver(onCreate, "page-thumbnail:create");
ok(true, "thumbnail created after preloaded tab was shown");
// Test finished! // Test finished!
Services.prefs.setBoolPref(CAPTURE_PREF, originalDisabledState); Services.prefs.setBoolPref(CAPTURE_PREF, originalDisabledState);
gBrowser.removeTab(tab);
file.remove(false); file.remove(false);
TestRunner.next(); TestRunner.next();
}, "page-thumbnail:create", false); }, "page-thumbnail:create", false);
@ -76,7 +61,3 @@ function runTests() {
info("Waiting for thumbnail capture"); info("Waiting for thumbnail capture");
yield true; yield true;
} }
function wait(ms) {
setTimeout(TestRunner.next, ms);
}

View File

@ -374,21 +374,27 @@ function addNewTabPageTabPromise() {
} }
} }
// The new tab page might have been preloaded in the background.
if (browser.contentDocument.readyState == "complete") {
waitForCondition(() => !browser.contentDocument.hidden).then(whenNewTabLoaded);
return deferred.promise;
}
// Wait for the new tab page to be loaded. // Wait for the new tab page to be loaded.
browser.addEventListener("load", function onLoad() { waitForBrowserLoad(browser, function () {
browser.removeEventListener("load", onLoad, true); // Wait for the document to become visible in case it was preloaded.
whenNewTabLoaded(); waitForCondition(() => !browser.contentDocument.hidden).then(whenNewTabLoaded);
}, true); });
return deferred.promise; return deferred.promise;
} }
function waitForBrowserLoad(browser, callback = TestRunner.next) {
if (browser.contentDocument.readyState == "complete") {
executeSoon(callback);
return;
}
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
executeSoon(callback);
}, true);
}
/** /**
* Compares the current grid arrangement with the given pattern. * Compares the current grid arrangement with the given pattern.
* @param the pattern (see below) * @param the pattern (see below)

View File

@ -828,9 +828,15 @@ let MozLoopServiceInternal = {
let window = chatbox.contentWindow; let window = chatbox.contentWindow;
window.addEventListener("unload", function onUnloadChat(evt) { function socialFrameChanged(eventName) {
UITour.notify("Loop:ChatWindowClosed"); UITour.availableTargetsCache.clear();
}); UITour.notify(eventName);
}
window.addEventListener("socialFrameHide", socialFrameChanged.bind(null, "Loop:ChatWindowHidden"));
window.addEventListener("socialFrameShow", socialFrameChanged.bind(null, "Loop:ChatWindowShown"));
window.addEventListener("socialFrameDetached", socialFrameChanged.bind(null, "Loop:ChatWindowDetached"));
window.addEventListener("unload", socialFrameChanged.bind(null, "Loop:ChatWindowClosed"));
injectLoopAPI(window); injectLoopAPI(window);

View File

@ -53,9 +53,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils", XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm"); "resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserNewTabPreloader",
"resource:///modules/BrowserNewTabPreloader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader", XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm"); "resource:///modules/CustomizationTabPreloader.jsm");
@ -791,7 +788,6 @@ BrowserGlue.prototype = {
Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e); Cu.reportError("Could not end startup crash tracking in quit-application-granted: " + e);
} }
BrowserNewTabPreloader.uninit();
CustomizationTabPreloader.uninit(); CustomizationTabPreloader.uninit();
WebappManager.uninit(); WebappManager.uninit();
#ifdef NIGHTLY_BUILD #ifdef NIGHTLY_BUILD

View File

@ -1,7 +1,19 @@
# LOCALIZATION NOTE (needUser) # This Source Code Form is subject to the terms of the Mozilla Public
# %S = Firefox Accounts brand name from syncBrand.dtd # License, v. 2.0. If a copy of the MPL was not distributed with this
needUser = %S required for sync # file, You can obtain one at http://mozilla.org/MPL/2.0/.
# LOCALIZATION NOTE (needVerifiedUser) # LOCALIZATION NOTE (needUserShort)
# %S = Firefox Accounts brand name from syncBrand.dtd
needUserShort = %S required for sync
needUserLong = We've rebuilt Sync to make it easier for everyone. Please upgrade to a Firefox Account to continue syncing.
upgradeToFxA.label = Upgrade
upgradeToFxA.accessKey = U
# LOCALIZATION NOTE (needVerifiedUserShort, needVerifiedUserLong)
# %S = Email address of user's Firefox Account # %S = Email address of user's Firefox Account
needVerifiedUser = %S not verified needVerifiedUserShort = %S not verified
needVerifiedUserLong = Please click the verification link in the email sent to %S
resendVerificationEmail.label = Resend
resendVerificationEmail.accessKey = R

View File

@ -1,379 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["BrowserNewTabPreloader"];
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
const HTML_NS = "http://www.w3.org/1999/xhtml";
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const XUL_PAGE = "data:application/vnd.mozilla.xul+xml;charset=utf-8,<window%20id='win'/>";
const NEWTAB_URL = "about:newtab";
const PREF_NEWTAB_URL = "browser.newtab.url";
const PREF_NEWTAB_PRELOAD = "browser.newtab.preload";
// The interval between swapping in a preload docShell and kicking off the
// next preload in the background.
const PRELOADER_INTERVAL_MS = 600;
// The number of miliseconds we'll wait after we received a notification that
// causes us to update our list of browsers and tabbrowser sizes. This acts as
// kind of a damper when too many events are occuring in quick succession.
const PRELOADER_UPDATE_DELAY_MS = 3000;
const TOPIC_TIMER_CALLBACK = "timer-callback";
const TOPIC_DELAYED_STARTUP = "browser-delayed-startup-finished";
const TOPIC_XUL_WINDOW_CLOSED = "xul-window-destroyed";
const BROWSER_CONTENT_SCRIPT = "chrome://browser/content/content.js";
function isPreloadingEnabled() {
return Services.prefs.getBoolPref(PREF_NEWTAB_PRELOAD) &&
!Services.prefs.prefHasUserValue(PREF_NEWTAB_URL);
}
function createTimer(obj, delay) {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.init(obj, delay, Ci.nsITimer.TYPE_ONE_SHOT);
return timer;
}
function clearTimer(timer) {
if (timer) {
timer.cancel();
}
return null;
}
this.BrowserNewTabPreloader = {
uninit: function Preloader_uninit() {
HostFrame.destroy();
HiddenBrowsers.uninit();
},
newTab: function Preloader_newTab(aTab) {
if (!isPreloadingEnabled()) {
return false;
}
let win = aTab.ownerDocument.defaultView;
if (win.gBrowser) {
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
let {width, height} = utils.getBoundsWithoutFlushing(win.gBrowser);
let hiddenBrowser = HiddenBrowsers.get(width, height)
if (hiddenBrowser) {
return hiddenBrowser.swapWithNewTab(aTab);
}
}
return false;
}
};
Object.freeze(BrowserNewTabPreloader);
let HiddenBrowsers = {
_browsers: null,
_updateTimer: null,
_topics: [
TOPIC_DELAYED_STARTUP,
TOPIC_XUL_WINDOW_CLOSED
],
_init: function () {
this._browsers = new Map();
this._updateBrowserSizes();
this._topics.forEach(t => Services.obs.addObserver(this, t, false));
},
uninit: function () {
if (this._browsers) {
this._topics.forEach(t => Services.obs.removeObserver(this, t, false));
this._updateTimer = clearTimer(this._updateTimer);
for (let [key, browser] of this._browsers) {
browser.destroy();
}
this._browsers = null;
}
},
get: function (width, height) {
// Initialize if this is the first call.
if (!this._browsers) {
this._init();
}
let key = width + "x" + height;
if (!this._browsers.has(key)) {
// Update all browsers' sizes if we can't find a matching one.
this._updateBrowserSizes();
}
// We should now have a matching browser.
if (this._browsers.has(key)) {
return this._browsers.get(key);
}
// We should never be here. Return the first browser we find.
Cu.reportError("NewTabPreloader: no matching browser found after updating");
for (let [size, browser] of this._browsers) {
return browser;
}
// We should really never be here.
Cu.reportError("NewTabPreloader: not even a single browser was found?");
return null;
},
observe: function (subject, topic, data) {
if (topic === TOPIC_TIMER_CALLBACK) {
this._updateTimer = null;
this._updateBrowserSizes();
} else {
this._updateTimer = clearTimer(this._updateTimer);
this._updateTimer = createTimer(this, PRELOADER_UPDATE_DELAY_MS);
}
},
_updateBrowserSizes: function () {
let sizes = this._collectTabBrowserSizes();
let toRemove = [];
// Iterate all browsers and check that they
// each can be assigned to one of the sizes.
for (let [key, browser] of this._browsers) {
if (sizes.has(key)) {
// We already have a browser for that size, great!
sizes.delete(key);
} else {
// This browser is superfluous or needs to be resized.
toRemove.push(browser);
this._browsers.delete(key);
}
}
// Iterate all sizes that we couldn't find a browser for.
for (let [key, {width, height}] of sizes) {
let browser;
if (toRemove.length) {
// Let's just resize one of the superfluous
// browsers and put it back into the map.
browser = toRemove.shift();
browser.resize(width, height);
} else {
// No more browsers to reuse, create a new one.
browser = new HiddenBrowser(width, height);
}
this._browsers.set(key, browser);
}
// Finally, remove all browsers we don't need anymore.
toRemove.forEach(b => b.destroy());
},
_collectTabBrowserSizes: function () {
let sizes = new Map();
function tabBrowserBounds() {
let wins = Services.ww.getWindowEnumerator("navigator:browser");
while (wins.hasMoreElements()) {
let win = wins.getNext();
if (win.gBrowser) {
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
yield utils.getBoundsWithoutFlushing(win.gBrowser);
}
}
}
// Collect the sizes of all <tabbrowser>s out there.
for (let {width, height} of tabBrowserBounds()) {
if (width > 0 && height > 0) {
let key = width + "x" + height;
if (!sizes.has(key)) {
sizes.set(key, {width: width, height: height});
}
}
}
return sizes;
}
};
function HiddenBrowser(width, height) {
this.resize(width, height);
this._createBrowser();
}
HiddenBrowser.prototype = {
_width: null,
_height: null,
_timer: null,
get isPreloaded() {
return this._browser &&
this._browser.contentDocument &&
this._browser.contentDocument.readyState === "complete" &&
this._browser.currentURI.spec === NEWTAB_URL;
},
swapWithNewTab: function (aTab) {
if (!this.isPreloaded || this._timer) {
return false;
}
let win = aTab.ownerDocument.defaultView;
let tabbrowser = win.gBrowser;
if (!tabbrowser) {
return false;
}
// Swap docShells.
tabbrowser.swapNewTabWithBrowser(aTab, this._browser);
// Load all delayed frame scripts attached to the "browers" message manager.
// The browser content script was already loaded, so don't load it again.
let mm = aTab.linkedBrowser.messageManager;
let scripts = win.getGroupMessageManager("browsers").getDelayedFrameScripts();
Array.forEach(scripts, ([script, runGlobal]) => {
if (script != BROWSER_CONTENT_SCRIPT) {
mm.loadFrameScript(script, true, runGlobal);
}
});
// Remove the browser, it will be recreated by a timer.
this._removeBrowser();
// Start a timer that will kick off preloading the next newtab page.
this._timer = createTimer(this, PRELOADER_INTERVAL_MS);
// Signal that we swapped docShells.
return true;
},
observe: function () {
this._timer = null;
// Start pre-loading the new tab page.
this._createBrowser();
},
resize: function (width, height) {
this._width = width;
this._height = height;
this._applySize();
},
destroy: function () {
this._removeBrowser();
this._timer = clearTimer(this._timer);
},
_applySize: function () {
if (this._browser) {
this._browser.style.width = this._width + "px";
this._browser.style.height = this._height + "px";
}
},
_createBrowser: function () {
HostFrame.get().then(aFrame => {
let doc = aFrame.document;
this._browser = doc.createElementNS(XUL_NS, "browser");
this._browser.setAttribute("type", "content");
this._browser.setAttribute("src", NEWTAB_URL);
this._applySize();
doc.getElementById("win").appendChild(this._browser);
// The browser might not have a docShell here if the HostFrame was
// destroyed while the promise was resolved. Simply bail out.
if (!this._browser.docShell) {
return;
}
// Let the docShell be inactive so that document.hidden=true.
this._browser.docShell.isActive = false;
this._browser.messageManager.loadFrameScript(BROWSER_CONTENT_SCRIPT,
true);
});
},
_removeBrowser: function () {
if (this._browser) {
this._browser.remove();
this._browser = null;
}
}
};
let HostFrame = {
_frame: null,
_deferred: null,
get hiddenDOMDocument() {
return Services.appShell.hiddenDOMWindow.document;
},
get isReady() {
return this.hiddenDOMDocument.readyState === "complete";
},
get: function () {
if (!this._deferred) {
this._deferred = Promise.defer();
this._create();
}
return this._deferred.promise;
},
destroy: function () {
if (this._frame) {
if (!Cu.isDeadWrapper(this._frame)) {
this._frame.removeEventListener("load", this, true);
this._frame.remove();
}
this._frame = null;
this._deferred = null;
}
},
handleEvent: function () {
let contentWindow = this._frame.contentWindow;
if (contentWindow.location.href === XUL_PAGE) {
this._frame.removeEventListener("load", this, true);
this._deferred.resolve(contentWindow);
} else {
contentWindow.location = XUL_PAGE;
}
},
_create: function () {
if (this.isReady) {
let doc = this.hiddenDOMDocument;
this._frame = doc.createElementNS(HTML_NS, "iframe");
this._frame.addEventListener("load", this, true);
doc.documentElement.appendChild(this._frame);
} else {
let flags = Ci.nsIThread.DISPATCH_NORMAL;
Services.tm.currentThread.dispatch(() => this._create(), flags);
}
}
};

View File

@ -142,6 +142,16 @@ this.UITour = {
return loopBrowser.contentDocument.querySelector(".room-list"); return loopBrowser.contentDocument.querySelector(".room-list");
}, },
}], }],
["loop-selectedRoomButtons", {
infoPanelPosition: "leftcenter bottomright",
query: (aDocument) => {
let chatbox = aDocument.querySelector("chatbox[src^='about\:loopconversation'][selected]");
if (!chatbox || !chatbox.contentDocument) {
return null;
}
return chatbox.contentDocument.querySelector(".call-action-group");
},
}],
["loop-signInUpLink", { ["loop-signInUpLink", {
query: (aDocument) => { query: (aDocument) => {
let loopBrowser = aDocument.querySelector("#loop-notification-panel > #loop"); let loopBrowser = aDocument.querySelector("#loop-notification-panel > #loop");
@ -1375,8 +1385,7 @@ this.UITour = {
hideLoopPanelAnnotations: function(aEvent) { hideLoopPanelAnnotations: function(aEvent) {
UITour.hideAnnotationsForPanel(aEvent, (aTarget) => { UITour.hideAnnotationsForPanel(aEvent, (aTarget) => {
// TODO: Bug 1104927 - Handle the conversation targets separately. return aTarget.targetName.startsWith("loop-") && aTarget.targetName != "loop-selectedRoomButtons";
return aTarget.targetName.startsWith("loop-");
}); });
}, },

View File

@ -11,7 +11,6 @@ XPCSHELL_TESTS_MANIFESTS += [
] ]
EXTRA_JS_MODULES += [ EXTRA_JS_MODULES += [
'BrowserNewTabPreloader.jsm',
'BrowserUITelemetry.jsm', 'BrowserUITelemetry.jsm',
'CastingApps.jsm', 'CastingApps.jsm',
'Chat.jsm', 'Chat.jsm',

View File

@ -90,9 +90,12 @@ let tests = [
gContentAPI.observe((event, params) => { gContentAPI.observe((event, params) => {
is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification"); is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
gContentAPI.observe((event, params) => { gContentAPI.observe((event, params) => {
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification"); is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
gContentAPI.observe((event, params) => { gContentAPI.observe((event, params) => {
ok(false, "No more notifications should have arrived"); is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
gContentAPI.observe((event, params) => {
ok(false, "No more notifications should have arrived");
});
}); });
done(); done();
}); });

View File

@ -122,4 +122,10 @@ LoadInfo::GetBaseURI(nsIURI** aBaseURI)
return NS_OK; return NS_OK;
} }
nsIURI*
LoadInfo::BaseURI()
{
return mBaseURI;
}
} // namespace mozilla } // namespace mozilla

View File

@ -17,7 +17,7 @@ typedef unsigned long nsSecurityFlags;
/** /**
* An nsILoadOwner represents per-load information about who started the load. * An nsILoadOwner represents per-load information about who started the load.
*/ */
[scriptable, builtinclass, uuid(da363267-236d-49bf-83a2-33da8d892728)] [scriptable, builtinclass, uuid(768a1f20-57d4-462a-812a-41c04e5d1e19)]
interface nsILoadInfo : nsISupports interface nsILoadInfo : nsISupports
{ {
/** /**
@ -156,7 +156,7 @@ interface nsILoadInfo : nsISupports
* The contentPolicyType of the channel, used for security checks * The contentPolicyType of the channel, used for security checks
* like Mixed Content Blocking and Content Security Policy. * like Mixed Content Blocking and Content Security Policy.
*/ */
readonly attribute nsContentPolicyType contentPolicyType; readonly attribute nsContentPolicyType contentPolicyType;
%{ C++ %{ C++
inline nsContentPolicyType GetContentPolicyType() inline nsContentPolicyType GetContentPolicyType()
@ -173,5 +173,11 @@ interface nsILoadInfo : nsISupports
* This attribute may be null. The value of this attribute may be * This attribute may be null. The value of this attribute may be
* ignored if the base URI can be inferred by the channel's URI. * ignored if the base URI can be inferred by the channel's URI.
*/ */
readonly attribute nsIURI baseURI; readonly attribute nsIURI baseURI;
/**
* A C++-friendly version of baseURI.
*/
[noscript, notxpcom, nostdcall, binaryname(BaseURI)]
nsIURI binaryBaseURI();
}; };

View File

@ -56,6 +56,37 @@ namespace mozilla {
namespace dom { namespace dom {
namespace indexedDB { namespace indexedDB {
/*******************************************************************************
* ThreadLocal
******************************************************************************/
ThreadLocal::ThreadLocal(const nsID& aBackgroundChildLoggingId)
: mLoggingInfo(aBackgroundChildLoggingId, 1, -1, 1)
, mCurrentTransaction(0)
#ifdef DEBUG
, mOwningThread(PR_GetCurrentThread())
#endif
{
MOZ_ASSERT(mOwningThread);
MOZ_COUNT_CTOR(mozilla::dom::indexedDB::ThreadLocal);
}
ThreadLocal::~ThreadLocal()
{
MOZ_COUNT_DTOR(mozilla::dom::indexedDB::ThreadLocal);
}
#ifdef DEBUG
void
ThreadLocal::AssertIsOnOwningThread() const
{
MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread);
}
#endif // DEBUG
/******************************************************************************* /*******************************************************************************
* Helpers * Helpers
******************************************************************************/ ******************************************************************************/
@ -104,39 +135,40 @@ class MOZ_STACK_CLASS AutoSetCurrentTransaction MOZ_FINAL
IDBTransaction* const mTransaction; IDBTransaction* const mTransaction;
IDBTransaction* mPreviousTransaction; IDBTransaction* mPreviousTransaction;
IDBTransaction** mThreadLocalSlot; ThreadLocal* mThreadLocal;
public: public:
explicit AutoSetCurrentTransaction(IDBTransaction* aTransaction) explicit AutoSetCurrentTransaction(IDBTransaction* aTransaction)
: mTransaction(aTransaction) : mTransaction(aTransaction)
, mPreviousTransaction(nullptr) , mPreviousTransaction(nullptr)
, mThreadLocalSlot(nullptr) , mThreadLocal(nullptr)
{ {
if (aTransaction) { if (aTransaction) {
BackgroundChildImpl::ThreadLocal* threadLocal = BackgroundChildImpl::ThreadLocal* threadLocal =
BackgroundChildImpl::GetThreadLocalForCurrentThread(); BackgroundChildImpl::GetThreadLocalForCurrentThread();
MOZ_ASSERT(threadLocal); MOZ_ASSERT(threadLocal);
// Hang onto this location for resetting later. // Hang onto this for resetting later.
mThreadLocalSlot = &threadLocal->mCurrentTransaction; mThreadLocal = threadLocal->mIndexedDBThreadLocal;
MOZ_ASSERT(mThreadLocal);
// Save the current value. // Save the current value.
mPreviousTransaction = *mThreadLocalSlot; mPreviousTransaction = mThreadLocal->GetCurrentTransaction();
// Set the new value. // Set the new value.
*mThreadLocalSlot = aTransaction; mThreadLocal->SetCurrentTransaction(aTransaction);
} }
} }
~AutoSetCurrentTransaction() ~AutoSetCurrentTransaction()
{ {
MOZ_ASSERT_IF(mThreadLocalSlot, mTransaction); MOZ_ASSERT_IF(mThreadLocal, mTransaction);
MOZ_ASSERT_IF(mThreadLocal,
if (mThreadLocalSlot) { mThreadLocal->GetCurrentTransaction() == mTransaction);
MOZ_ASSERT(*mThreadLocalSlot == mTransaction);
if (mThreadLocal) {
// Reset old value. // Reset old value.
*mThreadLocalSlot = mPreviousTransaction; mThreadLocal->SetCurrentTransaction(mPreviousTransaction);
} }
} }
@ -589,6 +621,25 @@ DispatchErrorEvent(IDBRequest* aRequest,
asct.emplace(aTransaction); asct.emplace(aTransaction);
} }
if (transaction) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"Firing %s event with error 0x%x",
"IndexedDB %s: C T[%lld] R[%llu]: %s (0x%x)",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(aEvent, kErrorEventType),
aErrorCode);
} else {
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: "
"Firing %s event with error 0x%x",
"IndexedDB %s: C R[%llu]: %s (0x%x)",
IDB_LOG_ID_STRING(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(aEvent, kErrorEventType),
aErrorCode);
}
bool doDefault; bool doDefault;
nsresult rv = request->DispatchEvent(aEvent, &doDefault); nsresult rv = request->DispatchEvent(aEvent, &doDefault);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
@ -648,6 +699,22 @@ DispatchSuccessEvent(ResultHelper* aResultHelper,
MOZ_ASSERT(aEvent); MOZ_ASSERT(aEvent);
MOZ_ASSERT_IF(transaction, transaction->IsOpen()); MOZ_ASSERT_IF(transaction, transaction->IsOpen());
if (transaction) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"Firing %s event",
"IndexedDB %s: C T[%lld] R[%llu]: %s",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: Firing %s event",
"IndexedDB %s: C R[%llu]: %s",
IDB_LOG_ID_STRING(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
}
bool dummy; bool dummy;
nsresult rv = request->DispatchEvent(aEvent, &dummy); nsresult rv = request->DispatchEvent(aEvent, &dummy);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
@ -1068,6 +1135,11 @@ BackgroundFactoryRequestChild::RecvBlocked(const uint64_t& aCurrentVersion)
nsRefPtr<IDBRequest> kungFuDeathGrip = mRequest; nsRefPtr<IDBRequest> kungFuDeathGrip = mRequest;
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: Firing \"blocked\" event",
"IndexedDB %s: C R[%llu]: \"blocked\"",
IDB_LOG_ID_STRING(),
mRequest->LoggingSerialNumber());
bool dummy; bool dummy;
if (NS_FAILED(mRequest->DispatchEvent(blockedEvent, &dummy))) { if (NS_FAILED(mRequest->DispatchEvent(blockedEvent, &dummy))) {
NS_WARNING("Failed to dispatch event!"); NS_WARNING("Failed to dispatch event!");
@ -1357,6 +1429,10 @@ BackgroundDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
return false; return false;
} }
IDB_LOG_MARK("IndexedDB %s: Child : Firing \"versionchange\" event",
"IndexedDB %s: C: IDBDatabase \"versionchange\" event",
IDB_LOG_ID_STRING());
bool dummy; bool dummy;
if (NS_FAILED(mDatabase->DispatchEvent(versionChangeEvent, &dummy))) { if (NS_FAILED(mDatabase->DispatchEvent(versionChangeEvent, &dummy))) {
NS_WARNING("Failed to dispatch event!"); NS_WARNING("Failed to dispatch event!");

View File

@ -5,6 +5,7 @@
#ifndef mozilla_dom_indexeddb_actorschild_h__ #ifndef mozilla_dom_indexeddb_actorschild_h__
#define mozilla_dom_indexeddb_actorschild_h__ #define mozilla_dom_indexeddb_actorschild_h__
#include "IDBTransaction.h"
#include "js/RootingAPI.h" #include "js/RootingAPI.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBCursorChild.h" #include "mozilla/dom/indexedDB/PBackgroundIDBCursorChild.h"
@ -12,6 +13,7 @@
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h" #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryRequestChild.h" #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryRequestChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBRequestChild.h" #include "mozilla/dom/indexedDB/PBackgroundIDBRequestChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBTransactionChild.h" #include "mozilla/dom/indexedDB/PBackgroundIDBTransactionChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionChild.h" #include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionChild.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
@ -19,6 +21,7 @@
#include "nsTArray.h" #include "nsTArray.h"
class nsIEventTarget; class nsIEventTarget;
struct nsID;
struct PRThread; struct PRThread;
namespace mozilla { namespace mozilla {
@ -38,13 +41,97 @@ class IDBFactory;
class IDBMutableFile; class IDBMutableFile;
class IDBOpenDBRequest; class IDBOpenDBRequest;
class IDBRequest; class IDBRequest;
class IDBTransaction;
class Key; class Key;
class PBackgroundIDBFileChild; class PBackgroundIDBFileChild;
class PermissionRequestChild; class PermissionRequestChild;
class PermissionRequestParent; class PermissionRequestParent;
class SerializedStructuredCloneReadInfo; class SerializedStructuredCloneReadInfo;
class ThreadLocal
{
friend class nsAutoPtr<ThreadLocal>;
friend class IDBFactory;
LoggingInfo mLoggingInfo;
IDBTransaction* mCurrentTransaction;
#ifdef DEBUG
PRThread* mOwningThread;
#endif
public:
void
AssertIsOnOwningThread() const
#ifdef DEBUG
;
#else
{ }
#endif
const LoggingInfo&
GetLoggingInfo() const
{
AssertIsOnOwningThread();
return mLoggingInfo;
}
const nsID&
Id() const
{
AssertIsOnOwningThread();
return mLoggingInfo.backgroundChildLoggingId();
}
int64_t
NextTransactionSN(IDBTransaction::Mode aMode)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mLoggingInfo.nextTransactionSerialNumber() < INT64_MAX);
MOZ_ASSERT(mLoggingInfo.nextVersionChangeTransactionSerialNumber() >
INT64_MIN);
if (aMode == IDBTransaction::VERSION_CHANGE) {
return mLoggingInfo.nextVersionChangeTransactionSerialNumber()--;
}
return mLoggingInfo.nextTransactionSerialNumber()++;
}
uint64_t
NextRequestSN()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mLoggingInfo.nextRequestSerialNumber() < UINT64_MAX);
return mLoggingInfo.nextRequestSerialNumber()++;
}
void
SetCurrentTransaction(IDBTransaction* aCurrentTransaction)
{
AssertIsOnOwningThread();
mCurrentTransaction = aCurrentTransaction;
}
IDBTransaction*
GetCurrentTransaction() const
{
AssertIsOnOwningThread();
return mCurrentTransaction;
}
private:
ThreadLocal(const nsID& aBackgroundChildLoggingId);
~ThreadLocal();
ThreadLocal() MOZ_DELETE;
ThreadLocal(const ThreadLocal& aOther) MOZ_DELETE;
};
class BackgroundFactoryChild MOZ_FINAL class BackgroundFactoryChild MOZ_FINAL
: public PBackgroundIDBFactoryChild : public PBackgroundIDBFactoryChild
{ {

View File

@ -107,6 +107,7 @@ namespace {
class Cursor; class Cursor;
class Database; class Database;
struct DatabaseActorInfo; struct DatabaseActorInfo;
class DatabaseLoggingInfo;
class DatabaseFile; class DatabaseFile;
class DatabaseOfflineStorage; class DatabaseOfflineStorage;
class Factory; class Factory;
@ -2553,17 +2554,14 @@ class DatabaseOperationBase
: public nsRunnable : public nsRunnable
, public mozIStorageProgressHandler , public mozIStorageProgressHandler
{ {
// Uniquely tracks each operation for logging purposes. Only modified on the
// PBackground thread.
static uint64_t sNextSerialNumber;
protected: protected:
class AutoSetProgressHandler; class AutoSetProgressHandler;
typedef nsDataHashtable<nsUint64HashKey, bool> UniqueIndexTable; typedef nsDataHashtable<nsUint64HashKey, bool> UniqueIndexTable;
nsCOMPtr<nsIEventTarget> mOwningThread; nsCOMPtr<nsIEventTarget> mOwningThread;
const uint64_t mSerialNumber; const nsID mBackgroundChildLoggingId;
const uint64_t mLoggingSerialNumber;
nsresult mResultCode; nsresult mResultCode;
private: private:
@ -2610,10 +2608,16 @@ public:
return mOperationMayProceed; return mOperationMayProceed;
} }
uint64_t const nsID&
SerialNumber() const BackgroundChildLoggingId() const
{ {
return mSerialNumber; return mBackgroundChildLoggingId;
}
uint64_t
LoggingSerialNumber() const
{
return mLoggingSerialNumber;
} }
nsresult nsresult
@ -2632,9 +2636,11 @@ public:
} }
protected: protected:
DatabaseOperationBase() DatabaseOperationBase(const nsID& aBackgroundChildLoggingId,
uint64_t aLoggingSerialNumber)
: mOwningThread(NS_GetCurrentThread()) : mOwningThread(NS_GetCurrentThread())
, mSerialNumber(++sNextSerialNumber) , mBackgroundChildLoggingId(aBackgroundChildLoggingId)
, mLoggingSerialNumber(aLoggingSerialNumber)
, mResultCode(NS_OK) , mResultCode(NS_OK)
, mOperationMayProceed(true) , mOperationMayProceed(true)
, mActorDestroyed(false) , mActorDestroyed(false)
@ -2709,6 +2715,7 @@ class TransactionDatabaseOperationBase
: public DatabaseOperationBase : public DatabaseOperationBase
{ {
nsRefPtr<TransactionBase> mTransaction; nsRefPtr<TransactionBase> mTransaction;
const int64_t mTransactionLoggingSerialNumber;
const bool mTransactionIsAborted; const bool mTransactionIsAborted;
public: public:
@ -2736,7 +2743,11 @@ public:
Cleanup(); Cleanup();
protected: protected:
explicit TransactionDatabaseOperationBase(TransactionBase* aTransaction); explicit
TransactionDatabaseOperationBase(TransactionBase* aTransaction);
TransactionDatabaseOperationBase(TransactionBase* aTransaction,
uint64_t aLoggingSerialNumber);
virtual virtual
~TransactionDatabaseOperationBase(); ~TransactionDatabaseOperationBase();
@ -2779,17 +2790,29 @@ class Factory MOZ_FINAL
// ActorDestroy called. // ActorDestroy called.
static uint64_t sFactoryInstanceCount; static uint64_t sFactoryInstanceCount;
nsRefPtr<DatabaseLoggingInfo> mLoggingInfo;
DebugOnly<bool> mActorDestroyed; DebugOnly<bool> mActorDestroyed;
public: public:
static already_AddRefed<Factory> static already_AddRefed<Factory>
Create(); Create(const LoggingInfo& aLoggingInfo);
DatabaseLoggingInfo*
GetLoggingInfo() const
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mLoggingInfo);
return mLoggingInfo;
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::Factory) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::Factory)
private: private:
// Only constructed in Create(). // Only constructed in Create().
explicit Factory(); explicit
Factory(already_AddRefed<DatabaseLoggingInfo> aLoggingInfo);
// Reference counted. // Reference counted.
~Factory(); ~Factory();
@ -2801,6 +2824,9 @@ private:
virtual bool virtual bool
RecvDeleteMe() MOZ_OVERRIDE; RecvDeleteMe() MOZ_OVERRIDE;
virtual bool
RecvIncrementLoggingRequestSerialNumber() MOZ_OVERRIDE;
virtual PBackgroundIDBFactoryRequestParent* virtual PBackgroundIDBFactoryRequestParent*
AllocPBackgroundIDBFactoryRequestParent(const FactoryRequestParams& aParams) AllocPBackgroundIDBFactoryRequestParent(const FactoryRequestParams& aParams)
MOZ_OVERRIDE; MOZ_OVERRIDE;
@ -2924,6 +2950,15 @@ public:
return Manager()->Manager(); return Manager()->Manager();
} }
DatabaseLoggingInfo*
GetLoggingInfo() const
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mFactory);
return mFactory->GetLoggingInfo();
}
bool bool
RegisterTransaction(TransactionBase* aTransaction); RegisterTransaction(TransactionBase* aTransaction);
@ -3130,6 +3165,7 @@ private:
mModifiedAutoIncrementObjectStoreMetadataArray; mModifiedAutoIncrementObjectStoreMetadataArray;
const uint64_t mTransactionId; const uint64_t mTransactionId;
const nsCString mDatabaseId; const nsCString mDatabaseId;
const int64_t mLoggingSerialNumber;
uint64_t mActiveRequestCount; uint64_t mActiveRequestCount;
Atomic<bool> mInvalidatedOnAnyThread; Atomic<bool> mInvalidatedOnAnyThread;
Mode mMode; Mode mMode;
@ -3248,6 +3284,21 @@ public:
return mDatabase; return mDatabase;
} }
DatabaseLoggingInfo*
GetLoggingInfo() const
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mDatabase);
return mDatabase->GetLoggingInfo();
}
int64_t
LoggingSerialNumber() const
{
return mLoggingSerialNumber;
}
bool bool
IsAborted() const IsAborted() const
{ {
@ -3297,8 +3348,7 @@ public:
Invalidate(); Invalidate();
protected: protected:
TransactionBase(Database* aDatabase, TransactionBase(Database* aDatabase, Mode aMode);
Mode aMode);
virtual virtual
~TransactionBase(); ~TransactionBase();
@ -3420,13 +3470,7 @@ class TransactionBase::CommitOp MOZ_FINAL
nsresult mResultCode; nsresult mResultCode;
private: private:
CommitOp(TransactionBase* aTransaction, CommitOp(TransactionBase* aTransaction, nsresult aResultCode);
nsresult aResultCode)
: mTransaction(aTransaction)
, mResultCode(aResultCode)
{
MOZ_ASSERT(aTransaction);
}
~CommitOp() ~CommitOp()
{ } { }
@ -3670,8 +3714,8 @@ class NormalTransaction MOZ_FINAL
private: private:
// This constructor is only called by Database. // This constructor is only called by Database.
NormalTransaction(Database* aDatabase, NormalTransaction(Database* aDatabase,
nsTArray<nsRefPtr<FullObjectStoreMetadata>>& aObjectStores, TransactionBase::Mode aMode,
TransactionBase::Mode aMode); nsTArray<nsRefPtr<FullObjectStoreMetadata>>& aObjectStores);
// Reference counted. // Reference counted.
~NormalTransaction() ~NormalTransaction()
@ -4133,9 +4177,11 @@ class OpenDatabaseOp::VersionChangeOp MOZ_FINAL
uint64_t mPreviousVersion; uint64_t mPreviousVersion;
private: private:
explicit VersionChangeOp(OpenDatabaseOp* aOpenDatabaseOp) explicit
VersionChangeOp(OpenDatabaseOp* aOpenDatabaseOp)
: TransactionDatabaseOperationBase( : TransactionDatabaseOperationBase(
aOpenDatabaseOp->mVersionChangeTransaction) aOpenDatabaseOp->mVersionChangeTransaction,
aOpenDatabaseOp->LoggingSerialNumber())
, mOpenDatabaseOp(aOpenDatabaseOp) , mOpenDatabaseOp(aOpenDatabaseOp)
, mRequestedVersion(aOpenDatabaseOp->mRequestedVersion) , mRequestedVersion(aOpenDatabaseOp->mRequestedVersion)
, mPreviousVersion(aOpenDatabaseOp->mMetadata->mCommonMetadata.version()) , mPreviousVersion(aOpenDatabaseOp->mMetadata->mCommonMetadata.version())
@ -4214,8 +4260,11 @@ class DeleteDatabaseOp::VersionChangeOp MOZ_FINAL
nsRefPtr<DeleteDatabaseOp> mDeleteDatabaseOp; nsRefPtr<DeleteDatabaseOp> mDeleteDatabaseOp;
private: private:
explicit VersionChangeOp(DeleteDatabaseOp* aDeleteDatabaseOp) explicit
: mDeleteDatabaseOp(aDeleteDatabaseOp) VersionChangeOp(DeleteDatabaseOp* aDeleteDatabaseOp)
: DatabaseOperationBase(aDeleteDatabaseOp->BackgroundChildLoggingId(),
aDeleteDatabaseOp->LoggingSerialNumber())
, mDeleteDatabaseOp(aDeleteDatabaseOp)
{ {
MOZ_ASSERT(aDeleteDatabaseOp); MOZ_ASSERT(aDeleteDatabaseOp);
MOZ_ASSERT(!aDeleteDatabaseOp->mDatabaseDirectoryPath.IsEmpty()); MOZ_ASSERT(!aDeleteDatabaseOp->mDatabaseDirectoryPath.IsEmpty());
@ -4991,7 +5040,7 @@ private:
* Other class declarations * Other class declarations
******************************************************************************/ ******************************************************************************/
struct DatabaseActorInfo struct DatabaseActorInfo MOZ_FINAL
{ {
friend class nsAutoPtr<DatabaseActorInfo>; friend class nsAutoPtr<DatabaseActorInfo>;
@ -5021,6 +5070,60 @@ private:
} }
}; };
class DatabaseLoggingInfo MOZ_FINAL
{
#ifdef DEBUG
// Just for potential warnings.
friend class Factory;
#endif
LoggingInfo mLoggingInfo;
public:
DatabaseLoggingInfo(const LoggingInfo& aLoggingInfo)
: mLoggingInfo(aLoggingInfo)
{
AssertIsOnBackgroundThread();
}
const nsID&
Id() const
{
AssertIsOnBackgroundThread();
return mLoggingInfo.backgroundChildLoggingId();
}
int64_t
NextTransactionSN(IDBTransaction::Mode aMode)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mLoggingInfo.nextTransactionSerialNumber() < INT64_MAX);
MOZ_ASSERT(mLoggingInfo.nextVersionChangeTransactionSerialNumber() >
INT64_MIN);
if (aMode == IDBTransaction::VERSION_CHANGE) {
return mLoggingInfo.nextVersionChangeTransactionSerialNumber()--;
}
return mLoggingInfo.nextTransactionSerialNumber()++;
}
uint64_t
NextRequestSN()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mLoggingInfo.nextRequestSerialNumber() < UINT64_MAX);
return mLoggingInfo.nextRequestSerialNumber()++;
}
NS_INLINE_DECL_REFCOUNTING(DatabaseLoggingInfo)
private:
~DatabaseLoggingInfo();
};
class NonMainThreadHackBlobImpl MOZ_FINAL class NonMainThreadHackBlobImpl MOZ_FINAL
: public FileImplFile : public FileImplFile
{ {
@ -5524,6 +5627,11 @@ StaticRefPtr<nsRunnable> gStartTransactionRunnable;
StaticRefPtr<TransactionThreadPool> gTransactionThreadPool; StaticRefPtr<TransactionThreadPool> gTransactionThreadPool;
typedef nsDataHashtable<nsIDHashKey, DatabaseLoggingInfo*>
DatabaseLoggingInfoHashtable;
StaticAutoPtr<DatabaseLoggingInfoHashtable> gLoggingInfoHashtable;
#ifdef DEBUG #ifdef DEBUG
StaticRefPtr<DEBUGThreadSlower> gDEBUGThreadSlower; StaticRefPtr<DEBUGThreadSlower> gDEBUGThreadSlower;
@ -5537,7 +5645,7 @@ StaticRefPtr<DEBUGThreadSlower> gDEBUGThreadSlower;
******************************************************************************/ ******************************************************************************/
PBackgroundIDBFactoryParent* PBackgroundIDBFactoryParent*
AllocPBackgroundIDBFactoryParent() AllocPBackgroundIDBFactoryParent(const LoggingInfo& aLoggingInfo)
{ {
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
@ -5545,12 +5653,15 @@ AllocPBackgroundIDBFactoryParent()
return nullptr; return nullptr;
} }
nsRefPtr<Factory> actor = Factory::Create(); nsRefPtr<Factory> actor = Factory::Create(aLoggingInfo);
MOZ_ASSERT(actor);
return actor.forget().take(); return actor.forget().take();
} }
bool bool
RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor) RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor,
const LoggingInfo& /* aLoggingInfo */)
{ {
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor); MOZ_ASSERT(aActor);
@ -5727,14 +5838,29 @@ FullDatabaseMetadata::Duplicate() const
return newMetadata.forget(); return newMetadata.forget();
} }
DatabaseLoggingInfo::~DatabaseLoggingInfo()
{
AssertIsOnBackgroundThread();
if (gLoggingInfoHashtable) {
const nsID& backgroundChildLoggingId =
mLoggingInfo.backgroundChildLoggingId();
MOZ_ASSERT(gLoggingInfoHashtable->Get(backgroundChildLoggingId) == this);
gLoggingInfoHashtable->Remove(backgroundChildLoggingId);
}
}
/******************************************************************************* /*******************************************************************************
* Factory * Factory
******************************************************************************/ ******************************************************************************/
uint64_t Factory::sFactoryInstanceCount = 0; uint64_t Factory::sFactoryInstanceCount = 0;
Factory::Factory() Factory::Factory(already_AddRefed<DatabaseLoggingInfo> aLoggingInfo)
: mActorDestroyed(false) : mLoggingInfo(Move(aLoggingInfo))
, mActorDestroyed(false)
{ {
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread()); MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
@ -5747,7 +5873,7 @@ Factory::~Factory()
// static // static
already_AddRefed<Factory> already_AddRefed<Factory>
Factory::Create() Factory::Create(const LoggingInfo& aLoggingInfo)
{ {
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread()); MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
@ -5770,6 +5896,9 @@ Factory::Create()
MOZ_ASSERT(!gStartTransactionRunnable); MOZ_ASSERT(!gStartTransactionRunnable);
gStartTransactionRunnable = new nsRunnable(); gStartTransactionRunnable = new nsRunnable();
MOZ_ASSERT(!gLoggingInfoHashtable);
gLoggingInfoHashtable = new DatabaseLoggingInfoHashtable();
#ifdef DEBUG #ifdef DEBUG
if (kDEBUGThreadPriority != nsISupportsPriority::PRIORITY_NORMAL) { if (kDEBUGThreadPriority != nsISupportsPriority::PRIORITY_NORMAL) {
NS_WARNING("PBackground thread debugging enabled, priority has been " NS_WARNING("PBackground thread debugging enabled, priority has been "
@ -5795,7 +5924,29 @@ Factory::Create()
#endif // DEBUG #endif // DEBUG
} }
nsRefPtr<Factory> actor = new Factory(); nsRefPtr<DatabaseLoggingInfo> loggingInfo =
gLoggingInfoHashtable->Get(aLoggingInfo.backgroundChildLoggingId());
if (loggingInfo) {
MOZ_ASSERT(aLoggingInfo.backgroundChildLoggingId() == loggingInfo->Id());
#if !DISABLE_ASSERTS_FOR_FUZZING
NS_WARN_IF_FALSE(aLoggingInfo.nextTransactionSerialNumber() ==
loggingInfo->mLoggingInfo.nextTransactionSerialNumber(),
"NextTransactionSerialNumber doesn't match!");
NS_WARN_IF_FALSE(aLoggingInfo.nextVersionChangeTransactionSerialNumber() ==
loggingInfo->mLoggingInfo.
nextVersionChangeTransactionSerialNumber(),
"NextVersionChangeTransactionSerialNumber doesn't match!");
NS_WARN_IF_FALSE(aLoggingInfo.nextRequestSerialNumber() ==
loggingInfo->mLoggingInfo.nextRequestSerialNumber(),
"NextRequestSerialNumber doesn't match!");
#endif // !DISABLE_ASSERTS_FOR_FUZZING
} else {
loggingInfo = new DatabaseLoggingInfo(aLoggingInfo);
gLoggingInfoHashtable->Put(aLoggingInfo.backgroundChildLoggingId(),
loggingInfo);
}
nsRefPtr<Factory> actor = new Factory(loggingInfo.forget());
sFactoryInstanceCount++; sFactoryInstanceCount++;
@ -5812,6 +5963,9 @@ Factory::ActorDestroy(ActorDestroyReason aWhy)
// Clean up if there are no more instances. // Clean up if there are no more instances.
if (!(--sFactoryInstanceCount)) { if (!(--sFactoryInstanceCount)) {
MOZ_ASSERT(gLoggingInfoHashtable);
gLoggingInfoHashtable = nullptr;
MOZ_ASSERT(gStartTransactionRunnable); MOZ_ASSERT(gStartTransactionRunnable);
gStartTransactionRunnable = nullptr; gStartTransactionRunnable = nullptr;
@ -5853,6 +6007,16 @@ Factory::RecvDeleteMe()
return PBackgroundIDBFactoryParent::Send__delete__(this); return PBackgroundIDBFactoryParent::Send__delete__(this);
} }
bool
Factory::RecvIncrementLoggingRequestSerialNumber()
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mLoggingInfo);
mLoggingInfo->NextRequestSN();
return true;
}
PBackgroundIDBFactoryRequestParent* PBackgroundIDBFactoryRequestParent*
Factory::AllocPBackgroundIDBFactoryRequestParent( Factory::AllocPBackgroundIDBFactoryRequestParent(
const FactoryRequestParams& aParams) const FactoryRequestParams& aParams)
@ -6077,7 +6241,7 @@ Database::Invalidate()
mInvalidated = true; mInvalidated = true;
if (!mActorDestroyed) { if (mActorWasAlive && !mActorDestroyed) {
unused << SendInvalidate(); unused << SendInvalidate();
} }
@ -6329,6 +6493,15 @@ Database::AllocPBackgroundIDBTransactionParent(
for (uint32_t nameIndex = 0; nameIndex < nameCount; nameIndex++) { for (uint32_t nameIndex = 0; nameIndex < nameCount; nameIndex++) {
const nsString& name = aObjectStoreNames[nameIndex]; const nsString& name = aObjectStoreNames[nameIndex];
if (nameIndex) {
// Make sure that this name is sorted properly and not a duplicate.
if (NS_WARN_IF(name <= aObjectStoreNames[nameIndex - 1])) {
ASSERT_UNLESS_FUZZING();
return nullptr;
}
}
const uint32_t oldLength = fallibleObjectStores.Length(); const uint32_t oldLength = fallibleObjectStores.Length();
Closure closure(name, fallibleObjectStores); Closure closure(name, fallibleObjectStores);
@ -6343,7 +6516,7 @@ Database::AllocPBackgroundIDBTransactionParent(
infallibleObjectStores.SwapElements(fallibleObjectStores); infallibleObjectStores.SwapElements(fallibleObjectStores);
nsRefPtr<NormalTransaction> transaction = nsRefPtr<NormalTransaction> transaction =
new NormalTransaction(this, infallibleObjectStores, aMode); new NormalTransaction(this, aMode, infallibleObjectStores);
MOZ_ASSERT(infallibleObjectStores.IsEmpty()); MOZ_ASSERT(infallibleObjectStores.IsEmpty());
@ -6372,13 +6545,13 @@ Database::RecvPBackgroundIDBTransactionConstructor(
auto* transaction = static_cast<NormalTransaction*>(aActor); auto* transaction = static_cast<NormalTransaction*>(aActor);
// Add a placeholder for this transaction immediately. // Add a placeholder for this transaction immediately.
gTransactionThreadPool->Dispatch(transaction->TransactionId(), gTransactionThreadPool->Start(transaction->TransactionId(),
mMetadata->mDatabaseId, mMetadata->mDatabaseId,
aObjectStoreNames, aObjectStoreNames,
aMode, aMode,
gStartTransactionRunnable, GetLoggingInfo()->Id(),
/* aFinish */ false, transaction->LoggingSerialNumber(),
/* aFinishCallback */ nullptr); gStartTransactionRunnable);
transaction->SetActive(); transaction->SetActive();
@ -6472,11 +6645,11 @@ Database::RecvClose()
* TransactionBase * TransactionBase
******************************************************************************/ ******************************************************************************/
TransactionBase::TransactionBase(Database* aDatabase, TransactionBase::TransactionBase(Database* aDatabase, Mode aMode)
Mode aMode)
: mDatabase(aDatabase) : mDatabase(aDatabase)
, mTransactionId(gTransactionThreadPool->NextTransactionId()) , mTransactionId(gTransactionThreadPool->NextTransactionId())
, mDatabaseId(aDatabase->Id()) , mDatabaseId(aDatabase->Id())
, mLoggingSerialNumber(aDatabase->GetLoggingInfo()->NextTransactionSN(aMode))
, mActiveRequestCount(0) , mActiveRequestCount(0)
, mInvalidatedOnAnyThread(false) , mInvalidatedOnAnyThread(false)
, mMode(aMode) , mMode(aMode)
@ -6492,6 +6665,8 @@ TransactionBase::TransactionBase(Database* aDatabase,
{ {
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
MOZ_ASSERT(aDatabase); MOZ_ASSERT(aDatabase);
MOZ_ASSERT(mTransactionId);
MOZ_ASSERT(mLoggingSerialNumber);
} }
TransactionBase::~TransactionBase() TransactionBase::~TransactionBase()
@ -7621,8 +7796,8 @@ TransactionBase::ReleaseBackgroundThreadObjects()
NormalTransaction::NormalTransaction( NormalTransaction::NormalTransaction(
Database* aDatabase, Database* aDatabase,
nsTArray<nsRefPtr<FullObjectStoreMetadata>>& aObjectStores, TransactionBase::Mode aMode,
TransactionBase::Mode aMode) nsTArray<nsRefPtr<FullObjectStoreMetadata>>& aObjectStores)
: TransactionBase(aDatabase, aMode) : TransactionBase(aDatabase, aMode)
{ {
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
@ -9919,8 +10094,6 @@ DatabaseOfflineStorage::Invalidate()
NS_IMPL_ISUPPORTS(CompressDataBlobsFunction, mozIStorageFunction) NS_IMPL_ISUPPORTS(CompressDataBlobsFunction, mozIStorageFunction)
NS_IMPL_ISUPPORTS(EncodeKeysFunction, mozIStorageFunction) NS_IMPL_ISUPPORTS(EncodeKeysFunction, mozIStorageFunction)
uint64_t DatabaseOperationBase::sNextSerialNumber = 0;
// static // static
void void
DatabaseOperationBase::GetBindingClauseForKeyRange( DatabaseOperationBase::GetBindingClauseForKeyRange(
@ -10329,7 +10502,9 @@ FactoryOp::FactoryOp(Factory* aFactory,
already_AddRefed<ContentParent> aContentParent, already_AddRefed<ContentParent> aContentParent,
const CommonFactoryRequestParams& aCommonParams, const CommonFactoryRequestParams& aCommonParams,
bool aDeleting) bool aDeleting)
: mFactory(aFactory) : DatabaseOperationBase(aFactory->GetLoggingInfo()->Id(),
aFactory->GetLoggingInfo()->NextRequestSN())
, mFactory(aFactory)
, mContentParent(Move(aContentParent)) , mContentParent(Move(aContentParent))
, mCommonParams(aCommonParams) , mCommonParams(aCommonParams)
, mState(State_Initial) , mState(State_Initial)
@ -11076,7 +11251,7 @@ OpenDatabaseOp::DoDatabaseWork()
MOZ_ASSERT(mState == State_DatabaseWorkOpen); MOZ_ASSERT(mState == State_DatabaseWorkOpen);
PROFILER_LABEL("IndexedDB", PROFILER_LABEL("IndexedDB",
"OpenDatabaseHelper::DoDatabaseWork", "OpenDatabaseOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE); js::ProfileEntry::Category::STORAGE);
if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) || if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonMainThread()) ||
@ -11649,6 +11824,8 @@ OpenDatabaseOp::DispatchToWorkThread()
AssertIsOnOwningThread(); AssertIsOnOwningThread();
MOZ_ASSERT(mState == State_WaitingForTransactionsToComplete); MOZ_ASSERT(mState == State_WaitingForTransactionsToComplete);
MOZ_ASSERT(mVersionChangeTransaction); MOZ_ASSERT(mVersionChangeTransaction);
MOZ_ASSERT(mVersionChangeTransaction->GetMode() ==
IDBTransaction::VERSION_CHANGE);
MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty()); MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
if (IsActorDestroyed()) { if (IsActorDestroyed()) {
@ -11661,15 +11838,20 @@ OpenDatabaseOp::DispatchToWorkThread()
// Intentionally empty. // Intentionally empty.
nsTArray<nsString> objectStoreNames; nsTArray<nsString> objectStoreNames;
const int64_t loggingSerialNumber =
mVersionChangeTransaction->LoggingSerialNumber();
const nsID& backgroundChildLoggingId =
mVersionChangeTransaction->GetLoggingInfo()->Id();
nsRefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this); nsRefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);
gTransactionThreadPool->Dispatch(mVersionChangeTransaction->TransactionId(), gTransactionThreadPool->Start(mVersionChangeTransaction->TransactionId(),
mVersionChangeTransaction->DatabaseId(), mVersionChangeTransaction->DatabaseId(),
objectStoreNames, objectStoreNames,
mVersionChangeTransaction->GetMode(), mVersionChangeTransaction->GetMode(),
versionChangeOp, backgroundChildLoggingId,
/* aFinish */ false, loggingSerialNumber,
/* aFinishCallback */ nullptr); versionChangeOp);
mVersionChangeTransaction->SetActive(); mVersionChangeTransaction->SetActive();
@ -12109,7 +12291,7 @@ VersionChangeOp::DoDatabaseWork(TransactionBase* aTransaction)
} }
PROFILER_LABEL("IndexedDB", PROFILER_LABEL("IndexedDB",
"VersionChangeOp::DoDatabaseWork", "OpenDatabaseOp::VersionChangeOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE); js::ProfileEntry::Category::STORAGE);
mozIStorageConnection* connection = aTransaction->Connection(); mozIStorageConnection* connection = aTransaction->Connection();
@ -12797,10 +12979,27 @@ VersionChangeOp::Run()
TransactionDatabaseOperationBase::TransactionDatabaseOperationBase( TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
TransactionBase* aTransaction) TransactionBase* aTransaction)
: mTransaction(aTransaction) : DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
aTransaction->GetLoggingInfo()->NextRequestSN())
, mTransaction(aTransaction)
, mTransactionLoggingSerialNumber(aTransaction->LoggingSerialNumber())
, mTransactionIsAborted(aTransaction->IsAborted()) , mTransactionIsAborted(aTransaction->IsAborted())
{ {
MOZ_ASSERT(aTransaction); MOZ_ASSERT(aTransaction);
MOZ_ASSERT(LoggingSerialNumber());
}
TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
TransactionBase* aTransaction,
uint64_t aLoggingSerialNumber)
: DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
aLoggingSerialNumber)
, mTransaction(aTransaction)
, mTransactionLoggingSerialNumber(aTransaction->LoggingSerialNumber())
, mTransactionIsAborted(aTransaction->IsAborted())
{
MOZ_ASSERT(aTransaction);
MOZ_ASSERT(LoggingSerialNumber());
} }
TransactionDatabaseOperationBase::~TransactionDatabaseOperationBase() TransactionDatabaseOperationBase::~TransactionDatabaseOperationBase()
@ -12842,6 +13041,10 @@ TransactionDatabaseOperationBase::RunOnTransactionThread()
MOZ_ASSERT(mTransaction); MOZ_ASSERT(mTransaction);
MOZ_ASSERT(NS_SUCCEEDED(mResultCode)); MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
PROFILER_LABEL("IndexedDB",
"TransactionDatabaseOperationBase::RunOnTransactionThread",
js::ProfileEntry::Category::STORAGE);
// There are several cases where we don't actually have to to any work here. // There are several cases where we don't actually have to to any work here.
if (mTransactionIsAborted) { if (mTransactionIsAborted) {
@ -12868,7 +13071,22 @@ TransactionDatabaseOperationBase::RunOnTransactionThread()
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
mResultCode = rv; mResultCode = rv;
} else { } else {
IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
"Beginning database work",
"IndexedDB %s: P T[%lld] R[%llu]: DB Start",
IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
mTransactionLoggingSerialNumber,
mLoggingSerialNumber);
rv = DoDatabaseWork(mTransaction); rv = DoDatabaseWork(mTransaction);
IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
"Finished database work",
"IndexedDB %s: P T[%lld] R[%llu]: DB End",
IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
mTransactionLoggingSerialNumber,
mLoggingSerialNumber);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
mResultCode = rv; mResultCode = rv;
} }
@ -12950,6 +13168,18 @@ TransactionDatabaseOperationBase::Run()
return NS_OK; return NS_OK;
} }
TransactionBase::
CommitOp::CommitOp(TransactionBase* aTransaction, nsresult aResultCode)
: DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
aTransaction->GetLoggingInfo()->NextRequestSN())
, mTransaction(aTransaction)
, mResultCode(aResultCode)
{
MOZ_ASSERT(aTransaction);
MOZ_ASSERT(LoggingSerialNumber());
}
nsresult nsresult
TransactionBase:: TransactionBase::
CommitOp::WriteAutoIncrementCounts() CommitOp::WriteAutoIncrementCounts()
@ -13055,6 +13285,13 @@ CommitOp::Run()
AssertIsOnTransactionThread(); AssertIsOnTransactionThread();
IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
"Beginning database work",
"IndexedDB %s: P T[%lld] R[%llu]: DB Start",
IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
mTransaction->LoggingSerialNumber(),
mLoggingSerialNumber);
if (NS_SUCCEEDED(mResultCode) && mTransaction->mUpdateFileRefcountFunction) { if (NS_SUCCEEDED(mResultCode) && mTransaction->mUpdateFileRefcountFunction) {
mResultCode = mTransaction-> mResultCode = mTransaction->
mUpdateFileRefcountFunction->WillCommit(connection); mUpdateFileRefcountFunction->WillCommit(connection);
@ -13095,6 +13332,13 @@ CommitOp::Run()
mTransaction->ReleaseTransactionThreadObjects(); mTransaction->ReleaseTransactionThreadObjects();
IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
"Finished database work",
"IndexedDB %s: P T[%lld] R[%llu]: DB End",
IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
mTransaction->LoggingSerialNumber(),
mLoggingSerialNumber);
return NS_OK; return NS_OK;
} }
@ -13121,13 +13365,14 @@ CommitOp::TransactionFinishedAfterUnblock()
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
MOZ_ASSERT(mTransaction); MOZ_ASSERT(mTransaction);
PROFILER_LABEL("IndexedDB", if (!mTransaction->IsActorDestroyed()) {
"CommitOp::TransactionFinishedAfterUnblock", IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
js::ProfileEntry::Category::STORAGE); "Finished with result 0x%x",
"IndexedDB %s: P T[%lld]: Transaction finished (0x%x)",
IDB_PROFILER_MARK("IndexedDB Transaction %llu: Complete (rv = %lu)", IDB_LOG_ID_STRING(mTransaction->GetLoggingInfo()->Id()),
"IDBTransaction[%llu] MT Complete", mTransaction->LoggingSerialNumber(),
mTransaction->TransactionId(), mResultCode); mResultCode);
}
mTransaction->ReleaseBackgroundThreadObjects(); mTransaction->ReleaseBackgroundThreadObjects();
@ -16604,6 +16849,10 @@ OpenOp::DoDatabaseWork(TransactionBase* aTransaction)
MOZ_ASSERT(mCursor->mKey.IsUnset()); MOZ_ASSERT(mCursor->mKey.IsUnset());
MOZ_ASSERT(mCursor->mRangeKey.IsUnset()); MOZ_ASSERT(mCursor->mRangeKey.IsUnset());
PROFILER_LABEL("IndexedDB",
"Cursor::OpenOp::DoDatabaseWork",
js::ProfileEntry::Category::STORAGE);
nsresult rv; nsresult rv;
switch (mCursor->mType) { switch (mCursor->mType) {

View File

@ -7,6 +7,7 @@
template <class> struct already_AddRefed; template <class> struct already_AddRefed;
class nsCString; class nsCString;
struct nsID;
class nsIPrincipal; class nsIPrincipal;
class nsPIDOMWindow; class nsPIDOMWindow;
@ -23,14 +24,16 @@ class Client;
namespace indexedDB { namespace indexedDB {
class LoggingInfo;
class PBackgroundIDBFactoryParent; class PBackgroundIDBFactoryParent;
class PIndexedDBPermissionRequestParent; class PIndexedDBPermissionRequestParent;
PBackgroundIDBFactoryParent* PBackgroundIDBFactoryParent*
AllocPBackgroundIDBFactoryParent(); AllocPBackgroundIDBFactoryParent(const LoggingInfo& aLoggingInfo);
bool bool
RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor); RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor,
const LoggingInfo& aLoggingInfo);
bool bool
DeallocPBackgroundIDBFactoryParent(PBackgroundIDBFactoryParent* aActor); DeallocPBackgroundIDBFactoryParent(PBackgroundIDBFactoryParent* aActor);

View File

@ -426,36 +426,41 @@ IDBCursor::Continue(JSContext* aCx,
} }
} }
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
mRequest->SetLoggingSerialNumber(requestSerialNumber);
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).continue(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continue()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceObjectStore),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(key));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).continue(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continue()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
IDB_LOG_STRINGIFY(mSourceIndex),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(key));
}
mBackgroundActor->SendContinueInternal(ContinueParams(key)); mBackgroundActor->SendContinueInternal(ContinueParams(key));
mContinueCalled = true; mContinueCalled = true;
#ifdef IDB_PROFILER_USE_MARKS
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).cursor(%s)."
"continue(%s)",
"IDBRequest[%llu] MT IDBCursor.continue()",
Request()->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(mSourceObjectStore),
IDB_PROFILER_STRING(mDirection),
key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"cursor(%s).continue(%s)",
"IDBRequest[%llu] MT IDBCursor.continue()",
Request()->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(mSourceIndex->ObjectStore()),
IDB_PROFILER_STRING(mSourceIndex),
IDB_PROFILER_STRING(mDirection),
key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
}
#endif
} }
void void
@ -478,36 +483,41 @@ IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
return; return;
} }
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
mRequest->SetLoggingSerialNumber(requestSerialNumber);
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).advance(%ld)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.advance()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceObjectStore),
IDB_LOG_STRINGIFY(mDirection),
aCount);
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).advance(%ld)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.advance()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
IDB_LOG_STRINGIFY(mSourceIndex),
IDB_LOG_STRINGIFY(mDirection),
aCount);
}
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount)); mBackgroundActor->SendContinueInternal(AdvanceParams(aCount));
mContinueCalled = true; mContinueCalled = true;
#ifdef IDB_PROFILER_USE_MARKS
{
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).advance(%ld)",
"IDBRequest[%llu] MT IDBCursor.advance()",
Request()->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(mSourceObjectStore),
IDB_PROFILER_STRING(mDirection), aCount);
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).advance(%ld)",
"IDBRequest[%llu] MT IDBCursor.advance()",
Request()->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(mSourceIndex->ObjectStore()),
IDB_PROFILER_STRING(mSourceIndex),
IDB_PROFILER_STRING(mDirection), aCount);
}
}
#endif
} }
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
@ -563,7 +573,12 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
return nullptr; return nullptr;
} }
request = objectStore->Put(aCx, aValue, JS::UndefinedHandleValue, aRv); request = objectStore->AddOrPut(aCx,
aValue,
/* aKey */ JS::UndefinedHandleValue,
/* aOverwrite */ true,
/* aFromCursor */ true,
aRv);
if (aRv.Failed()) { if (aRv.Failed()) {
return nullptr; return nullptr;
} }
@ -575,7 +590,12 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
return nullptr; return nullptr;
} }
request = objectStore->Put(aCx, aValue, keyVal, aRv); request = objectStore->AddOrPut(aCx,
aValue,
keyVal,
/* aOverwrite */ true,
/* aFromCursor */ true,
aRv);
if (aRv.Failed()) { if (aRv.Failed()) {
return nullptr; return nullptr;
} }
@ -583,37 +603,34 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
request->SetSource(this); request->SetSource(this);
#ifdef IDB_PROFILER_USE_MARKS if (mType == Type_ObjectStore) {
{ IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
uint64_t requestSerial = request->GetSerialNumber(); "database(%s).transaction(%s).objectStore(%s)."
if (mType == Type_ObjectStore) { "cursor(%s).update(%s)",
IDB_PROFILER_MARK("IndexedDB Request %llu: " "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()",
"database(%s).transaction(%s).objectStore(%s)." IDB_LOG_ID_STRING(),
"cursor(%s).update(%s)", mTransaction->LoggingSerialNumber(),
"IDBRequest[%llu] MT IDBCursor.update()", request->LoggingSerialNumber(),
requestSerial, IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction),
IDB_PROFILER_STRING(mTransaction), IDB_LOG_STRINGIFY(objectStore),
IDB_PROFILER_STRING(objectStore), IDB_LOG_STRINGIFY(mDirection),
IDB_PROFILER_STRING(mDirection), IDB_LOG_STRINGIFY(objectStore, primaryKey));
mObjectStore->HasValidKeyPath() ? "" : } else {
IDB_PROFILER_STRING(primaryKey)); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
} else { "database(%s).transaction(%s).objectStore(%s)."
IDB_PROFILER_MARK("IndexedDB Request %llu: " "index(%s).cursor(%s).update(%s)",
"database(%s).transaction(%s).objectStore(%s)." "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()",
"index(%s).cursor(%s).update(%s)", IDB_LOG_ID_STRING(),
"IDBRequest[%llu] MT IDBCursor.update()", mTransaction->LoggingSerialNumber(),
requestSerial, request->LoggingSerialNumber(),
IDB_PROFILER_STRING(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction), IDB_LOG_STRINGIFY(mTransaction),
IDB_PROFILER_STRING(objectStore), IDB_LOG_STRINGIFY(objectStore),
IDB_PROFILER_STRING(mSourceIndex), IDB_LOG_STRINGIFY(mSourceIndex),
IDB_PROFILER_STRING(mDirection), IDB_LOG_STRINGIFY(mDirection),
mObjectStore->HasValidKeyPath() ? "" : IDB_LOG_STRINGIFY(objectStore, primaryKey));
IDB_PROFILER_STRING(primaryKey));
}
} }
#endif
return request.forget(); return request.forget();
} }
@ -658,44 +675,42 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
return nullptr; return nullptr;
} }
nsRefPtr<IDBRequest> request = objectStore->Delete(aCx, key, aRv); nsRefPtr<IDBRequest> request =
objectStore->DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
if (aRv.Failed()) { if (aRv.Failed()) {
return nullptr; return nullptr;
} }
request->SetSource(this); request->SetSource(this);
#ifdef IDB_PROFILER_USE_MARKS if (mType == Type_ObjectStore) {
{ IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
uint64_t requestSerial = request->GetSerialNumber(); "database(%s).transaction(%s).objectStore(%s)."
if (mType == Type_ObjectStore) { "cursor(%s).delete(%s)",
IDB_PROFILER_MARK("IndexedDB Request %llu: " "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()",
"database(%s).transaction(%s).objectStore(%s)." IDB_LOG_ID_STRING(),
"cursor(%s).delete(%s)", mTransaction->LoggingSerialNumber(),
"IDBRequest[%llu] MT IDBCursor.delete()", request->LoggingSerialNumber(),
requestSerial, IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction),
IDB_PROFILER_STRING(mTransaction), IDB_LOG_STRINGIFY(objectStore),
IDB_PROFILER_STRING(objectStore), IDB_LOG_STRINGIFY(mDirection),
IDB_PROFILER_STRING(mDirection), IDB_LOG_STRINGIFY(objectStore, primaryKey));
mObjectStore->HasValidKeyPath() ? "" : } else {
IDB_PROFILER_STRING(primaryKey)); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
} else { "database(%s).transaction(%s).objectStore(%s)."
IDB_PROFILER_MARK("IndexedDB Request %llu: " "index(%s).cursor(%s).delete(%s)",
"database(%s).transaction(%s).objectStore(%s)." "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()",
"index(%s).cursor(%s).delete(%s)", IDB_LOG_ID_STRING(),
"IDBRequest[%llu] MT IDBCursor.delete()", mTransaction->LoggingSerialNumber(),
requestSerial, request->LoggingSerialNumber(),
IDB_PROFILER_STRING(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction), IDB_LOG_STRINGIFY(mTransaction),
IDB_PROFILER_STRING(objectStore), IDB_LOG_STRINGIFY(objectStore),
IDB_PROFILER_STRING(mSourceIndex), IDB_LOG_STRINGIFY(mSourceIndex),
IDB_PROFILER_STRING(mDirection), IDB_LOG_STRINGIFY(mDirection),
mObjectStore->HasValidKeyPath() ? "" : IDB_LOG_STRINGIFY(objectStore, primaryKey));
IDB_PROFILER_STRING(primaryKey));
}
} }
#endif
return request.forget(); return request.forget();
} }

View File

@ -506,12 +506,20 @@ IDBDatabase::CreateObjectStore(
transaction->CreateObjectStore(*newSpec); transaction->CreateObjectStore(*newSpec);
MOZ_ASSERT(objectStore); MOZ_ASSERT(objectStore);
IDB_PROFILER_MARK("IndexedDB Pseudo-request: " // Don't do this in the macro because we always need to increment the serial
"database(%s).transaction(%s).createObjectStore(%s)", // number to keep in sync with the parent.
"MT IDBDatabase.createObjectStore()", const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aTransaction), IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
IDB_PROFILER_STRING(objectStore)); "database(%s).transaction(%s).createObjectStore(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: "
"IDBDatabase.createObjectStore()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(objectStore));
return objectStore.forget(); return objectStore.forget();
} }
@ -559,12 +567,20 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv)
return; return;
} }
IDB_PROFILER_MARK("IndexedDB Pseudo-request: " // Don't do this in the macro because we always need to increment the serial
"database(%s).transaction(%s).deleteObjectStore(\"%s\")", // number to keep in sync with the parent.
"MT IDBDatabase.deleteObjectStore()", const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(transaction), IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
NS_ConvertUTF16toUTF8(aName).get()); "database(%s).transaction(%s).deleteObjectStore(\"%s\")",
"IndexedDB %s: C T[%lld] R[%llu]: "
"IDBDatabase.deleteObjectStore()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(transaction),
NS_ConvertUTF16toUTF8(aName).get());
} }
already_AddRefed<IDBTransaction> already_AddRefed<IDBTransaction>
@ -669,6 +685,14 @@ IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
BackgroundTransactionChild* actor = BackgroundTransactionChild* actor =
new BackgroundTransactionChild(transaction); new BackgroundTransactionChild(transaction);
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: "
"database(%s).transaction(%s)",
"IndexedDB %s: C T[%lld]: IDBDatabase.transaction()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(transaction));
MOZ_ALWAYS_TRUE( MOZ_ALWAYS_TRUE(
mBackgroundActor->SendPBackgroundIDBTransactionConstructor(actor, mBackgroundActor->SendPBackgroundIDBTransactionConstructor(actor,
sortedStoreNames, sortedStoreNames,
@ -676,11 +700,6 @@ IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
transaction->SetBackgroundActor(actor); transaction->SetBackgroundActor(actor);
IDB_PROFILER_MARK("IndexedDB Transaction %llu: database(%s).transaction(%s)",
"IDBTransaction[%llu] MT Started",
transaction->GetSerialNumber(), IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(transaction));
return transaction.forget(); return transaction.forget();
} }
@ -722,6 +741,8 @@ IDBDatabase::CreateMutableFile(const nsAString& aName,
type = aType.Value(); type = aType.Value();
} }
mFactory->IncrementParentLoggingRequestSerialNumber();
aRv = CreateFileHelper::CreateAndDispatch(this, request, aName, type); aRv = CreateFileHelper::CreateAndDispatch(this, request, aName, type);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;

View File

@ -6,6 +6,7 @@
#include "IDBFactory.h" #include "IDBFactory.h"
#include "BackgroundChildImpl.h"
#include "IDBRequest.h" #include "IDBRequest.h"
#include "IndexedDatabaseManager.h" #include "IndexedDatabaseManager.h"
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
@ -21,7 +22,9 @@
#include "nsIIPCBackgroundChildCreateCallback.h" #include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsILoadContext.h" #include "nsILoadContext.h"
#include "nsIPrincipal.h" #include "nsIPrincipal.h"
#include "nsIUUIDGenerator.h"
#include "nsIWebNavigation.h" #include "nsIWebNavigation.h"
#include "nsServiceManagerUtils.h"
#include "ProfilerHelpers.h" #include "ProfilerHelpers.h"
#include "ReportInternalError.h" #include "ReportInternalError.h"
@ -76,10 +79,14 @@ class IDBFactory::BackgroundCreateCallback MOZ_FINAL
: public nsIIPCBackgroundChildCreateCallback : public nsIIPCBackgroundChildCreateCallback
{ {
nsRefPtr<IDBFactory> mFactory; nsRefPtr<IDBFactory> mFactory;
LoggingInfo mLoggingInfo;
public: public:
explicit BackgroundCreateCallback(IDBFactory* aFactory) explicit
: mFactory(aFactory) BackgroundCreateCallback(IDBFactory* aFactory,
const LoggingInfo& aLoggingInfo)
: mFactory(aFactory)
, mLoggingInfo(aLoggingInfo)
{ {
MOZ_ASSERT(aFactory); MOZ_ASSERT(aFactory);
} }
@ -306,6 +313,15 @@ IDBFactory::SetBackgroundActor(BackgroundFactoryChild* aBackgroundActor)
mBackgroundActor = aBackgroundActor; mBackgroundActor = aBackgroundActor;
} }
void
IDBFactory::IncrementParentLoggingRequestSerialNumber()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mBackgroundActor);
mBackgroundActor->SendIncrementLoggingRequestSerialNumber();
}
already_AddRefed<IDBOpenDBRequest> already_AddRefed<IDBOpenDBRequest>
IDBFactory::Open(const nsAString& aName, IDBFactory::Open(const nsAString& aName,
uint64_t aVersion, uint64_t aVersion,
@ -501,27 +517,44 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
params = OpenDatabaseRequestParams(commonParams); params = OpenDatabaseRequestParams(commonParams);
} }
if (!mBackgroundActor) { if (!mBackgroundActor && mPendingRequests.IsEmpty()) {
// If another consumer has already created a background actor for this // We need to start the sequence to create a background actor for this
// thread then we can start this request immediately. // thread.
if (PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread()) { BackgroundChildImpl::ThreadLocal* threadLocal =
nsresult rv = BackgroundActorCreated(bgActor); BackgroundChildImpl::GetThreadLocalForCurrentThread();
if (NS_WARN_IF(NS_FAILED(rv))) {
IDB_REPORT_INTERNAL_ERR(); nsAutoPtr<ThreadLocal> newIDBThreadLocal;
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); ThreadLocal* idbThreadLocal;
return nullptr;
} if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
MOZ_ASSERT(mBackgroundActor); idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
} else if (mPendingRequests.IsEmpty()) { } else {
// We need to start the sequence to create a background actor for this nsCOMPtr<nsIUUIDGenerator> uuidGen =
// thread. do_GetService("@mozilla.org/uuid-generator;1");
nsRefPtr<BackgroundCreateCallback> cb = MOZ_ASSERT(uuidGen);
new BackgroundCreateCallback(this);
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(cb))) { nsID id;
IDB_REPORT_INTERNAL_ERR(); MOZ_ALWAYS_TRUE(NS_SUCCEEDED(uuidGen->GenerateUUIDInPlace(&id)));
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr; newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id);
}
nsRefPtr<BackgroundCreateCallback> cb =
new BackgroundCreateCallback(this, idbThreadLocal->GetLoggingInfo());
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(cb))) {
IDB_REPORT_INTERNAL_ERR();
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
}
if (newIDBThreadLocal) {
if (!threadLocal) {
threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread();
} }
MOZ_ASSERT(threadLocal);
MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal);
threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget();
} }
} }
@ -550,6 +583,23 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (aDeleting) {
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: "
"indexedDB.deleteDatabase(\"%s\")",
"IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()",
IDB_LOG_ID_STRING(),
request->LoggingSerialNumber(),
NS_ConvertUTF16toUTF8(aName).get());
} else {
IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: "
"indexedDB.open(\"%s\", %s)",
"IndexedDB %s: C R[%llu]: IDBFactory.open()",
IDB_LOG_ID_STRING(),
request->LoggingSerialNumber(),
NS_ConvertUTF16toUTF8(aName).get(),
IDB_LOG_STRINGIFY(aVersion));
}
// If we already have a background actor then we can start this request now. // If we already have a background actor then we can start this request now.
if (mBackgroundActor) { if (mBackgroundActor) {
nsresult rv = InitiateRequest(request, params); nsresult rv = InitiateRequest(request, params);
@ -562,27 +612,12 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
mPendingRequests.AppendElement(new PendingRequestInfo(request, params)); mPendingRequests.AppendElement(new PendingRequestInfo(request, params));
} }
#ifdef IDB_PROFILER_USE_MARKS
{
NS_ConvertUTF16toUTF8 profilerName(aName);
if (aDeleting) {
IDB_PROFILER_MARK("IndexedDB Request %llu: deleteDatabase(\"%s\")",
"MT IDBFactory.deleteDatabase()",
request->GetSerialNumber(), profilerName.get());
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: open(\"%s\", %lld)",
"MT IDBFactory.open()",
request->GetSerialNumber(), profilerName.get(),
aVersion);
}
}
#endif
return request.forget(); return request.forget();
} }
nsresult nsresult
IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor) IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor,
const LoggingInfo& aLoggingInfo)
{ {
MOZ_ASSERT(aBackgroundActor); MOZ_ASSERT(aBackgroundActor);
MOZ_ASSERT(!mBackgroundActor); MOZ_ASSERT(!mBackgroundActor);
@ -595,7 +630,8 @@ IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor)
mBackgroundActor = mBackgroundActor =
static_cast<BackgroundFactoryChild*>( static_cast<BackgroundFactoryChild*>(
aBackgroundActor->SendPBackgroundIDBFactoryConstructor(actor)); aBackgroundActor->SendPBackgroundIDBFactoryConstructor(actor,
aLoggingInfo));
} }
if (NS_WARN_IF(!mBackgroundActor)) { if (NS_WARN_IF(!mBackgroundActor)) {
@ -735,7 +771,7 @@ IDBFactory::BackgroundCreateCallback::ActorCreated(PBackgroundChild* aActor)
nsRefPtr<IDBFactory> factory; nsRefPtr<IDBFactory> factory;
mFactory.swap(factory); mFactory.swap(factory);
factory->BackgroundActorCreated(aActor); factory->BackgroundActorCreated(aActor, mLoggingInfo);
} }
void void

View File

@ -42,6 +42,7 @@ namespace indexedDB {
class BackgroundFactoryChild; class BackgroundFactoryChild;
class FactoryRequestParams; class FactoryRequestParams;
class IDBOpenDBRequest; class IDBOpenDBRequest;
class LoggingInfo;
class IDBFactory MOZ_FINAL class IDBFactory MOZ_FINAL
: public nsISupports : public nsISupports
@ -112,6 +113,9 @@ public:
mBackgroundActor = nullptr; mBackgroundActor = nullptr;
} }
void
IncrementParentLoggingRequestSerialNumber();
nsPIDOMWindow* nsPIDOMWindow*
GetParentObject() const GetParentObject() const
{ {
@ -208,7 +212,8 @@ private:
ErrorResult& aRv); ErrorResult& aRv);
nsresult nsresult
BackgroundActorCreated(PBackgroundChild* aBackgroundActor); BackgroundActorCreated(PBackgroundChild* aBackgroundActor,
const LoggingInfo& aLoggingInfo);
void void
BackgroundActorFailed(); BackgroundActorFailed();

View File

@ -264,33 +264,38 @@ IDBIndex::GetInternal(bool aKeyOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (aKeyOnly) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"getKey(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getKey()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"get(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.get()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange));
}
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
transaction->StartRequest(actor, params); transaction->StartRequest(actor, params);
if (aKeyOnly) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"getKey(%s)",
"IDBRequest[%llu] MT IDBIndex.getKey()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(transaction->Database()),
IDB_PROFILER_STRING(transaction),
IDB_PROFILER_STRING(mObjectStore),
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aKey));
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"get(%s)",
"IDBRequest[%llu] MT IDBIndex.get()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(transaction->Database()),
IDB_PROFILER_STRING(transaction),
IDB_PROFILER_STRING(mObjectStore),
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aKey));
}
return request.forget(); return request.forget();
} }
@ -340,36 +345,40 @@ IDBIndex::GetAllInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (aKeysOnly) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"getAllKeys(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAllKeys()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(aLimit));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"getAll(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAll()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(aLimit));
}
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
transaction->StartRequest(actor, params); transaction->StartRequest(actor, params);
if (aKeysOnly) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"getAllKeys(%s, %lu)",
"IDBRequest[%llu] MT IDBIndex.getAllKeys()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(transaction->Database()),
IDB_PROFILER_STRING(transaction),
IDB_PROFILER_STRING(mObjectStore),
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aKeyRange),
aLimit);
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"getAll(%s, %lu)",
"IDBRequest[%llu] MT IDBIndex.getAll()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(transaction->Database()),
IDB_PROFILER_STRING(transaction),
IDB_PROFILER_STRING(mObjectStore),
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aKeyRange),
aLimit);
}
return request.forget(); return request.forget();
} }
@ -432,6 +441,37 @@ IDBIndex::OpenCursorInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (aKeysOnly) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"openKeyCursor(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.openKeyCursor()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(direction));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"openCursor(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: "
"IDBObjectStore.openKeyCursor()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(direction));
}
BackgroundCursorChild* actor = BackgroundCursorChild* actor =
new BackgroundCursorChild(request, this, direction); new BackgroundCursorChild(request, this, direction);
@ -474,21 +514,23 @@ IDBIndex::Count(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"count(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()",
IDB_LOG_ID_STRING(),
transaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(transaction->Database()),
IDB_LOG_STRINGIFY(transaction),
IDB_LOG_STRINGIFY(mObjectStore),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange));
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
transaction->StartRequest(actor, params); transaction->StartRequest(actor, params);
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).index(%s)."
"count(%s)",
"IDBRequest[%llu] MT IDBObjectStore.count()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(transaction->Database()),
IDB_PROFILER_STRING(transaction),
IDB_PROFILER_STRING(mObjectStore),
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aKey));
return request.forget(); return request.forget();
} }

View File

@ -1143,10 +1143,12 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
JS::Handle<JS::Value> aValue, JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aKey, JS::Handle<JS::Value> aKey,
bool aOverwrite, bool aOverwrite,
bool aFromCursor,
ErrorResult& aRv) ErrorResult& aRv)
{ {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
MOZ_ASSERT(aCx); MOZ_ASSERT(aCx);
MOZ_ASSERT_IF(aFromCursor, aOverwrite);
if (!mTransaction->IsOpen()) { if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
@ -1249,6 +1251,32 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (!aFromCursor) {
if (aOverwrite) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).put(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.put()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(key));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).add(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.add()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(key));
}
}
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
mTransaction->StartRequest(actor, params); mTransaction->StartRequest(actor, params);
@ -1261,28 +1289,6 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
MOZ_ASSERT(fileInfos.IsEmpty()); MOZ_ASSERT(fileInfos.IsEmpty());
} }
#ifdef IDB_PROFILER_USE_MARKS
if (aOverwrite) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).%s(%s)",
"IDBRequest[%llu] MT IDBObjectStore.put()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this),
key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).add(%s)",
"IDBRequest[%llu] MT IDBObjectStore.add()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this),
key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
}
#endif
return request.forget(); return request.forget();
} }
@ -1329,36 +1335,38 @@ IDBObjectStore::GetAllInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (aKeysOnly) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"getAllKeys(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAllKeys()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(aLimit));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"getAll(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAll()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(aLimit));
}
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
mTransaction->StartRequest(actor, params); mTransaction->StartRequest(actor, params);
#ifdef IDB_PROFILER_USE_MARKS
if (aKeysOnly) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"getAllKeys(%s, %lu)",
"IDBRequest[%llu] MT IDBObjectStore.getAllKeys()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aKeyRange),
aLimit);
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"getAll(%s, %lu)",
"IDBRequest[%llu] MT IDBObjectStore.getAll()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aKeyRange),
aLimit);
}
#endif
return request.forget(); return request.forget();
} }
@ -1383,18 +1391,20 @@ IDBObjectStore::Clear(ErrorResult& aRv)
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).clear()",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.clear()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this));
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
mTransaction->StartRequest(actor, params); mTransaction->StartRequest(actor, params);
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).clear()",
"IDBRequest[%llu] MT IDBObjectStore.clear()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this));
return request.forget(); return request.forget();
} }
@ -1579,25 +1589,29 @@ IDBObjectStore::Get(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).get(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.get()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange));
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
mTransaction->StartRequest(actor, params); mTransaction->StartRequest(actor, params);
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).get(%s)",
"IDBRequest[%llu] MT IDBObjectStore.get()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
return request.forget(); return request.forget();
} }
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
IDBObjectStore::Delete(JSContext* aCx, IDBObjectStore::DeleteInternal(JSContext* aCx,
JS::Handle<JS::Value> aKey, JS::Handle<JS::Value> aKey,
ErrorResult& aRv) bool aFromCursor,
ErrorResult& aRv)
{ {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
@ -1630,18 +1644,23 @@ IDBObjectStore::Delete(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (!aFromCursor) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).delete(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.delete()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange));
}
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
mTransaction->StartRequest(actor, params); mTransaction->StartRequest(actor, params);
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).delete(%s)",
"IDBRequest[%llu] MT IDBObjectStore.delete()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
return request.forget(); return request.forget();
} }
@ -1748,13 +1767,20 @@ IDBObjectStore::CreateIndexInternal(
mIndexes.AppendElement(index); mIndexes.AppendElement(index);
IDB_PROFILER_MARK("IndexedDB Pseudo-request: " // Don't do this in the macro because we always need to increment the serial
"database(%s).transaction(%s).objectStore(%s)." // number to keep in sync with the parent.
"createIndex(%s)", const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
"MT IDBObjectStore.createIndex()",
IDB_PROFILER_STRING(Transaction()->Database()), IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
IDB_PROFILER_STRING(Transaction()), "database(%s).transaction(%s).objectStore(%s).createIndex(%s)",
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(index)); "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.createIndex()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(index));
return index.forget(); return index.forget();
} }
@ -1813,16 +1839,23 @@ IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv)
return; return;
} }
transaction->DeleteIndex(this, foundId); // Don't do this in the macro because we always need to increment the serial
// number to keep in sync with the parent.
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
IDB_PROFILER_MARK("IndexedDB Pseudo-request: " IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)." "database(%s).transaction(%s).objectStore(%s)."
"deleteIndex(\"%s\")", "deleteIndex(\"%s\")",
"MT IDBObjectStore.deleteIndex()", "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.deleteIndex()",
IDB_PROFILER_STRING(Transaction()->Database()), IDB_LOG_ID_STRING(),
IDB_PROFILER_STRING(Transaction()), mTransaction->LoggingSerialNumber(),
IDB_PROFILER_STRING(this), requestSerialNumber,
NS_ConvertUTF16toUTF8(aName).get()); IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
NS_ConvertUTF16toUTF8(aName).get());
transaction->DeleteIndex(this, foundId);
} }
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
@ -1855,18 +1888,21 @@ IDBObjectStore::Count(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s).count(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange));
BackgroundRequestChild* actor = new BackgroundRequestChild(request); BackgroundRequestChild* actor = new BackgroundRequestChild(request);
mTransaction->StartRequest(actor, params); mTransaction->StartRequest(actor, params);
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s).count(%s)",
"IDBRequest[%llu] MT IDBObjectStore.count()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
return request.forget(); return request.forget();
} }
@ -1925,34 +1961,40 @@ IDBObjectStore::OpenCursorInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this); nsRefPtr<IDBRequest> request = GenerateRequest(this);
MOZ_ASSERT(request); MOZ_ASSERT(request);
if (aKeysOnly) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"openKeyCursor(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: "
"IDBObjectStore.openKeyCursor()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(direction));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"openCursor(%s, %s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.openCursor()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
IDB_LOG_STRINGIFY(keyRange),
IDB_LOG_STRINGIFY(direction));
}
BackgroundCursorChild* actor = BackgroundCursorChild* actor =
new BackgroundCursorChild(request, this, direction); new BackgroundCursorChild(request, this, direction);
mTransaction->OpenCursor(actor, params); mTransaction->OpenCursor(actor, params);
#ifdef IDB_PROFILER_USE_MARKS
if (aKeysOnly) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"openKeyCursor(%s, %s)",
"IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
IDB_PROFILER_STRING(direction));
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"openCursor(%s, %s)",
"IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()",
request->GetSerialNumber(),
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
IDB_PROFILER_STRING(direction));
}
#endif
return request.forget(); return request.forget();
} }

View File

@ -33,6 +33,7 @@ template <typename> class Sequence;
namespace indexedDB { namespace indexedDB {
class FileManager; class FileManager;
class IDBCursor;
class IDBKeyRange; class IDBKeyRange;
class IDBRequest; class IDBRequest;
class IDBTransaction; class IDBTransaction;
@ -47,6 +48,9 @@ class IDBObjectStore MOZ_FINAL
: public nsISupports : public nsISupports
, public nsWrapperCache , public nsWrapperCache
{ {
// For AddOrPut() and DeleteInternal().
friend class IDBCursor;
static const JSClass sDummyPropJSClass; static const JSClass sDummyPropJSClass;
nsRefPtr<IDBTransaction> mTransaction; nsRefPtr<IDBTransaction> mTransaction;
@ -160,7 +164,7 @@ public:
{ {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
return AddOrPut(aCx, aValue, aKey, false, aRv); return AddOrPut(aCx, aValue, aKey, false, /* aFromCursor */ false, aRv);
} }
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
@ -171,11 +175,18 @@ public:
{ {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
return AddOrPut(aCx, aValue, aKey, true, aRv); return AddOrPut(aCx, aValue, aKey, true, /* aFromCursor */ false, aRv);
} }
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
Delete(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv); Delete(JSContext* aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
{
AssertIsOnOwningThread();
return DeleteInternal(aCx, aKey, /* aFromCursor */ false, aRv);
}
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
Get(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv); Get(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv);
@ -286,8 +297,15 @@ private:
JS::Handle<JS::Value> aValue, JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aKey, JS::Handle<JS::Value> aKey,
bool aOverwrite, bool aOverwrite,
bool aFromCursor,
ErrorResult& aRv); ErrorResult& aRv);
already_AddRefed<IDBRequest>
DeleteInternal(JSContext* aCx,
JS::Handle<JS::Value> aKey,
bool aFromCursor,
ErrorResult& aRv);
already_AddRefed<IDBRequest> already_AddRefed<IDBRequest>
GetAllInternal(bool aKeysOnly, GetAllInternal(bool aKeysOnly,
JSContext* aCx, JSContext* aCx,

View File

@ -29,6 +29,9 @@
#include "nsString.h" #include "nsString.h"
#include "ReportInternalError.h" #include "ReportInternalError.h"
// Include this last to avoid path problems on Windows.
#include "ActorsChild.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
namespace indexedDB { namespace indexedDB {
@ -75,19 +78,10 @@ IDBRequest::InitMembers()
AssertIsOnOwningThread(); AssertIsOnOwningThread();
mResultVal.setUndefined(); mResultVal.setUndefined();
mLoggingSerialNumber = NextSerialNumber();
mErrorCode = NS_OK; mErrorCode = NS_OK;
mLineNo = 0; mLineNo = 0;
mHaveResultOrErrorCode = false; mHaveResultOrErrorCode = false;
#ifdef MOZ_ENABLE_PROFILER_SPS
{
BackgroundChildImpl::ThreadLocal* threadLocal =
BackgroundChildImpl::GetThreadLocalForCurrentThread();
MOZ_ASSERT(threadLocal);
mSerialNumber = threadLocal->mNextRequestSerialNumber++;
}
#endif
} }
// static // static
@ -140,6 +134,28 @@ IDBRequest::Create(IDBIndex* aSourceAsIndex,
} }
// static // static
uint64_t
IDBRequest::NextSerialNumber()
{
BackgroundChildImpl::ThreadLocal* threadLocal =
BackgroundChildImpl::GetThreadLocalForCurrentThread();
MOZ_ASSERT(threadLocal);
ThreadLocal* idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
MOZ_ASSERT(idbThreadLocal);
return idbThreadLocal->NextRequestSN();
}
void
IDBRequest::SetLoggingSerialNumber(uint64_t aLoggingSerialNumber)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aLoggingSerialNumber > mLoggingSerialNumber);
mLoggingSerialNumber = aLoggingSerialNumber;
}
void void
IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo) IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo)
{ {

View File

@ -58,9 +58,7 @@ protected:
nsRefPtr<DOMError> mError; nsRefPtr<DOMError> mError;
nsString mFilename; nsString mFilename;
#ifdef MOZ_ENABLE_PROFILER_SPS uint64_t mLoggingSerialNumber;
uint64_t mSerialNumber;
#endif
nsresult mErrorCode; nsresult mErrorCode;
uint32_t mLineNo; uint32_t mLineNo;
bool mHaveResultOrErrorCode; bool mHaveResultOrErrorCode;
@ -84,6 +82,9 @@ public:
static void static void
CaptureCaller(nsAString& aFilename, uint32_t* aLineNo); CaptureCaller(nsAString& aFilename, uint32_t* aLineNo);
static uint64_t
NextSerialNumber();
// nsIDOMEventTarget // nsIDOMEventTarget
virtual nsresult virtual nsresult
PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE; PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
@ -125,13 +126,16 @@ public:
return !mHaveResultOrErrorCode; return !mHaveResultOrErrorCode;
} }
#ifdef MOZ_ENABLE_PROFILER_SPS
uint64_t uint64_t
GetSerialNumber() const LoggingSerialNumber() const
{ {
return mSerialNumber; AssertIsOnOwningThread();
return mLoggingSerialNumber;
} }
#endif
void
SetLoggingSerialNumber(uint64_t aLoggingSerialNumber);
nsPIDOMWindow* nsPIDOMWindow*
GetParentObject() const GetParentObject() const

View File

@ -32,6 +32,8 @@ namespace mozilla {
namespace dom { namespace dom {
namespace indexedDB { namespace indexedDB {
using namespace mozilla::ipc;
namespace { namespace {
NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
@ -44,6 +46,7 @@ IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
: IDBWrapperCache(aDatabase) : IDBWrapperCache(aDatabase)
, mDatabase(aDatabase) , mDatabase(aDatabase)
, mObjectStoreNames(aObjectStoreNames) , mObjectStoreNames(aObjectStoreNames)
, mLoggingSerialNumber(0)
, mNextObjectStoreId(0) , mNextObjectStoreId(0)
, mNextIndexId(0) , mNextIndexId(0)
, mAbortCode(NS_OK) , mAbortCode(NS_OK)
@ -63,16 +66,15 @@ IDBTransaction::IDBTransaction(IDBDatabase* aDatabase,
mBackgroundActor.mNormalBackgroundActor = nullptr; mBackgroundActor.mNormalBackgroundActor = nullptr;
#ifdef MOZ_ENABLE_PROFILER_SPS BackgroundChildImpl::ThreadLocal* threadLocal =
{ BackgroundChildImpl::GetThreadLocalForCurrentThread();
using namespace mozilla::ipc; MOZ_ASSERT(threadLocal);
BackgroundChildImpl::ThreadLocal* threadLocal =
BackgroundChildImpl::GetThreadLocalForCurrentThread();
MOZ_ASSERT(threadLocal);
mSerialNumber = threadLocal->mNextTransactionSerialNumber++; ThreadLocal* idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
} MOZ_ASSERT(idbThreadLocal);
#endif
const_cast<int64_t&>(mLoggingSerialNumber) =
idbThreadLocal->NextTransactionSN(aMode);
#ifdef DEBUG #ifdef DEBUG
if (!aObjectStoreNames.IsEmpty()) { if (!aObjectStoreNames.IsEmpty()) {
@ -111,13 +113,15 @@ IDBTransaction::~IDBTransaction()
mDatabase->UnregisterTransaction(this); mDatabase->UnregisterTransaction(this);
if (mMode == VERSION_CHANGE) { if (mMode == VERSION_CHANGE) {
if (mBackgroundActor.mVersionChangeBackgroundActor) { if (auto* actor = mBackgroundActor.mVersionChangeBackgroundActor) {
mBackgroundActor.mVersionChangeBackgroundActor->SendDeleteMeInternal(); actor->SendDeleteMeInternal();
MOZ_ASSERT(!mBackgroundActor.mVersionChangeBackgroundActor, MOZ_ASSERT(!mBackgroundActor.mVersionChangeBackgroundActor,
"SendDeleteMeInternal should have cleared!"); "SendDeleteMeInternal should have cleared!");
} }
} else if (mBackgroundActor.mNormalBackgroundActor) { } else if (auto* actor = mBackgroundActor.mNormalBackgroundActor) {
mBackgroundActor.mNormalBackgroundActor->SendDeleteMeInternal(); actor->SendDeleteMeInternal();
MOZ_ASSERT(!mBackgroundActor.mNormalBackgroundActor, MOZ_ASSERT(!mBackgroundActor.mNormalBackgroundActor,
"SendDeleteMeInternal should have cleared!"); "SendDeleteMeInternal should have cleared!");
} }
@ -212,7 +216,10 @@ IDBTransaction::GetCurrent()
BackgroundChildImpl::GetThreadLocalForCurrentThread(); BackgroundChildImpl::GetThreadLocalForCurrentThread();
MOZ_ASSERT(threadLocal); MOZ_ASSERT(threadLocal);
return threadLocal->mCurrentTransaction; ThreadLocal* idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
MOZ_ASSERT(idbThreadLocal);
return idbThreadLocal->GetCurrentTransaction();
} }
#ifdef DEBUG #ifdef DEBUG
@ -339,6 +346,18 @@ IDBTransaction::SendCommit()
MOZ_ASSERT(NS_SUCCEEDED(mAbortCode)); MOZ_ASSERT(NS_SUCCEEDED(mAbortCode));
MOZ_ASSERT(IsFinished()); MOZ_ASSERT(IsFinished());
MOZ_ASSERT(!mSentCommitOrAbort); MOZ_ASSERT(!mSentCommitOrAbort);
MOZ_ASSERT(!mPendingRequestCount);
// Don't do this in the macro because we always need to increment the serial
// number to keep in sync with the parent.
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"All requests complete, committing transaction",
"IndexedDB %s: C T[%lld] R[%llu]: IDBTransaction commit",
IDB_LOG_ID_STRING(),
LoggingSerialNumber(),
requestSerialNumber);
if (mMode == VERSION_CHANGE) { if (mMode == VERSION_CHANGE) {
MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor);
@ -361,6 +380,18 @@ IDBTransaction::SendAbort(nsresult aResultCode)
MOZ_ASSERT(IsFinished()); MOZ_ASSERT(IsFinished());
MOZ_ASSERT(!mSentCommitOrAbort); MOZ_ASSERT(!mSentCommitOrAbort);
// Don't do this in the macro because we always need to increment the serial
// number to keep in sync with the parent.
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"Aborting transaction with result 0x%x",
"IndexedDB %s: C T[%lld] R[%llu]: IDBTransaction abort (0x%x)",
IDB_LOG_ID_STRING(),
LoggingSerialNumber(),
requestSerialNumber,
aResultCode);
if (mMode == VERSION_CHANGE) { if (mMode == VERSION_CHANGE) {
MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor);
mBackgroundActor.mVersionChangeBackgroundActor->SendAbort(aResultCode); mBackgroundActor.mVersionChangeBackgroundActor->SendAbort(aResultCode);
@ -517,11 +548,14 @@ IDBTransaction::AbortInternal(nsresult aAbortCode,
const bool isInvalidated = mDatabase->IsInvalidated(); const bool isInvalidated = mDatabase->IsInvalidated();
bool needToSendAbort = mReadyState == INITIAL && !isInvalidated; bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
#ifdef DEBUG
if (isInvalidated) { if (isInvalidated) {
#ifdef DEBUG
mSentCommitOrAbort = true; mSentCommitOrAbort = true;
}
#endif #endif
// Increment the serial number counter here to account for the aborted
// transaction and keep the parent in sync.
IDBRequest::NextSerialNumber();
}
mAbortCode = aAbortCode; mAbortCode = aAbortCode;
mReadyState = DONE; mReadyState = DONE;
@ -639,10 +673,6 @@ IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult)
AssertIsOnOwningThread(); AssertIsOnOwningThread();
MOZ_ASSERT(!mFiredCompleteOrAbort); MOZ_ASSERT(!mFiredCompleteOrAbort);
IDB_PROFILER_MARK("IndexedDB Transaction %llu: Complete (rv = %lu)",
"IDBTransaction[%llu] MT Complete",
mTransaction->GetSerialNumber(), mAbortCode);
mReadyState = DONE; mReadyState = DONE;
#ifdef DEBUG #ifdef DEBUG
@ -670,6 +700,21 @@ IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult)
return; return;
} }
if (NS_SUCCEEDED(mAbortCode)) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: "
"Firing 'complete' event",
"IndexedDB %s: C T[%lld]: IDBTransaction 'complete' event",
IDB_LOG_ID_STRING(),
mLoggingSerialNumber);
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: "
"Firing 'abort' event with error 0x%x",
"IndexedDB %s: C T[%lld]: IDBTransaction 'abort' event (0x%x)",
IDB_LOG_ID_STRING(),
mLoggingSerialNumber,
mAbortCode);
}
bool dummy; bool dummy;
if (NS_FAILED(DispatchEvent(event, &dummy))) { if (NS_FAILED(DispatchEvent(event, &dummy))) {
NS_WARNING("DispatchEvent failed!"); NS_WARNING("DispatchEvent failed!");

View File

@ -83,15 +83,12 @@ private:
BackgroundVersionChangeTransactionChild* mVersionChangeBackgroundActor; BackgroundVersionChangeTransactionChild* mVersionChangeBackgroundActor;
} mBackgroundActor; } mBackgroundActor;
const int64_t mLoggingSerialNumber;
// Only used for VERSION_CHANGE transactions. // Only used for VERSION_CHANGE transactions.
int64_t mNextObjectStoreId; int64_t mNextObjectStoreId;
int64_t mNextIndexId; int64_t mNextIndexId;
#ifdef MOZ_ENABLE_PROFILER_SPS
uint64_t mSerialNumber;
#endif
nsresult mAbortCode; nsresult mAbortCode;
uint32_t mPendingRequestCount; uint32_t mPendingRequestCount;
@ -245,14 +242,13 @@ public:
void void
Abort(nsresult aAbortCode); Abort(nsresult aAbortCode);
#ifdef MOZ_ENABLE_PROFILER_SPS int64_t
uint32_t LoggingSerialNumber() const
GetSerialNumber() const
{ {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
return mSerialNumber;
return mLoggingSerialNumber;
} }
#endif
nsPIDOMWindow* nsPIDOMWindow*
GetParentObject() const; GetParentObject() const;

View File

@ -32,11 +32,13 @@
#include "mozilla/storage.h" #include "mozilla/storage.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "prlog.h"
#include "IDBEvents.h" #include "IDBEvents.h"
#include "IDBFactory.h" #include "IDBFactory.h"
#include "IDBKeyRange.h" #include "IDBKeyRange.h"
#include "IDBRequest.h" #include "IDBRequest.h"
#include "ProfilerHelpers.h"
// Bindings for ResolveConstructors // Bindings for ResolveConstructors
#include "mozilla/dom/IDBCursorBinding.h" #include "mozilla/dom/IDBCursorBinding.h"
@ -111,7 +113,22 @@ private:
namespace { namespace {
const char kTestingPref[] = "dom.indexedDB.testing"; #define IDB_PREF_BRANCH_ROOT "dom.indexedDB."
const char kTestingPref[] = IDB_PREF_BRANCH_ROOT "testing";
#define IDB_PREF_LOGGING_BRANCH_ROOT IDB_PREF_BRANCH_ROOT "logging."
const char kPrefLoggingEnabled[] = IDB_PREF_LOGGING_BRANCH_ROOT "enabled";
const char kPrefLoggingDetails[] = IDB_PREF_LOGGING_BRANCH_ROOT "details";
#if defined(DEBUG) || defined(MOZ_ENABLE_PROFILER_SPS)
const char kPrefLoggingProfiler[] =
IDB_PREF_LOGGING_BRANCH_ROOT "profiler-marks";
#endif
#undef IDB_PREF_LOGGING_BRANCH_ROOT
#undef IDB_PREF_BRANCH_ROOT
mozilla::StaticRefPtr<IndexedDatabaseManager> gDBManager; mozilla::StaticRefPtr<IndexedDatabaseManager> gDBManager;
@ -205,6 +222,13 @@ IndexedDatabaseManager::~IndexedDatabaseManager()
bool IndexedDatabaseManager::sIsMainProcess = false; bool IndexedDatabaseManager::sIsMainProcess = false;
bool IndexedDatabaseManager::sFullSynchronousMode = false; bool IndexedDatabaseManager::sFullSynchronousMode = false;
PRLogModuleInfo* IndexedDatabaseManager::sLoggingModule;
Atomic<IndexedDatabaseManager::LoggingMode>
IndexedDatabaseManager::sLoggingMode(
IndexedDatabaseManager::Logging_Disabled);
mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false); mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
// static // static
@ -221,6 +245,10 @@ IndexedDatabaseManager::GetOrCreate()
if (!gDBManager) { if (!gDBManager) {
sIsMainProcess = XRE_GetProcessType() == GeckoProcessType_Default; sIsMainProcess = XRE_GetProcessType() == GeckoProcessType_Default;
if (!sLoggingModule) {
sLoggingModule = PR_NewLogModule("IndexedDB");
}
if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) { if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) {
// See if we're starting up in low disk space conditions. // See if we're starting up in low disk space conditions.
nsCOMPtr<nsIDiskSpaceWatcher> watcher = nsCOMPtr<nsIDiskSpaceWatcher> watcher =
@ -300,6 +328,15 @@ IndexedDatabaseManager::Init()
// hit. // hit.
sFullSynchronousMode = Preferences::GetBool("dom.indexedDB.fullSynchronous"); sFullSynchronousMode = Preferences::GetBool("dom.indexedDB.fullSynchronous");
Preferences::RegisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingDetails);
#ifdef MOZ_ENABLE_PROFILER_SPS
Preferences::RegisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingProfiler);
#endif
Preferences::RegisterCallbackAndCall(LoggingModePrefChangedCallback,
kPrefLoggingEnabled);
return NS_OK; return NS_OK;
} }
@ -314,6 +351,15 @@ IndexedDatabaseManager::Destroy()
Preferences::UnregisterCallback(TestingPrefChangedCallback, kTestingPref); Preferences::UnregisterCallback(TestingPrefChangedCallback, kTestingPref);
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingDetails);
#ifdef MOZ_ENABLE_PROFILER_SPS
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingProfiler);
#endif
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingEnabled);
delete this; delete this;
} }
@ -491,7 +537,30 @@ IndexedDatabaseManager::InLowDiskSpaceMode()
"initialized!"); "initialized!");
return sLowDiskSpaceMode; return sLowDiskSpaceMode;
} }
#endif
// static
IndexedDatabaseManager::LoggingMode
IndexedDatabaseManager::GetLoggingMode()
{
MOZ_ASSERT(gDBManager,
"GetLoggingMode called before IndexedDatabaseManager has been "
"initialized!");
return sLoggingMode;
}
// static
PRLogModuleInfo*
IndexedDatabaseManager::GetLoggingModule()
{
MOZ_ASSERT(gDBManager,
"GetLoggingModule called before IndexedDatabaseManager has been "
"initialized!");
return sLoggingModule;
}
#endif // DEBUG
// static // static
bool bool
@ -687,6 +756,44 @@ IndexedDatabaseManager::BlockAndGetFileReferences(
return NS_OK; return NS_OK;
} }
// static
void
IndexedDatabaseManager::LoggingModePrefChangedCallback(
const char* /* aPrefName */,
void* /* aClosure */)
{
MOZ_ASSERT(NS_IsMainThread());
if (!Preferences::GetBool(kPrefLoggingEnabled)) {
sLoggingMode = Logging_Disabled;
return;
}
bool useProfiler =
#if defined(DEBUG) || defined(MOZ_ENABLE_PROFILER_SPS)
Preferences::GetBool(kPrefLoggingProfiler);
#if !defined(MOZ_ENABLE_PROFILER_SPS)
if (useProfiler) {
NS_WARNING("IndexedDB cannot create profiler marks because this build does "
"not have profiler extensions enabled!");
useProfiler = false;
}
#endif
#else
false;
#endif
const bool logDetails = Preferences::GetBool(kPrefLoggingDetails);
if (useProfiler) {
sLoggingMode = logDetails ?
Logging_DetailedProfilerMarks :
Logging_ConciseProfilerMarks;
} else {
sLoggingMode = logDetails ? Logging_Detailed : Logging_Concise;
}
}
NS_IMPL_ADDREF(IndexedDatabaseManager) NS_IMPL_ADDREF(IndexedDatabaseManager)
NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy()) NS_IMPL_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver) NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver)

View File

@ -17,6 +17,7 @@
#include "nsHashKeys.h" #include "nsHashKeys.h"
class nsPIDOMWindow; class nsPIDOMWindow;
struct PRLogModuleInfo;
namespace mozilla { namespace mozilla {
@ -36,6 +37,15 @@ class IndexedDatabaseManager MOZ_FINAL : public nsIObserver
typedef mozilla::dom::quota::PersistenceType PersistenceType; typedef mozilla::dom::quota::PersistenceType PersistenceType;
public: public:
enum LoggingMode
{
Logging_Disabled = 0,
Logging_Concise,
Logging_Detailed,
Logging_ConciseProfilerMarks,
Logging_DetailedProfilerMarks
};
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER NS_DECL_NSIOBSERVER
@ -76,6 +86,26 @@ public:
static bool static bool
FullSynchronous(); FullSynchronous();
static LoggingMode
GetLoggingMode()
#ifdef DEBUG
;
#else
{
return sLoggingMode;
}
#endif
static PRLogModuleInfo*
GetLoggingModule()
#ifdef DEBUG
;
#else
{
return sLoggingModule;
}
#endif
already_AddRefed<FileManager> already_AddRefed<FileManager>
GetFileManager(PersistenceType aPersistenceType, GetFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin, const nsACString& aOrigin,
@ -143,6 +173,9 @@ private:
void void
Destroy(); Destroy();
static void
LoggingModePrefChangedCallback(const char* aPrefName, void* aClosure);
// Maintains a list of all file managers per origin. This list isn't // Maintains a list of all file managers per origin. This list isn't
// protected by any mutex but it is only ever touched on the IO thread. // protected by any mutex but it is only ever touched on the IO thread.
nsClassHashtable<nsCStringHashKey, FileManagerInfo> mFileManagerInfos; nsClassHashtable<nsCStringHashKey, FileManagerInfo> mFileManagerInfos;
@ -154,6 +187,8 @@ private:
static bool sIsMainProcess; static bool sIsMainProcess;
static bool sFullSynchronousMode; static bool sFullSynchronousMode;
static PRLogModuleInfo* sLoggingModule;
static Atomic<LoggingMode> sLoggingMode;
static mozilla::Atomic<bool> sLowDiskSpaceMode; static mozilla::Atomic<bool> sLowDiskSpaceMode;
}; };

View File

@ -51,6 +51,8 @@ parent:
PBackgroundIDBFactoryRequest(FactoryRequestParams params); PBackgroundIDBFactoryRequest(FactoryRequestParams params);
IncrementLoggingRequestSerialNumber();
child: child:
__delete__(); __delete__();

View File

@ -5,6 +5,8 @@
include protocol PBlob; include protocol PBlob;
include protocol PBackgroundIDBDatabaseFile; include protocol PBackgroundIDBDatabaseFile;
include DOMTypes;
include "mozilla/dom/indexedDB/SerializationHelpers.h"; include "mozilla/dom/indexedDB/SerializationHelpers.h";
using struct mozilla::void_t using struct mozilla::void_t
@ -253,6 +255,14 @@ union RequestParams
IndexCountParams; IndexCountParams;
}; };
struct LoggingInfo
{
nsID backgroundChildLoggingId;
int64_t nextTransactionSerialNumber;
int64_t nextVersionChangeTransactionSerialNumber;
uint64_t nextRequestSerialNumber;
};
} // namespace indexedDB } // namespace indexedDB
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla

View File

@ -7,40 +7,76 @@
#ifndef mozilla_dom_indexeddb_profilerhelpers_h__ #ifndef mozilla_dom_indexeddb_profilerhelpers_h__
#define mozilla_dom_indexeddb_profilerhelpers_h__ #define mozilla_dom_indexeddb_profilerhelpers_h__
// This file is not exported and is only meant to be included in IndexedDB
// source files.
#include "BackgroundChildImpl.h"
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
// Uncomment this if you want IndexedDB operations to be marked in the profiler.
//#define IDB_PROFILER_USE_MARKS
// Uncomment this if you want extended details to appear in profiler marks.
//#define IDB_PROFILER_MARK_DETAILS 0
// Sanity check the options above.
#if defined(IDB_PROFILER_USE_MARKS) && !defined(MOZ_ENABLE_PROFILER_SPS)
#error Cannot use IDB_PROFILER_USE_MARKS without MOZ_ENABLE_PROFILER_SPS!
#endif
#if defined(IDB_PROFILER_MARK_DETAILS) && !defined(IDB_PROFILER_USE_MARKS)
#error Cannot use IDB_PROFILER_MARK_DETAILS without IDB_PROFILER_USE_MARKS!
#endif
#ifdef IDB_PROFILER_USE_MARKS
#ifdef IDB_PROFILER_MARK_DETAILS
#include "IDBCursor.h" #include "IDBCursor.h"
#include "IDBDatabase.h" #include "IDBDatabase.h"
#include "IDBIndex.h" #include "IDBIndex.h"
#include "IDBKeyRange.h" #include "IDBKeyRange.h"
#include "IDBObjectStore.h" #include "IDBObjectStore.h"
#include "IDBTransaction.h" #include "IDBTransaction.h"
#include "IndexedDatabaseManager.h"
#include "Key.h" #include "Key.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsDebug.h"
#include "nsID.h"
#include "nsIDOMEvent.h"
#include "nsString.h"
#include "prlog.h"
// Include this last to avoid path problems on Windows.
#include "ActorsChild.h"
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
namespace indexedDB { namespace indexedDB {
class ProfilerString : public nsAutoCString class MOZ_STACK_CLASS LoggingIdString MOZ_FINAL
: public nsAutoCString
{
public:
LoggingIdString()
{
using mozilla::ipc::BackgroundChildImpl;
BackgroundChildImpl::ThreadLocal* threadLocal =
BackgroundChildImpl::GetThreadLocalForCurrentThread();
MOZ_ASSERT(threadLocal);
ThreadLocal* idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
MOZ_ASSERT(idbThreadLocal);
Init(idbThreadLocal->Id());
}
explicit
LoggingIdString(const nsID& aID)
{
Init(aID);
}
private:
void
Init(const nsID& aID)
{
static_assert(NSID_LENGTH > 1, "NSID_LENGTH is set incorrectly!");
MOZ_ASSERT(Capacity() > NSID_LENGTH);
// NSID_LENGTH counts the null terminator, SetLength() does not.
SetLength(NSID_LENGTH - 1);
aID.ToProvidedString(
*reinterpret_cast<char(*)[NSID_LENGTH]>(BeginWriting()));
}
};
class MOZ_STACK_CLASS LoggingString MOZ_FINAL
: public nsAutoCString
{ {
static const char kQuote = '\"'; static const char kQuote = '\"';
static const char kOpenBracket = '['; static const char kOpenBracket = '[';
@ -50,20 +86,38 @@ class ProfilerString : public nsAutoCString
public: public:
explicit explicit
ProfilerString(IDBDatabase* aDatabase) LoggingString(IDBDatabase* aDatabase)
: nsAutoCString(kQuote)
{ {
MOZ_ASSERT(aDatabase); MOZ_ASSERT(aDatabase);
Append(kQuote);
AppendUTF16toUTF8(aDatabase->Name(), *this); AppendUTF16toUTF8(aDatabase->Name(), *this);
Append(kQuote); Append(kQuote);
} }
explicit explicit
ProfilerString(IDBTransaction* aTransaction) LoggingString(IDBTransaction* aTransaction)
: nsAutoCString(kOpenBracket)
{ {
MOZ_ASSERT(aTransaction); MOZ_ASSERT(aTransaction);
NS_NAMED_LITERAL_CSTRING(kCommaSpace, ", ");
const nsTArray<nsString>& stores = aTransaction->ObjectStoreNamesInternal();
for (uint32_t count = stores.Length(), index = 0; index < count; index++) {
Append(kQuote);
AppendUTF16toUTF8(stores[index], *this);
Append(kQuote);
if (index != count - 1) {
Append(kCommaSpace);
}
}
Append(kCloseBracket);
Append(kCommaSpace);
switch (aTransaction->GetMode()) { switch (aTransaction->GetMode()) {
case IDBTransaction::READ_ONLY: case IDBTransaction::READ_ONLY:
AppendLiteral("\"readonly\""); AppendLiteral("\"readonly\"");
@ -80,128 +134,198 @@ public:
} }
explicit explicit
ProfilerString(IDBObjectStore* aObjectStore) LoggingString(IDBObjectStore* aObjectStore)
: nsAutoCString(kQuote)
{ {
MOZ_ASSERT(aObjectStore); MOZ_ASSERT(aObjectStore);
Append(kQuote);
AppendUTF16toUTF8(aObjectStore->Name(), *this); AppendUTF16toUTF8(aObjectStore->Name(), *this);
Append(kQuote); Append(kQuote);
} }
explicit explicit
ProfilerString(IDBIndex* aIndex) LoggingString(IDBIndex* aIndex)
: nsAutoCString(kQuote)
{ {
MOZ_ASSERT(aIndex); MOZ_ASSERT(aIndex);
Append(kQuote);
AppendUTF16toUTF8(aIndex->Name(), *this); AppendUTF16toUTF8(aIndex->Name(), *this);
Append(kQuote); Append(kQuote);
} }
explicit explicit
ProfilerString(IDBKeyRange* aKeyRange) LoggingString(IDBKeyRange* aKeyRange)
{ {
if (aKeyRange) { if (aKeyRange) {
if (aKeyRange->IsOnly()) { if (aKeyRange->IsOnly()) {
Append(ProfilerString(aKeyRange->Lower())); Assign(LoggingString(aKeyRange->Lower()));
} } else {
else { Assign(aKeyRange->LowerOpen() ? kOpenParen : kOpenBracket);
Append(aKeyRange->IsLowerOpen() ? kOpenParen : kOpenBracket); Append(LoggingString(aKeyRange->Lower()));
Append(ProfilerString(aKeyRange->Lower()));
AppendLiteral(", "); AppendLiteral(", ");
Append(ProfilerString(aKeyRange->Upper())); Append(LoggingString(aKeyRange->Upper()));
Append(aKeyRange->IsUpperOpen() ? kCloseParen : kCloseBracket); Append(aKeyRange->UpperOpen() ? kCloseParen : kCloseBracket);
} }
} else {
AssignLiteral("<undefined>");
} }
} }
explicit explicit
ProfilerString(const Key& aKey) LoggingString(const Key& aKey)
{ {
if (aKey.IsUnset()) { if (aKey.IsUnset()) {
AssignLiteral("null"); AssignLiteral("<undefined>");
} } else if (aKey.IsFloat()) {
else if (aKey.IsFloat()) {
AppendPrintf("%g", aKey.ToFloat()); AppendPrintf("%g", aKey.ToFloat());
} } else if (aKey.IsDate()) {
else if (aKey.IsDate()) {
AppendPrintf("<Date %g>", aKey.ToDateMsec()); AppendPrintf("<Date %g>", aKey.ToDateMsec());
} } else if (aKey.IsString()) {
else if (aKey.IsString()) {
nsAutoString str; nsAutoString str;
aKey.ToString(str); aKey.ToString(str);
AppendPrintf("\"%s\"", NS_ConvertUTF16toUTF8(str).get()); AppendPrintf("\"%s\"", NS_ConvertUTF16toUTF8(str).get());
} } else {
else {
MOZ_ASSERT(aKey.IsArray()); MOZ_ASSERT(aKey.IsArray());
AppendLiteral("<Array>"); AssignLiteral("[...]");
} }
} }
explicit explicit
ProfilerString(const IDBCursor::Direction aDirection) LoggingString(const IDBCursor::Direction aDirection)
{ {
switch (aDirection) { switch (aDirection) {
case IDBCursor::NEXT: case IDBCursor::NEXT:
AppendLiteral("\"next\""); AssignLiteral("\"next\"");
break; break;
case IDBCursor::NEXT_UNIQUE: case IDBCursor::NEXT_UNIQUE:
AppendLiteral("\"nextunique\""); AssignLiteral("\"nextunique\"");
break; break;
case IDBCursor::PREV: case IDBCursor::PREV:
AppendLiteral("\"prev\""); AssignLiteral("\"prev\"");
break; break;
case IDBCursor::PREV_UNIQUE: case IDBCursor::PREV_UNIQUE:
AppendLiteral("\"prevunique\""); AssignLiteral("\"prevunique\"");
break; break;
default: default:
MOZ_CRASH("Unknown direction!"); MOZ_CRASH("Unknown direction!");
}; };
} }
explicit
LoggingString(const Optional<uint64_t>& aVersion)
{
if (aVersion.WasPassed()) {
AppendInt(aVersion.Value());
} else {
AssignLiteral("<undefined>");
}
}
explicit
LoggingString(const Optional<uint32_t>& aLimit)
{
if (aLimit.WasPassed()) {
AppendInt(aLimit.Value());
} else {
AssignLiteral("<undefined>");
}
}
LoggingString(IDBObjectStore* aObjectStore, const Key& aKey)
{
MOZ_ASSERT(aObjectStore);
if (!aObjectStore->HasValidKeyPath()) {
Append(LoggingString(aKey));
}
}
LoggingString(nsIDOMEvent* aEvent, const char16_t* aDefault)
: nsAutoCString(kQuote)
{
MOZ_ASSERT(aDefault);
nsString eventType;
if (aEvent) {
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aEvent->GetType(eventType)));
} else {
eventType = nsDependentString(aDefault);
}
AppendUTF16toUTF8(eventType, *this);
Append(kQuote);
}
}; };
inline void
LoggingHelper(bool aUseProfiler, const char* aFmt, ...)
{
MOZ_ASSERT(IndexedDatabaseManager::GetLoggingMode() !=
IndexedDatabaseManager::Logging_Disabled);
MOZ_ASSERT(aFmt);
PRLogModuleInfo* logModule = IndexedDatabaseManager::GetLoggingModule();
MOZ_ASSERT(logModule);
static const PRLogModuleLevel logLevel = PR_LOG_DEBUG;
if (PR_LOG_TEST(logModule, logLevel) ||
(aUseProfiler && profiler_is_active())) {
nsAutoCString message;
{
va_list args;
va_start(args, aFmt);
message.AppendPrintf(aFmt, args);
va_end(args);
}
PR_LOG(logModule, logLevel, ("%s", message.get()));
if (aUseProfiler) {
PROFILER_MARKER(message.get());
}
}
}
} // namespace indexedDB } // namespace indexedDB
} // namespace dom } // namespace dom
} // namespace mozilla } // namespace mozilla
#define IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, ...) \ #define IDB_LOG_MARK(_detailedFmt, _conciseFmt, ...) \
do { \ do { \
nsAutoCString _mark; \ using namespace mozilla::dom::indexedDB; \
_mark.AppendPrintf(_detailedFmt, ##__VA_ARGS__); \ \
PROFILER_MARKER(_mark.get()); \ const IndexedDatabaseManager::LoggingMode mode = \
} while (0) IndexedDatabaseManager::GetLoggingMode(); \
\
#define IDB_PROFILER_STRING(_arg) \ if (mode != IndexedDatabaseManager::Logging_Disabled) { \
mozilla::dom::indexedDB::ProfilerString((_arg)).get() const char* _fmt; \
if (mode == IndexedDatabaseManager::Logging_Concise || \
#else // IDB_PROFILER_MARK_DETAILS mode == IndexedDatabaseManager::Logging_ConciseProfilerMarks) { \
_fmt = _conciseFmt; \
#define IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, ...) \ } else { \
do { \ MOZ_ASSERT( \
nsAutoCString _mark; \ mode == IndexedDatabaseManager::Logging_Detailed || \
_mark.AppendPrintf(_conciseFmt, ##__VA_ARGS__); \ mode == IndexedDatabaseManager::Logging_DetailedProfilerMarks); \
PROFILER_MARKER(_mark.get()); \ _fmt = _detailedFmt; \
} while (0) } \
\
#define IDB_PROFILER_STRING(_arg) "" const bool _useProfiler = \
mode == IndexedDatabaseManager::Logging_ConciseProfilerMarks || \
#endif // IDB_PROFILER_MARK_DETAILS mode == IndexedDatabaseManager::Logging_DetailedProfilerMarks; \
\
#define IDB_PROFILER_MARK_IF(_cond, _detailedFmt, _conciseFmt, ...) \ LoggingHelper(_useProfiler, _fmt, ##__VA_ARGS__); \
do { \
if (_cond) { \
IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, __VA_ARGS__); \
} \ } \
} while (0) } while (0)
#else // IDB_PROFILER_USE_MARKS #define IDB_LOG_ID_STRING(...) \
mozilla::dom::indexedDB::LoggingIdString(__VA_ARGS__).get()
#define IDB_PROFILER_MARK(...) do { } while(0) #define IDB_LOG_STRINGIFY(...) \
#define IDB_PROFILER_MARK_IF(_cond, ...) do { } while(0) mozilla::dom::indexedDB::LoggingString(__VA_ARGS__).get()
#define IDB_PROFILER_MARK2(_detailedFmt, _notdetailedFmt, ...) do { } while(0)
#define IDB_PROFILER_STRING(_arg) ""
#endif // IDB_PROFILER_USE_MARKS
#endif // mozilla_dom_indexeddb_profilerhelpers_h__ #endif // mozilla_dom_indexeddb_profilerhelpers_h__

View File

@ -144,7 +144,9 @@ class TransactionThreadPool::TransactionQueue MOZ_FINAL
Monitor mMonitor; Monitor mMonitor;
nsRefPtr<TransactionThreadPool> mOwningThreadPool; nsRefPtr<TransactionThreadPool> mOwningThreadPool;
uint64_t mTransactionId; const uint64_t mTransactionId;
const nsID mBackgroundChildLoggingId;
const int64_t mLoggingSerialNumber;
const nsCString mDatabaseId; const nsCString mDatabaseId;
const nsTArray<nsString> mObjectStoreNames; const nsTArray<nsString> mObjectStoreNames;
uint16_t mMode; uint16_t mMode;
@ -155,10 +157,12 @@ class TransactionThreadPool::TransactionQueue MOZ_FINAL
public: public:
TransactionQueue(TransactionThreadPool* aThreadPool, TransactionQueue(TransactionThreadPool* aThreadPool,
uint64_t aTransactionId, uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
const nsTArray<nsString>& aObjectStoreNames, const nsTArray<nsString>& aObjectStoreNames,
uint16_t aMode); uint16_t aMode,
const nsID& aBackgroundChildLoggingId,
int64_t aLoggingSerialNumber);
NS_DECL_ISUPPORTS_INHERITED NS_DECL_ISUPPORTS_INHERITED
@ -187,13 +191,21 @@ struct TransactionThreadPool::TransactionInfo MOZ_FINAL
uint64_t aTransactionId, uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
const nsTArray<nsString>& aObjectStoreNames, const nsTArray<nsString>& aObjectStoreNames,
uint16_t aMode) uint16_t aMode,
const nsID& aBackgroundChildLoggingId,
int64_t aLoggingSerialNumber)
: transactionId(aTransactionId), databaseId(aDatabaseId) : transactionId(aTransactionId), databaseId(aDatabaseId)
{ {
MOZ_COUNT_CTOR(TransactionInfo); MOZ_COUNT_CTOR(TransactionInfo);
queue = new TransactionQueue(aThreadPool, aTransactionId, aDatabaseId, queue =
aObjectStoreNames, aMode); new TransactionQueue(aThreadPool,
aTransactionId,
aDatabaseId,
aObjectStoreNames,
aMode,
aBackgroundChildLoggingId,
aLoggingSerialNumber);
} }
~TransactionInfo() ~TransactionInfo()
@ -302,7 +314,6 @@ TransactionThreadPool::Shutdown()
} }
} }
// static
uint64_t uint64_t
TransactionThreadPool::NextTransactionId() TransactionThreadPool::NextTransactionId()
{ {
@ -548,20 +559,17 @@ TransactionThreadPool::GetQueueForTransaction(uint64_t aTransactionId,
} }
TransactionThreadPool::TransactionQueue& TransactionThreadPool::TransactionQueue&
TransactionThreadPool::GetQueueForTransaction( TransactionThreadPool::CreateQueueForTransaction(
uint64_t aTransactionId, uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
const nsTArray<nsString>& aObjectStoreNames, const nsTArray<nsString>& aObjectStoreNames,
uint16_t aMode) uint16_t aMode,
const nsID& aBackgroundChildLoggingId,
int64_t aLoggingSerialNumber)
{ {
AssertIsOnOwningThread(); AssertIsOnOwningThread();
MOZ_ASSERT(aTransactionId <= mNextTransactionId); MOZ_ASSERT(aTransactionId <= mNextTransactionId);
MOZ_ASSERT(!GetQueueForTransaction(aTransactionId, aDatabaseId));
TransactionQueue* existingQueue =
GetQueueForTransaction(aTransactionId, aDatabaseId);
if (existingQueue) {
return *existingQueue;
}
// See if we can run this transaction now. // See if we can run this transaction now.
DatabaseTransactionInfo* dbTransactionInfo; DatabaseTransactionInfo* dbTransactionInfo;
@ -579,11 +587,14 @@ TransactionThreadPool::GetQueueForTransaction(
return *info->queue; return *info->queue;
} }
TransactionInfo* transactionInfo = new TransactionInfo(this, TransactionInfo* transactionInfo =
aTransactionId, new TransactionInfo(this,
aDatabaseId, aTransactionId,
aObjectStoreNames, aDatabaseId,
aMode); aObjectStoreNames,
aMode,
aBackgroundChildLoggingId,
aLoggingSerialNumber);
dbTransactionInfo->transactions.Put(aTransactionId, transactionInfo);; dbTransactionInfo->transactions.Put(aTransactionId, transactionInfo);;
@ -633,26 +644,27 @@ TransactionThreadPool::GetQueueForTransaction(
} }
void void
TransactionThreadPool::Dispatch(uint64_t aTransactionId, TransactionThreadPool::Start(uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
const nsTArray<nsString>& aObjectStoreNames, const nsTArray<nsString>& aObjectStoreNames,
uint16_t aMode, uint16_t aMode,
nsIRunnable* aRunnable, const nsID& aBackgroundChildLoggingId,
bool aFinish, int64_t aLoggingSerialNumber,
FinishCallback* aFinishCallback) nsIRunnable* aRunnable)
{ {
AssertIsOnOwningThread();
MOZ_ASSERT(aTransactionId <= mNextTransactionId); MOZ_ASSERT(aTransactionId <= mNextTransactionId);
MOZ_ASSERT(aRunnable);
MOZ_ASSERT(!mShutdownRequested); MOZ_ASSERT(!mShutdownRequested);
TransactionQueue& queue = GetQueueForTransaction(aTransactionId, TransactionQueue& queue = CreateQueueForTransaction(aTransactionId,
aDatabaseId, aDatabaseId,
aObjectStoreNames, aObjectStoreNames,
aMode); aMode,
aBackgroundChildLoggingId,
aLoggingSerialNumber);
queue.Dispatch(aRunnable); queue.Dispatch(aRunnable);
if (aFinish) {
queue.Finish(aFinishCallback);
}
} }
void void
@ -765,14 +777,18 @@ TransactionQueue::TransactionQueue(TransactionThreadPool* aThreadPool,
uint64_t aTransactionId, uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
const nsTArray<nsString>& aObjectStoreNames, const nsTArray<nsString>& aObjectStoreNames,
uint16_t aMode) uint16_t aMode,
: mMonitor("TransactionQueue::mMonitor"), const nsID& aBackgroundChildLoggingId,
mOwningThreadPool(aThreadPool), int64_t aLoggingSerialNumber)
mTransactionId(aTransactionId), : mMonitor("TransactionQueue::mMonitor")
mDatabaseId(aDatabaseId), , mOwningThreadPool(aThreadPool)
mObjectStoreNames(aObjectStoreNames), , mTransactionId(aTransactionId)
mMode(aMode), , mBackgroundChildLoggingId(aBackgroundChildLoggingId)
mShouldFinish(false) , mLoggingSerialNumber(aLoggingSerialNumber)
, mDatabaseId(aDatabaseId)
, mObjectStoreNames(aObjectStoreNames)
, mMode(aMode)
, mShouldFinish(false)
{ {
MOZ_ASSERT(aThreadPool); MOZ_ASSERT(aThreadPool);
aThreadPool->AssertIsOnOwningThread(); aThreadPool->AssertIsOnOwningThread();
@ -824,9 +840,11 @@ TransactionThreadPool::TransactionQueue::Run()
"TransactionThreadPool::TransactionQueue""Run", "TransactionThreadPool::TransactionQueue""Run",
js::ProfileEntry::Category::STORAGE); js::ProfileEntry::Category::STORAGE);
IDB_PROFILER_MARK("IndexedDB Transaction %llu: Beginning database work", IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
"IDBTransaction[%llu] DT Start", "Beginning database work",
mTransaction->GetSerialNumber()); "IndexedDB %s: P T[%lld]: DB Start",
IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
mLoggingSerialNumber);
nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queue; nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queue;
nsRefPtr<FinishCallback> finishCallback; nsRefPtr<FinishCallback> finishCallback;
@ -877,9 +895,11 @@ TransactionThreadPool::TransactionQueue::Run()
} }
#endif // DEBUG #endif // DEBUG
IDB_PROFILER_MARK("IndexedDB Transaction %llu: Finished database work", IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
"IDBTransaction[%llu] DT Done", "Finished database work",
mTransaction->GetSerialNumber()); "IndexedDB %s: P T[%lld]: DB End",
IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
mLoggingSerialNumber);
nsRefPtr<FinishTransactionRunnable> finishTransactionRunnable = nsRefPtr<FinishTransactionRunnable> finishTransactionRunnable =
new FinishTransactionRunnable(mOwningThreadPool.forget(), new FinishTransactionRunnable(mOwningThreadPool.forget(),

View File

@ -15,6 +15,7 @@
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include "nsTArray.h" #include "nsTArray.h"
struct nsID;
class nsIEventTarget; class nsIEventTarget;
class nsIRunnable; class nsIRunnable;
class nsIThreadPool; class nsIThreadPool;
@ -55,13 +56,13 @@ public:
uint64_t NextTransactionId(); uint64_t NextTransactionId();
void Dispatch(uint64_t aTransactionId, void Start(uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
const nsTArray<nsString>& aObjectStoreNames, const nsTArray<nsString>& aObjectStoreNames,
uint16_t aMode, uint16_t aMode,
nsIRunnable* aRunnable, const nsID& aBackgroundChildLoggingId,
bool aFinish, int64_t aLoggingSerialNumber,
FinishCallback* aFinishCallback); nsIRunnable* aRunnable);
void Dispatch(uint64_t aTransactionId, void Dispatch(uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
@ -114,11 +115,13 @@ private:
TransactionQueue* GetQueueForTransaction(uint64_t aTransactionId, TransactionQueue* GetQueueForTransaction(uint64_t aTransactionId,
const nsACString& aDatabaseId); const nsACString& aDatabaseId);
TransactionQueue& GetQueueForTransaction( TransactionQueue& CreateQueueForTransaction(
uint64_t aTransactionId, uint64_t aTransactionId,
const nsACString& aDatabaseId, const nsACString& aDatabaseId,
const nsTArray<nsString>& aObjectStoreNames, const nsTArray<nsString>& aObjectStoreNames,
uint16_t aMode); uint16_t aMode,
const nsID& aBackgroundChildLoggingId,
int64_t aLoggingSerialNumber);
bool MaybeFireCallback(DatabasesCompleteCallback* aCallback); bool MaybeFireCallback(DatabasesCompleteCallback* aCallback);

View File

@ -268,7 +268,7 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
// switching to the end of the buffered range. // switching to the end of the buffered range.
MOZ_ASSERT(aReason == END_OF_STREAM); MOZ_ASSERT(aReason == END_OF_STREAM);
if (mVideoReader) { if (mVideoReader) {
AdjustEndTime(&mLastVideoTime, mAudioReader); AdjustEndTime(&mLastVideoTime, mVideoReader);
} }
// See if we can find a different reader that can pick up where we left off. We use the // See if we can find a different reader that can pick up where we left off. We use the

View File

@ -234,8 +234,8 @@ public:
// The following metrics are all in widget space/device pixels. // The following metrics are all in widget space/device pixels.
// //
// This is the area within the widget that we're compositing to. It is relative // This is the area within the widget that we're compositing to. It is in the
// to the layer tree origin. // same coordinate space as the reference frame for the scrolled frame.
// //
// This is useful because, on mobile, the viewport and composition dimensions // This is useful because, on mobile, the viewport and composition dimensions
// are not always the same. In this case, we calculate the displayport using // are not always the same. In this case, we calculate the displayport using
@ -256,11 +256,8 @@ public:
// space, so each is explained separately. // space, so each is explained separately.
// //
// The area of a frame's contents that has been painted, relative to the // The area of a frame's contents that has been painted, relative to
// viewport. It is in the same coordinate space as |mViewport|. For example, // mCompositionBounds.
// if it is at 0,0, then it's at the same place at the viewport, which is at
// the top-left in the layer, and at the same place as the scroll offset of
// the document.
// //
// Note that this is structured in such a way that it doesn't depend on the // Note that this is structured in such a way that it doesn't depend on the
// method layout uses to scroll content. // method layout uses to scroll content.

View File

@ -127,7 +127,12 @@ InputQueue::ReceiveScrollWheelInput(const nsRefPtr<AsyncPanZoomController>& aTar
uint64_t* aOutInputBlockId) { uint64_t* aOutInputBlockId) {
WheelBlockState* block = nullptr; WheelBlockState* block = nullptr;
if (!mInputBlockQueue.IsEmpty()) { if (!mInputBlockQueue.IsEmpty()) {
block = mInputBlockQueue.LastElement().get()->AsWheelBlock(); block = mInputBlockQueue.LastElement()->AsWheelBlock();
// If the block's APZC has been destroyed, request a new block.
if (block && block->GetTargetApzc()->IsDestroyed()) {
block = nullptr;
}
} }
if (!block) { if (!block) {

View File

@ -164,8 +164,7 @@ APZCCallbackHelper::UpdateRootFrame(nsIDOMWindowUtils* aUtils,
margins.bottom, margins.bottom,
element, 0); element, 0);
CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels();
nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), nsRect base(0, 0,
baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(),
baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base); nsLayoutUtils::SetDisplayPortBaseIfNotSet(content, base);
@ -208,8 +207,7 @@ APZCCallbackHelper::UpdateSubFrame(nsIContent* aContent,
margins.bottom, margins.bottom,
element, 0); element, 0);
CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels();
nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(), nsRect base(0, 0,
baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(),
baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
baseCSS.height * nsPresContext::AppUnitsPerCSSPixel()); baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base); nsLayoutUtils::SetDisplayPortBaseIfNotSet(aContent, base);

View File

@ -4,12 +4,14 @@
#include "BackgroundChildImpl.h" #include "BackgroundChildImpl.h"
#include "ActorsChild.h" // IndexedDB
#include "FileDescriptorSetChild.h" #include "FileDescriptorSetChild.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/dom/PBlobChild.h" #include "mozilla/dom/PBlobChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h" #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
#include "mozilla/dom/ipc/BlobChild.h" #include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/ipc/PBackgroundTestChild.h" #include "mozilla/ipc/PBackgroundTestChild.h"
#include "nsID.h"
#include "nsTraceRefcnt.h" #include "nsTraceRefcnt.h"
namespace { namespace {
@ -48,11 +50,6 @@ namespace ipc {
BackgroundChildImpl:: BackgroundChildImpl::
ThreadLocal::ThreadLocal() ThreadLocal::ThreadLocal()
: mCurrentTransaction(nullptr)
#ifdef MOZ_ENABLE_PROFILER_SPS
, mNextTransactionSerialNumber(1)
, mNextRequestSerialNumber(1)
#endif
{ {
// May happen on any thread! // May happen on any thread!
MOZ_COUNT_CTOR(mozilla::ipc::BackgroundChildImpl::ThreadLocal); MOZ_COUNT_CTOR(mozilla::ipc::BackgroundChildImpl::ThreadLocal);
@ -136,7 +133,8 @@ BackgroundChildImpl::DeallocPBackgroundTestChild(PBackgroundTestChild* aActor)
} }
BackgroundChildImpl::PBackgroundIDBFactoryChild* BackgroundChildImpl::PBackgroundIDBFactoryChild*
BackgroundChildImpl::AllocPBackgroundIDBFactoryChild() BackgroundChildImpl::AllocPBackgroundIDBFactoryChild(
const LoggingInfo& aLoggingInfo)
{ {
MOZ_CRASH("PBackgroundIDBFactoryChild actors should be manually " MOZ_CRASH("PBackgroundIDBFactoryChild actors should be manually "
"constructed!"); "constructed!");

View File

@ -7,14 +7,13 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/ipc/PBackgroundChild.h" #include "mozilla/ipc/PBackgroundChild.h"
#include "nsAutoPtr.h"
template <class> class nsAutoPtr;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
namespace indexedDB { namespace indexedDB {
class IDBTransaction; class ThreadLocal;
} // namespace indexedDB } // namespace indexedDB
} // namespace dom } // namespace dom
@ -53,7 +52,7 @@ protected:
DeallocPBackgroundTestChild(PBackgroundTestChild* aActor) MOZ_OVERRIDE; DeallocPBackgroundTestChild(PBackgroundTestChild* aActor) MOZ_OVERRIDE;
virtual PBackgroundIDBFactoryChild* virtual PBackgroundIDBFactoryChild*
AllocPBackgroundIDBFactoryChild() MOZ_OVERRIDE; AllocPBackgroundIDBFactoryChild(const LoggingInfo& aLoggingInfo) MOZ_OVERRIDE;
virtual bool virtual bool
DeallocPBackgroundIDBFactoryChild(PBackgroundIDBFactoryChild* aActor) DeallocPBackgroundIDBFactoryChild(PBackgroundIDBFactoryChild* aActor)
@ -78,12 +77,7 @@ class BackgroundChildImpl::ThreadLocal MOZ_FINAL
friend class nsAutoPtr<ThreadLocal>; friend class nsAutoPtr<ThreadLocal>;
public: public:
mozilla::dom::indexedDB::IDBTransaction* mCurrentTransaction; nsAutoPtr<mozilla::dom::indexedDB::ThreadLocal> mIndexedDBThreadLocal;
#ifdef MOZ_ENABLE_PROFILER_SPS
uint64_t mNextTransactionSerialNumber;
uint64_t mNextRequestSerialNumber;
#endif
public: public:
ThreadLocal(); ThreadLocal();

View File

@ -119,7 +119,8 @@ BackgroundParentImpl::DeallocPBackgroundTestParent(
} }
auto auto
BackgroundParentImpl::AllocPBackgroundIDBFactoryParent() BackgroundParentImpl::AllocPBackgroundIDBFactoryParent(
const LoggingInfo& aLoggingInfo)
-> PBackgroundIDBFactoryParent* -> PBackgroundIDBFactoryParent*
{ {
using mozilla::dom::indexedDB::AllocPBackgroundIDBFactoryParent; using mozilla::dom::indexedDB::AllocPBackgroundIDBFactoryParent;
@ -127,12 +128,13 @@ BackgroundParentImpl::AllocPBackgroundIDBFactoryParent()
AssertIsInMainProcess(); AssertIsInMainProcess();
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
return AllocPBackgroundIDBFactoryParent(); return AllocPBackgroundIDBFactoryParent(aLoggingInfo);
} }
bool bool
BackgroundParentImpl::RecvPBackgroundIDBFactoryConstructor( BackgroundParentImpl::RecvPBackgroundIDBFactoryConstructor(
PBackgroundIDBFactoryParent* aActor) PBackgroundIDBFactoryParent* aActor,
const LoggingInfo& aLoggingInfo)
{ {
using mozilla::dom::indexedDB::RecvPBackgroundIDBFactoryConstructor; using mozilla::dom::indexedDB::RecvPBackgroundIDBFactoryConstructor;
@ -140,18 +142,20 @@ BackgroundParentImpl::RecvPBackgroundIDBFactoryConstructor(
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor); MOZ_ASSERT(aActor);
return RecvPBackgroundIDBFactoryConstructor(aActor); return RecvPBackgroundIDBFactoryConstructor(aActor, aLoggingInfo);
} }
bool bool
BackgroundParentImpl::DeallocPBackgroundIDBFactoryParent( BackgroundParentImpl::DeallocPBackgroundIDBFactoryParent(
PBackgroundIDBFactoryParent* aActor) PBackgroundIDBFactoryParent* aActor)
{ {
using mozilla::dom::indexedDB::DeallocPBackgroundIDBFactoryParent;
AssertIsInMainProcess(); AssertIsInMainProcess();
AssertIsOnBackgroundThread(); AssertIsOnBackgroundThread();
MOZ_ASSERT(aActor); MOZ_ASSERT(aActor);
return mozilla::dom::indexedDB::DeallocPBackgroundIDBFactoryParent(aActor); return DeallocPBackgroundIDBFactoryParent(aActor);
} }
auto auto

View File

@ -33,10 +33,12 @@ protected:
DeallocPBackgroundTestParent(PBackgroundTestParent* aActor) MOZ_OVERRIDE; DeallocPBackgroundTestParent(PBackgroundTestParent* aActor) MOZ_OVERRIDE;
virtual PBackgroundIDBFactoryParent* virtual PBackgroundIDBFactoryParent*
AllocPBackgroundIDBFactoryParent() MOZ_OVERRIDE; AllocPBackgroundIDBFactoryParent(const LoggingInfo& aLoggingInfo)
MOZ_OVERRIDE;
virtual bool virtual bool
RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor) RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor,
const LoggingInfo& aLoggingInfo)
MOZ_OVERRIDE; MOZ_OVERRIDE;
virtual bool virtual bool

View File

@ -8,6 +8,7 @@ include protocol PBlob;
include protocol PFileDescriptorSet; include protocol PFileDescriptorSet;
include DOMTypes; include DOMTypes;
include PBackgroundIDBSharedTypes;
namespace mozilla { namespace mozilla {
namespace ipc { namespace ipc {
@ -23,7 +24,7 @@ parent:
// Only called at startup during mochitests to check the basic infrastructure. // Only called at startup during mochitests to check the basic infrastructure.
PBackgroundTest(nsCString testArg); PBackgroundTest(nsCString testArg);
PBackgroundIDBFactory(); PBackgroundIDBFactory(LoggingInfo loggingInfo);
both: both:
PBlob(BlobConstructorParams params); PBlob(BlobConstructorParams params);

View File

@ -130,6 +130,7 @@ SOURCES += [
] ]
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'/dom/indexedDB',
'/xpcom/build', '/xpcom/build',
] ]

View File

@ -831,6 +831,7 @@ void wasapi_stream_destroy(cubeb_stream * stm)
SafeRelease(stm->client); SafeRelease(stm->client);
SafeRelease(stm->render_client); SafeRelease(stm->render_client);
SafeRelease(stm->audio_clock); SafeRelease(stm->audio_clock);
SafeRelease(stm->audio_stream_volume);
cubeb_resampler_destroy(stm->resampler); cubeb_resampler_destroy(stm->resampler);

View File

@ -32,12 +32,24 @@
namespace mozilla { namespace mozilla {
// IdealSegmentSize is how big each segment will be in bytes (or as close as is // |IdealSegmentSize| specifies how big each segment will be in bytes (or as
// possible). It's best to choose a size that's a power-of-two (to avoid slop) // close as is possible). Use the following guidelines to choose a size.
// and moderately large (not too small so segment allocations are infrequent, //
// and not too large so that not too much space is wasted when the final // - It should be a power-of-two, to avoid slop.
// segment is not full). Something like 4096 or 8192 is probably good. //
template<typename T, size_t IdealSegmentSize, // - It should not be too small, so that segment allocations are infrequent,
// and so that per-segment bookkeeping overhead is low. Typically each
// segment should be able to hold hundreds of elements, at least.
//
// - It should not be too large, so that OOMs are unlikely when allocating
// segments, and so that not too much space is wasted when the final segment
// is not full.
//
// The ideal size depends on how the SegmentedVector is used and the size of
// |T|, but reasonable sizes include 1024, 4096 (the default), 8192, and 16384.
//
template<typename T,
size_t IdealSegmentSize = 4096,
typename AllocPolicy = MallocAllocPolicy> typename AllocPolicy = MallocAllocPolicy>
class SegmentedVector : private AllocPolicy class SegmentedVector : private AllocPolicy
{ {

View File

@ -147,7 +147,7 @@ void TestSegmentCapacitiesAndAlignments()
SegmentedVector<B, 999> v3(999); SegmentedVector<B, 999> v3(999);
SegmentedVector<C, 10> v4(10); SegmentedVector<C, 10> v4(10);
SegmentedVector<D, 1234> v5(1234); SegmentedVector<D, 1234> v5(1234);
SegmentedVector<E, 4096> v6(4096); SegmentedVector<E> v6(4096); // 4096 is the default segment size
SegmentedVector<mozilla::AlignedElem<16>, 100> v7(100); SegmentedVector<mozilla::AlignedElem<16>, 100> v7(100);
} }

View File

@ -135,7 +135,7 @@ public class OverlayActionService extends Service {
OverlayToastHelper.showFailureToast(getApplicationContext(), shareMethod.getFailureMessage()); OverlayToastHelper.showFailureToast(getApplicationContext(), shareMethod.getFailureMessage());
break; break;
default: default:
Assert.isTrue(false, "Unknown share method result code: " + result); Assert.fail("Unknown share method result code: " + result);
break; break;
} }
} }

View File

@ -163,7 +163,7 @@ public class SendTabDeviceListArrayAdapter extends ArrayAdapter<ParcelableClient
showDummyRecord(getContext().getResources().getString(R.string.overlay_share_send_other)); showDummyRecord(getContext().getResources().getString(R.string.overlay_share_send_other));
break; break;
default: default:
Assert.isTrue(false, "Unexpected state transition: " + newState); Assert.fail("Unexpected state transition: " + newState);
} }
} }

View File

@ -48,18 +48,15 @@ public final class Prefs {
} }
} }
/* Prefs must be created on application startup or service startup. public static Prefs getInstance(Context c) {
* TODO: turn into regular singleton if Context dependency can be removed. */ if (sInstance == null) {
public static void createGlobalInstance(Context c) { sInstance = new Prefs(c);
if (sInstance != null) {
return;
} }
sInstance = new Prefs(c); return sInstance;
} }
/* Only access after CreatePrefsInstance(Context) has been called at startup. */ // Allows code without a context handle to grab the prefs. The caller must null check the return value.
public static Prefs getInstance() { public static Prefs getInstanceWithoutContext() {
assert(sInstance != null);
return sInstance; return sInstance;
} }

View File

@ -4,6 +4,7 @@
package org.mozilla.mozstumbler.service.stumblerthread; package org.mozilla.mozstumbler.service.stumblerthread;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.location.Location; import android.location.Location;
import android.os.AsyncTask; import android.os.AsyncTask;
@ -16,7 +17,6 @@ import org.mozilla.mozstumbler.service.Prefs;
import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface; import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInterface;
import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager; import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
import org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager; import org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager;
import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
import org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver; import org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver;
import org.mozilla.mozstumbler.service.utils.NetworkUtils; import org.mozilla.mozstumbler.service.utils.NetworkUtils;
import org.mozilla.mozstumbler.service.utils.PersistentIntentService; import org.mozilla.mozstumbler.service.utils.PersistentIntentService;
@ -68,8 +68,8 @@ public class StumblerService extends PersistentIntentService
mScanManager.setWifiBlockList(list); mScanManager.setWifiBlockList(list);
} }
public Prefs getPrefs() { public Prefs getPrefs(Context c) {
return Prefs.getInstance(); return Prefs.getInstance(c);
} }
public void checkPrefs() { public void checkPrefs() {
@ -116,7 +116,8 @@ public class StumblerService extends PersistentIntentService
// use (i.e. Fennec), init() can be called from this class's dedicated thread. // use (i.e. Fennec), init() can be called from this class's dedicated thread.
// Safe to call more than once, ensure added code complies with that intent. // Safe to call more than once, ensure added code complies with that intent.
protected void init() { protected void init() {
Prefs.createGlobalInstance(this); // Ensure Prefs is created, so internal utility code can use getInstanceWithoutContext
Prefs.getInstance(this);
NetworkUtils.createGlobalInstance(this); NetworkUtils.createGlobalInstance(this);
DataStorageManager.createGlobalInstance(this, this); DataStorageManager.createGlobalInstance(this, this);
@ -150,7 +151,7 @@ public class StumblerService extends PersistentIntentService
} }
if (!sFirefoxStumblingEnabled.get()) { if (!sFirefoxStumblingEnabled.get()) {
Prefs.getInstance().setFirefoxScanEnabled(false); Prefs.getInstance(StumblerService.this).setFirefoxScanEnabled(false);
} }
if (DataStorageManager.getInstance() != null) { if (DataStorageManager.getInstance() != null) {
@ -182,7 +183,7 @@ public class StumblerService extends PersistentIntentService
return; return;
} }
final boolean isScanEnabledInPrefs = Prefs.getInstance().getFirefoxScanEnabled(); final boolean isScanEnabledInPrefs = Prefs.getInstance(this).getFirefoxScanEnabled();
if (!isScanEnabledInPrefs && intent.getBooleanExtra(ACTION_NOT_FROM_HOST_APP, false)) { if (!isScanEnabledInPrefs && intent.getBooleanExtra(ACTION_NOT_FROM_HOST_APP, false)) {
stopSelf(); stopSelf();
@ -198,7 +199,7 @@ public class StumblerService extends PersistentIntentService
// This is the only upload trigger in Firefox mode // This is the only upload trigger in Firefox mode
// Firefox triggers this ~4 seconds after startup (after Gecko is loaded), add a small delay to avoid // Firefox triggers this ~4 seconds after startup (after Gecko is loaded), add a small delay to avoid
// clustering with other operations that are triggered at this time. // clustering with other operations that are triggered at this time.
final long lastAttemptedTime = Prefs.getInstance().getLastAttemptedUploadTime(); final long lastAttemptedTime = Prefs.getInstance(this).getLastAttemptedUploadTime();
final long timeNow = System.currentTimeMillis(); final long timeNow = System.currentTimeMillis();
if (timeNow - lastAttemptedTime < PASSIVE_UPLOAD_FREQ_GUARD_MSEC) { if (timeNow - lastAttemptedTime < PASSIVE_UPLOAD_FREQ_GUARD_MSEC) {
@ -207,23 +208,23 @@ public class StumblerService extends PersistentIntentService
Log.d(LOG_TAG, "Upload attempt too frequent."); Log.d(LOG_TAG, "Upload attempt too frequent.");
} }
} else { } else {
Prefs.getInstance().setLastAttemptedUploadTime(timeNow); Prefs.getInstance(this).setLastAttemptedUploadTime(timeNow);
UploadAlarmReceiver.scheduleAlarm(this, DELAY_IN_SEC_BEFORE_STARTING_UPLOAD_IN_PASSIVE_MODE, false /* no repeat*/); UploadAlarmReceiver.scheduleAlarm(this, DELAY_IN_SEC_BEFORE_STARTING_UPLOAD_IN_PASSIVE_MODE, false /* no repeat*/);
} }
} }
if (!isScanEnabledInPrefs) { if (!isScanEnabledInPrefs) {
Prefs.getInstance().setFirefoxScanEnabled(true); Prefs.getInstance(this).setFirefoxScanEnabled(true);
} }
String apiKey = intent.getStringExtra(ACTION_EXTRA_MOZ_API_KEY); String apiKey = intent.getStringExtra(ACTION_EXTRA_MOZ_API_KEY);
if (apiKey != null && !apiKey.equals(Prefs.getInstance().getMozApiKey())) { if (apiKey != null && !apiKey.equals(Prefs.getInstance(this).getMozApiKey())) {
Prefs.getInstance().setMozApiKey(apiKey); Prefs.getInstance(this).setMozApiKey(apiKey);
} }
String userAgent = intent.getStringExtra(ACTION_EXTRA_USER_AGENT); String userAgent = intent.getStringExtra(ACTION_EXTRA_USER_AGENT);
if (userAgent != null && !userAgent.equals(Prefs.getInstance().getUserAgent())) { if (userAgent != null && !userAgent.equals(Prefs.getInstance(this).getUserAgent())) {
Prefs.getInstance().setUserAgent(userAgent); Prefs.getInstance(this).setUserAgent(userAgent);
} }
if (!mScanManager.isScanning()) { if (!mScanManager.isScanning()) {

View File

@ -164,7 +164,11 @@ public class GPSScanner implements LocationListener {
mBlockList.updateBlocks(); mBlockList.updateBlocks();
} }
mAutoGeofencing = Prefs.getInstance().getGeofenceHere(); Prefs prefs = Prefs.getInstanceWithoutContext();
if (prefs == null) {
return;
}
mAutoGeofencing = prefs.getGeofenceHere();
} }
public boolean isGeofenced() { public boolean isGeofenced() {
@ -186,7 +190,7 @@ public class GPSScanner implements LocationListener {
String provider = location.getProvider(); String provider = location.getProvider();
if (!provider.toLowerCase().contains("gps")) { if (!provider.toLowerCase().contains("gps")) {
sendToLogActivity(logMsg + "Discard fused/network location."); Log.d(LOG_TAG, "Discard fused/network location.");
// only interested in GPS locations // only interested in GPS locations
return; return;
} }

View File

@ -28,8 +28,12 @@ public final class LocationBlockList {
} }
public void updateBlocks() { public void updateBlocks() {
mBlockedLocation = Prefs.getInstance().getGeofenceLocation(); Prefs prefs = Prefs.getInstanceWithoutContext();
mGeofencingEnabled = Prefs.getInstance().getGeofenceEnabled(); if (prefs == null) {
return;
}
mBlockedLocation = prefs.getGeofenceLocation();
mGeofencingEnabled = prefs.getGeofenceEnabled();
} }
public boolean contains(Location location) { public boolean contains(Location location) {

View File

@ -74,12 +74,13 @@ public class WifiScanner extends BroadcastReceiver {
public synchronized void start(final ActiveOrPassiveStumbling stumblingMode) { public synchronized void start(final ActiveOrPassiveStumbling stumblingMode) {
if (mStarted) { Prefs prefs = Prefs.getInstanceWithoutContext();
if (mStarted || prefs == null) {
return; return;
} }
mStarted = true; mStarted = true;
boolean scanAlways = Prefs.getInstance().getWifiScanAlways(); boolean scanAlways = prefs.getWifiScanAlways();
if (scanAlways || isWifiEnabled()) { if (scanAlways || isWifiEnabled()) {
activatePeriodicScan(stumblingMode); activatePeriodicScan(stumblingMode);

View File

@ -112,10 +112,6 @@ public class AsyncUploader extends AsyncTask<Void, Void, SyncSummary> {
private class Submitter extends AbstractCommunicator { private class Submitter extends AbstractCommunicator {
private static final String SUBMIT_URL = "https://location.services.mozilla.com/v1/submit"; private static final String SUBMIT_URL = "https://location.services.mozilla.com/v1/submit";
public Submitter() {
super(Prefs.getInstance().getUserAgent());
}
@Override @Override
public String getUrlString() { public String getUrlString() {
return SUBMIT_URL; return SUBMIT_URL;

View File

@ -48,7 +48,8 @@ public class UploadAlarmReceiver extends BroadcastReceiver {
@Override @Override
protected void onHandleIntent(Intent intent) { protected void onHandleIntent(Intent intent) {
boolean isRepeating = intent.getBooleanExtra(EXTRA_IS_REPEATING, true); // Default to a repeating alarm, which is what Fennec Stumbler uses
boolean isRepeating = (intent == null)? true : intent.getBooleanExtra(EXTRA_IS_REPEATING, true);
if (DataStorageManager.getInstance() == null) { if (DataStorageManager.getInstance() == null) {
DataStorageManager.createGlobalInstance(this, null); DataStorageManager.createGlobalInstance(this, null);
} }
@ -77,9 +78,9 @@ public class UploadAlarmReceiver extends BroadcastReceiver {
!AsyncUploader.isUploading()) { !AsyncUploader.isUploading()) {
Log.d(LOG_TAG, "Alarm upload(), call AsyncUploader"); Log.d(LOG_TAG, "Alarm upload(), call AsyncUploader");
AsyncUploader.UploadSettings settings = AsyncUploader.UploadSettings settings =
new AsyncUploader.UploadSettings(Prefs.getInstance().getWifiScanAlways(), Prefs.getInstance().getUseWifiOnly()); new AsyncUploader.UploadSettings(Prefs.getInstance(this).getWifiScanAlways(), Prefs.getInstance(this).getUseWifiOnly());
AsyncUploader uploader = new AsyncUploader(settings, null); AsyncUploader uploader = new AsyncUploader(settings, null);
uploader.setNickname(Prefs.getInstance().getNickname()); uploader.setNickname(Prefs.getInstance(this).getNickname());
uploader.execute(); uploader.execute();
// we could listen for completion and cancel, instead, cancel on next alarm when db empty // we could listen for completion and cancel, instead, cancel on next alarm when db empty
} }

View File

@ -61,14 +61,16 @@ public abstract class AbstractCommunicator {
return null; return null;
} }
public AbstractCommunicator(String userAgent) { public AbstractCommunicator() {
mUserAgent = userAgent; Prefs prefs = Prefs.getInstanceWithoutContext();
mUserAgent = (prefs != null)? prefs.getUserAgent() : "fennec-stumbler-unset-user-agent";
} }
private void openConnectionAndSetHeaders() { private void openConnectionAndSetHeaders() {
try { try {
if (sMozApiKey == null) { Prefs prefs = Prefs.getInstanceWithoutContext();
sMozApiKey = Prefs.getInstance().getMozApiKey(); if (sMozApiKey == null || prefs != null) {
sMozApiKey = prefs.getMozApiKey();
} }
URL url = new URL(getUrlString() + "?key=" + sMozApiKey); URL url = new URL(getUrlString() + "?key=" + sMozApiKey);
mHttpURLConnection = (HttpURLConnection) url.openConnection(); mHttpURLConnection = (HttpURLConnection) url.openConnection();

View File

@ -119,6 +119,12 @@ pref("dom.indexedDB.enabled", true);
pref("dom.indexedDB.warningQuota", 50); pref("dom.indexedDB.warningQuota", 50);
// Whether or not indexedDB experimental features are enabled. // Whether or not indexedDB experimental features are enabled.
pref("dom.indexedDB.experimental", false); pref("dom.indexedDB.experimental", false);
// Enable indexedDB logging.
pref("dom.indexedDB.logging.enabled", true);
// Detailed output in log messages.
pref("dom.indexedDB.logging.details", true);
// Enable profiler marks for indexedDB events.
pref("dom.indexedDB.logging.profiler-marks", false);
// Whether or not Web Workers are enabled. // Whether or not Web Workers are enabled.
pref("dom.workers.enabled", true); pref("dom.workers.enabled", true);

View File

@ -200,13 +200,17 @@ NS_NewFileURI(nsIURI* *result,
inline nsresult inline nsresult
NS_NewChannelInternal(nsIChannel** outChannel, NS_NewChannelInternal(nsIChannel** outChannel,
nsIURI* aUri, nsIURI* aUri,
nsILoadInfo* aLoadInfo, nsINode* aRequestingNode,
nsIPrincipal* aRequestingPrincipal,
nsIPrincipal* aTriggeringPrincipal,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsIURI* aBaseURI = nullptr,
nsILoadGroup* aLoadGroup = nullptr, nsILoadGroup* aLoadGroup = nullptr,
nsIInterfaceRequestor* aCallbacks = nullptr, nsIInterfaceRequestor* aCallbacks = nullptr,
nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL, nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL,
nsIIOService* aIoService = nullptr) nsIIOService* aIoService = nullptr)
{ {
NS_ASSERTION(aLoadInfo, "Can not create channel without aLoadInfo!");
NS_ENSURE_ARG_POINTER(outChannel); NS_ENSURE_ARG_POINTER(outChannel);
nsCOMPtr<nsIIOService> grip; nsCOMPtr<nsIIOService> grip;
@ -234,11 +238,31 @@ NS_NewChannelInternal(nsIChannel** outChannel,
rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE)); rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
} }
channel->SetLoadInfo(aLoadInfo);
// Some channels might already have a loadInfo attached at this
// point (see bug 1104623). We have to make sure to update
// security flags in such cases before we set the loadinfo.
// Once bug 1087442 lands, this problem disappears because we
// attach the loadinfo in each individual protocol handler.
nsCOMPtr<nsILoadInfo> loadInfo;
channel->GetLoadInfo(getter_AddRefs(loadInfo));
if (loadInfo) {
aSecurityFlags |= loadInfo->GetSecurityFlags();
}
// create a new Loadinfo with the potentially updated securityFlags
loadInfo =
new mozilla::LoadInfo(aRequestingPrincipal, aTriggeringPrincipal,
aRequestingNode, aSecurityFlags,
aContentPolicyType, aBaseURI);
if (!loadInfo) {
return NS_ERROR_UNEXPECTED;
}
channel->SetLoadInfo(loadInfo);
// If we're sandboxed, make sure to clear any owner the channel // If we're sandboxed, make sure to clear any owner the channel
// might already have. // might already have.
if (aLoadInfo->GetLoadingSandboxed()) { if (loadInfo->GetLoadingSandboxed()) {
channel->SetOwner(nullptr); channel->SetOwner(nullptr);
} }
@ -249,31 +273,27 @@ NS_NewChannelInternal(nsIChannel** outChannel,
inline nsresult inline nsresult
NS_NewChannelInternal(nsIChannel** outChannel, NS_NewChannelInternal(nsIChannel** outChannel,
nsIURI* aUri, nsIURI* aUri,
nsINode* aRequestingNode, nsILoadInfo* aLoadInfo,
nsIPrincipal* aRequestingPrincipal,
nsIPrincipal* aTriggeringPrincipal,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsILoadGroup* aLoadGroup = nullptr, nsILoadGroup* aLoadGroup = nullptr,
nsIInterfaceRequestor* aCallbacks = nullptr, nsIInterfaceRequestor* aCallbacks = nullptr,
nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL, nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL,
nsIIOService* aIoService = nullptr) nsIIOService* aIoService = nullptr)
{ {
NS_ASSERTION(aRequestingPrincipal, "Can not create channel without a requesting Principal!"); MOZ_ASSERT(aLoadInfo, "Can not create a channel without a loadInfo");
nsresult rv = NS_NewChannelInternal(outChannel,
nsCOMPtr<nsILoadInfo> loadInfo = aUri,
new mozilla::LoadInfo(aRequestingPrincipal, aTriggeringPrincipal, aLoadInfo->LoadingNode(),
aRequestingNode, aSecurityFlags, aContentPolicyType); aLoadInfo->LoadingPrincipal(),
if (!loadInfo) { aLoadInfo->TriggeringPrincipal(),
return NS_ERROR_UNEXPECTED; aLoadInfo->GetSecurityFlags(),
} aLoadInfo->GetContentPolicyType(),
return NS_NewChannelInternal(outChannel, aLoadInfo->BaseURI(),
aUri, aLoadGroup,
loadInfo, aCallbacks,
aLoadGroup, aLoadFlags,
aCallbacks, aIoService);
aLoadFlags, NS_ENSURE_SUCCESS(rv, rv);
aIoService); return NS_OK;
} }
inline nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */ inline nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
@ -297,6 +317,7 @@ NS_NewChannelWithTriggeringPrincipal(nsIChannel** outChannel,
aTriggeringPrincipal, aTriggeringPrincipal,
aSecurityFlags, aSecurityFlags,
aContentPolicyType, aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup, aLoadGroup,
aCallbacks, aCallbacks,
aLoadFlags, aLoadFlags,
@ -323,6 +344,7 @@ NS_NewChannelWithTriggeringPrincipal(nsIChannel** outChannel,
aTriggeringPrincipal, aTriggeringPrincipal,
aSecurityFlags, aSecurityFlags,
aContentPolicyType, aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup, aLoadGroup,
aCallbacks, aCallbacks,
aLoadFlags, aLoadFlags,
@ -348,6 +370,7 @@ NS_NewChannel(nsIChannel** outChannel,
nullptr, // aTriggeringPrincipal nullptr, // aTriggeringPrincipal
aSecurityFlags, aSecurityFlags,
aContentPolicyType, aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup, aLoadGroup,
aCallbacks, aCallbacks,
aLoadFlags, aLoadFlags,
@ -372,6 +395,7 @@ NS_NewChannel(nsIChannel** outChannel,
nullptr, // aTriggeringPrincipal nullptr, // aTriggeringPrincipal
aSecurityFlags, aSecurityFlags,
aContentPolicyType, aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup, aLoadGroup,
aCallbacks, aCallbacks,
aLoadFlags, aLoadFlags,
@ -406,6 +430,7 @@ NS_OpenURIInternal(nsIInputStream** outStream,
aTriggeringPrincipal, aTriggeringPrincipal,
aSecurityFlags, aSecurityFlags,
aContentPolicyType, aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup, aLoadGroup,
aCallbacks, aCallbacks,
aLoadFlags, aLoadFlags,
@ -962,6 +987,7 @@ NS_NewStreamLoaderInternal(nsIStreamLoader** outStream,
nullptr, // aTriggeringPrincipal nullptr, // aTriggeringPrincipal
aSecurityFlags, aSecurityFlags,
aContentPolicyType, aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup, aLoadGroup,
aCallbacks, aCallbacks,
aLoadFlags); aLoadFlags);

View File

@ -15,9 +15,6 @@ Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services", XPCOMUtils.defineLazyModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm"); "resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserNewTabPreloader",
"resource:///modules/BrowserNewTabPreloader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader", XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm"); "resource:///modules/CustomizationTabPreloader.jsm");
@ -504,7 +501,13 @@ Tester.prototype = {
Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm", {}); Cu.import("resource://gre/modules/BackgroundPageThumbs.jsm", {});
BackgroundPageThumbs._destroy(); BackgroundPageThumbs._destroy();
BrowserNewTabPreloader.uninit(); // Destroy preloaded browsers.
if (gBrowser._preloadedBrowser) {
let browser = gBrowser._preloadedBrowser;
gBrowser._preloadedBrowser = null;
gBrowser.getNotificationBox(browser).remove();
}
CustomizationTabPreloader.uninit(); CustomizationTabPreloader.uninit();
SocialFlyout.unload(); SocialFlyout.unload();
SocialShare.uninit(); SocialShare.uninit();

View File

@ -684,16 +684,15 @@ AutoRefreshHighlighter.prototype = {
_startRefreshLoop: function() { _startRefreshLoop: function() {
let win = this.currentNode.ownerDocument.defaultView; let win = this.currentNode.ownerDocument.defaultView;
this.rafID = win.requestAnimationFrame(this._startRefreshLoop.bind(this)); this.rafID = win.requestAnimationFrame(this._startRefreshLoop.bind(this));
this.rafWin = win;
this.update(); this.update();
}, },
_stopRefreshLoop: function() { _stopRefreshLoop: function() {
if (!this.rafID) { if (this.rafID && !Cu.isDeadWrapper(this.rafWin)) {
return; this.rafWin.cancelAnimationFrame(this.rafID);
} }
let win = this.currentNode.ownerDocument.defaultView; this.rafID = this.rafWin = null;
win.cancelAnimationFrame(this.rafID);
this.rafID = null;
}, },
destroy: function() { destroy: function() {