Merge mozilla-central to b2g-inbound

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

View File

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

View File

@ -982,6 +982,15 @@ HyperTextAccessible::NativeAttributes()
} else if (tag == nsGkAtoms::main) {
nsAccUtils::SetAccAttr(attributes, nsGkAtoms::xmlroles,
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();

View File

@ -22,8 +22,17 @@
var thisTabDocAcc = getTabDocAccessible();
var thisDocTabPanelAcc = thisTabDocAcc.parent.parent;
var tabPanelsAcc = thisDocTabPanelAcc.parent;
var newDocTabPanelAcc = tabPanelsAcc.lastChild.firstChild;
return newDocTabPanelAcc.firstChild;
var newDocTabPanelAcc = tabPanelsAcc.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)

View File

@ -1232,7 +1232,12 @@
//////////////////////////////////////////////////////////////////////////
// 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

View File

@ -15,25 +15,6 @@
src="../role.js"></script>
<script type="application/javascript"
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"
src="../events.js"></script>
@ -193,12 +174,6 @@
var accTree = {
role: ROLE_APP_ROOT,
children: [
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},
{
role: ROLE_CHROME_WINDOW
},

View File

@ -31,10 +31,15 @@
is(root.parentDocument, null,
"Wrong parent document of root accessible");
is(root.childDocumentCount, 1,
ok(root.childDocumentCount >= 1,
"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,
"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 DOORHANGER_ACTIVATE_DELAY_MS = 5000;
const SYNC_MIGRATION_NOTIFICATION_TITLE = "fxa-migration";
let gFxAccounts = {
@ -157,7 +158,7 @@ let gFxAccounts = {
setTimeout(() => this.onSyncStart(), DOORHANGER_ACTIVATE_DELAY_MS);
} else {
this._inCustomizationMode = event.type == "customizationstarting";
this.updateUI();
this.updateAppMenuItem();
}
},
@ -182,8 +183,13 @@ let gFxAccounts = {
},
updateUI: function () {
this.updateAppMenuItem();
this.updateMigrationNotification();
},
updateAppMenuItem: function () {
if (this._migrationInfo) {
this.showMigrationUI();
this.updateAppMenuItemForMigration();
return;
}
@ -241,32 +247,74 @@ let gFxAccounts = {
});
},
showMigrationUI: Task.async(function* () {
updateAppMenuItemForMigration: Task.async(function* () {
let status = null;
let label = null;
switch (this._migrationInfo.state) {
case fxaMigrator.STATE_USER_FXA:
status = "migrate-signup";
label = this.strings.formatStringFromName("needUser",
label = this.strings.formatStringFromName("needUserShort",
[this.button.getAttribute("fxabrandname")], 1);
break;
case fxaMigrator.STATE_USER_FXA_VERIFIED:
if (this._migrationInfo.email) {
status = "migrate-verify";
label = this.strings.formatStringFromName("needVerifiedUser",
[this._migrationInfo.email],
1);
}
status = "migrate-verify";
label = this.strings.formatStringFromName("needVerifiedUserShort",
[this._migrationInfo.email],
1);
break;
}
if (label && status) {
this.button.label = label;
this.button.hidden = false;
this.button.setAttribute("fxastatus", status);
} else {
Cu.reportError("Could not update menu panel button given migration " +
"state: " + this._migrationInfo.state);
this.button.label = label;
this.button.hidden = false;
this.button.setAttribute("fxastatus", status);
}),
updateMigrationNotification: Task.async(function* () {
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) {

View File

@ -13,8 +13,6 @@ let CloudSync = null;
// gSyncUI handles updating the tools menu and displaying notifications.
let gSyncUI = {
DEFAULT_EOL_URL: "https://www.mozilla.org/firefox/?utm_source=synceol",
_obs: ["weave:service:sync:start",
"weave:service:quota:remaining",
"weave:service:setup-complete",
@ -27,7 +25,6 @@ let gSyncUI = {
"weave:ui:sync:error",
"weave:ui:sync:finish",
"weave:ui:clear-error",
"weave:eol",
],
_unloaded: false,
@ -260,32 +257,6 @@ let gSyncUI = {
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 () {
let statusURL = Services.prefs.getCharPref("services.sync.statusURL");
window.openUILinkIn(statusURL, "tab");
@ -551,9 +522,6 @@ let gSyncUI = {
case "weave:ui:clear-error":
this.clearError();
break;
case "weave:eol":
this.onEOLNotice(subject);
break;
}
},

View File

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

View File

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

View File

@ -1513,6 +1513,134 @@
</body>
</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">
<parameter name="aURI"/>
<parameter name="aReferrerURI"/>
@ -1583,55 +1711,23 @@
if (aOwner)
t.owner = aOwner;
var b = document.createElementNS(
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.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"));
let b;
let usingPreloadedContent = false;
let isPrivateWindow = PrivateBrowsingUtils.isWindowPrivate(window);
if (remote)
b.setAttribute("remote", "true");
if (window.gShowPageResizers && window.windowState == window.STATE_NORMAL) {
b.setAttribute("showresizer", "true");
// If we open a new tab with the newtab URL,
// check if there is a preloaded browser ready.
if (aURI == BROWSER_NEW_TAB_URL && !isPrivateWindow) {
b = this._getPreloadedBrowser();
usingPreloadedContent = !!b;
}
if (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);
if (!b) {
// No preloaded browser found, create one.
b = this._createBrowser({remote, uriIsAboutBlank});
}
let notificationbox = this.getNotificationBox(b);
var position = this.tabs.length - 1;
var uniqueId = this._generateUniquePanelID();
notificationbox.id = uniqueId;
@ -1642,19 +1738,16 @@
t.lastAccessed = Date.now();
this.tabContainer._setPositionalAttributes();
// 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");
// Inject the <browser> into the DOM if necessary.
if (!notificationbox.parentNode) {
// 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);
}
// 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
// allows the TabLabelModified event to be properly dispatched.
if (!aURI || isBlankPageURL(aURI)) {
@ -1677,16 +1770,9 @@
b.droppedLinkHandler = handleDroppedLink;
// If we just created a new tab that loads the default
// newtab url, swap in a preloaded page if possible.
// Do nothing if we're a private window.
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);
// Swap in a preloaded customize tab, if available.
if (aURI == "about:customizing") {
usingPreloadedContent = gCustomizationTabPreloader.newTab(t);
}
// 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
// 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
// the document successfully loads
if (aURI && gInitialPages.indexOf(aURI) == -1)
@ -4279,6 +4365,9 @@
// without any scrolling and when the tabbar has already
// overflowed.
this.mTabstrip._updateScrollButtonsDisabledState();
// Preload the next about:newtab if there isn't one already.
this.tabbrowser._createPreloadBrowser();
]]></body>
</method>

View File

@ -2,6 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
const STATE_CHANGED_TOPIC = "fxa-migration:state-changed";
const NOTIFICATION_TITLE = "fxa-migration";
let 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() {
// Fake the state where we need an FxA user.
let buttonPromise = promiseButtonMutation();
Services.obs.notifyObservers(null, "fxa-migration:state-changed",
Services.obs.notifyObservers(null, STATE_CHANGED_TOPIC,
fxaMigrator.STATE_USER_FXA);
let buttonState = yield buttonPromise;
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.
buttonPromise = promiseButtonMutation();
let email = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
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);
buttonState = yield buttonPromise;
assertButtonState(buttonState, "migrate-verify", true,
"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.
buttonPromise = promiseButtonMutation();
Services.obs.notifyObservers(null, "fxa-migration:state-changed", null);
Services.obs.notifyObservers(null, STATE_CHANGED_TOPIC, null);
buttonState = yield buttonPromise;
// 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,
// the button is left with no fxastatus.
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,

View File

@ -11,7 +11,6 @@ const CAPTURE_PREF = "browser.pagethumbnails.capturing_disabled";
function runTests() {
let imports = {};
Cu.import("resource://gre/modules/PageThumbs.jsm", imports);
Cu.import("resource:///modules/BrowserNewTabPreloader.jsm", imports);
// Disable captures.
let originalDisabledState = Services.prefs.getBoolPref(CAPTURE_PREF);
@ -31,32 +30,15 @@ function runTests() {
yield setLinks("-1");
// 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
// of a hidden newtab, and then keep calling BrowserNewTabPreloader.newTab
// 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();
// doesn't allow background captures. Ensure we have a preloaded browser.
gBrowser._createPreloadBrowser();
// When newtab is loaded very quickly (which is what happens in 99% of cases)
// there is no need to wait so no tests are run. Because each test requires
// 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.");
// Wait for the preloaded browser to load.
yield waitForBrowserLoad(gBrowser._preloadedBrowser);
let swapWaitCount = 0;
let swapped = imports.BrowserNewTabPreloader.newTab(tab);
while (!swapped) {
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.
// We're now ready to use the preloaded browser.
BrowserOpenTab();
let tab = gBrowser.selectedTab;
let doc = tab.linkedBrowser.contentDocument;
// Enable captures.
@ -67,8 +49,11 @@ function runTests() {
if (data != url)
return;
Services.obs.removeObserver(onCreate, "page-thumbnail:create");
ok(true, "thumbnail created after preloaded tab was shown");
// Test finished!
Services.prefs.setBoolPref(CAPTURE_PREF, originalDisabledState);
gBrowser.removeTab(tab);
file.remove(false);
TestRunner.next();
}, "page-thumbnail:create", false);
@ -76,7 +61,3 @@ function runTests() {
info("Waiting for thumbnail capture");
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.
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
whenNewTabLoaded();
}, true);
waitForBrowserLoad(browser, function () {
// Wait for the document to become visible in case it was preloaded.
waitForCondition(() => !browser.contentDocument.hidden).then(whenNewTabLoaded);
});
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.
* @param the pattern (see below)

View File

@ -828,9 +828,15 @@ let MozLoopServiceInternal = {
let window = chatbox.contentWindow;
window.addEventListener("unload", function onUnloadChat(evt) {
UITour.notify("Loop:ChatWindowClosed");
});
function socialFrameChanged(eventName) {
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);

View File

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

View File

@ -1,7 +1,19 @@
# LOCALIZATION NOTE (needUser)
# %S = Firefox Accounts brand name from syncBrand.dtd
needUser = %S required for sync
# 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/.
# 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
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");
},
}],
["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", {
query: (aDocument) => {
let loopBrowser = aDocument.querySelector("#loop-notification-panel > #loop");
@ -1375,8 +1385,7 @@ this.UITour = {
hideLoopPanelAnnotations: function(aEvent) {
UITour.hideAnnotationsForPanel(aEvent, (aTarget) => {
// TODO: Bug 1104927 - Handle the conversation targets separately.
return aTarget.targetName.startsWith("loop-");
return aTarget.targetName.startsWith("loop-") && aTarget.targetName != "loop-selectedRoomButtons";
});
},

View File

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

View File

@ -90,9 +90,12 @@ let tests = [
gContentAPI.observe((event, params) => {
is(event, "Loop:ChatWindowOpened", "Check Loop:ChatWindowOpened notification");
gContentAPI.observe((event, params) => {
is(event, "Loop:ChatWindowClosed", "Check Loop:ChatWindowClosed notification");
is(event, "Loop:ChatWindowShown", "Check Loop:ChatWindowShown notification");
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();
});

View File

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

View File

@ -17,7 +17,7 @@ typedef unsigned long nsSecurityFlags;
/**
* 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
{
/**
@ -156,7 +156,7 @@ interface nsILoadInfo : nsISupports
* The contentPolicyType of the channel, used for security checks
* like Mixed Content Blocking and Content Security Policy.
*/
readonly attribute nsContentPolicyType contentPolicyType;
readonly attribute nsContentPolicyType contentPolicyType;
%{ C++
inline nsContentPolicyType GetContentPolicyType()
@ -173,5 +173,11 @@ interface nsILoadInfo : nsISupports
* 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.
*/
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 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
******************************************************************************/
@ -104,39 +135,40 @@ class MOZ_STACK_CLASS AutoSetCurrentTransaction MOZ_FINAL
IDBTransaction* const mTransaction;
IDBTransaction* mPreviousTransaction;
IDBTransaction** mThreadLocalSlot;
ThreadLocal* mThreadLocal;
public:
explicit AutoSetCurrentTransaction(IDBTransaction* aTransaction)
: mTransaction(aTransaction)
, mPreviousTransaction(nullptr)
, mThreadLocalSlot(nullptr)
, mThreadLocal(nullptr)
{
if (aTransaction) {
BackgroundChildImpl::ThreadLocal* threadLocal =
BackgroundChildImpl::GetThreadLocalForCurrentThread();
MOZ_ASSERT(threadLocal);
// Hang onto this location for resetting later.
mThreadLocalSlot = &threadLocal->mCurrentTransaction;
// Hang onto this for resetting later.
mThreadLocal = threadLocal->mIndexedDBThreadLocal;
MOZ_ASSERT(mThreadLocal);
// Save the current value.
mPreviousTransaction = *mThreadLocalSlot;
mPreviousTransaction = mThreadLocal->GetCurrentTransaction();
// Set the new value.
*mThreadLocalSlot = aTransaction;
mThreadLocal->SetCurrentTransaction(aTransaction);
}
}
~AutoSetCurrentTransaction()
{
MOZ_ASSERT_IF(mThreadLocalSlot, mTransaction);
if (mThreadLocalSlot) {
MOZ_ASSERT(*mThreadLocalSlot == mTransaction);
MOZ_ASSERT_IF(mThreadLocal, mTransaction);
MOZ_ASSERT_IF(mThreadLocal,
mThreadLocal->GetCurrentTransaction() == mTransaction);
if (mThreadLocal) {
// Reset old value.
*mThreadLocalSlot = mPreviousTransaction;
mThreadLocal->SetCurrentTransaction(mPreviousTransaction);
}
}
@ -589,6 +621,25 @@ DispatchErrorEvent(IDBRequest* aRequest,
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;
nsresult rv = request->DispatchEvent(aEvent, &doDefault);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -648,6 +699,22 @@ DispatchSuccessEvent(ResultHelper* aResultHelper,
MOZ_ASSERT(aEvent);
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;
nsresult rv = request->DispatchEvent(aEvent, &dummy);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -1068,6 +1135,11 @@ BackgroundFactoryRequestChild::RecvBlocked(const uint64_t& aCurrentVersion)
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;
if (NS_FAILED(mRequest->DispatchEvent(blockedEvent, &dummy))) {
NS_WARNING("Failed to dispatch event!");
@ -1357,6 +1429,10 @@ BackgroundDatabaseChild::RecvVersionChange(const uint64_t& aOldVersion,
return false;
}
IDB_LOG_MARK("IndexedDB %s: Child : Firing \"versionchange\" event",
"IndexedDB %s: C: IDBDatabase \"versionchange\" event",
IDB_LOG_ID_STRING());
bool dummy;
if (NS_FAILED(mDatabase->DispatchEvent(versionChangeEvent, &dummy))) {
NS_WARNING("Failed to dispatch event!");

View File

@ -5,6 +5,7 @@
#ifndef mozilla_dom_indexeddb_actorschild_h__
#define mozilla_dom_indexeddb_actorschild_h__
#include "IDBTransaction.h"
#include "js/RootingAPI.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBCursorChild.h"
@ -12,6 +13,7 @@
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBFactoryRequestChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBRequestChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBTransactionChild.h"
#include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionChild.h"
#include "nsAutoPtr.h"
@ -19,6 +21,7 @@
#include "nsTArray.h"
class nsIEventTarget;
struct nsID;
struct PRThread;
namespace mozilla {
@ -38,13 +41,97 @@ class IDBFactory;
class IDBMutableFile;
class IDBOpenDBRequest;
class IDBRequest;
class IDBTransaction;
class Key;
class PBackgroundIDBFileChild;
class PermissionRequestChild;
class PermissionRequestParent;
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
: public PBackgroundIDBFactoryChild
{

View File

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

View File

@ -7,6 +7,7 @@
template <class> struct already_AddRefed;
class nsCString;
struct nsID;
class nsIPrincipal;
class nsPIDOMWindow;
@ -23,14 +24,16 @@ class Client;
namespace indexedDB {
class LoggingInfo;
class PBackgroundIDBFactoryParent;
class PIndexedDBPermissionRequestParent;
PBackgroundIDBFactoryParent*
AllocPBackgroundIDBFactoryParent();
AllocPBackgroundIDBFactoryParent(const LoggingInfo& aLoggingInfo);
bool
RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor);
RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor,
const LoggingInfo& aLoggingInfo);
bool
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));
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
@ -478,36 +483,41 @@ IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
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));
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>
@ -563,7 +573,12 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
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()) {
return nullptr;
}
@ -575,7 +590,12 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
return nullptr;
}
request = objectStore->Put(aCx, aValue, keyVal, aRv);
request = objectStore->AddOrPut(aCx,
aValue,
keyVal,
/* aOverwrite */ true,
/* aFromCursor */ true,
aRv);
if (aRv.Failed()) {
return nullptr;
}
@ -583,37 +603,34 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
request->SetSource(this);
#ifdef IDB_PROFILER_USE_MARKS
{
uint64_t requestSerial = request->GetSerialNumber();
if (mType == Type_ObjectStore) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).update(%s)",
"IDBRequest[%llu] MT IDBCursor.update()",
requestSerial,
IDB_PROFILER_STRING(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction),
IDB_PROFILER_STRING(objectStore),
IDB_PROFILER_STRING(mDirection),
mObjectStore->HasValidKeyPath() ? "" :
IDB_PROFILER_STRING(primaryKey));
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).update(%s)",
"IDBRequest[%llu] MT IDBCursor.update()",
requestSerial,
IDB_PROFILER_STRING(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction),
IDB_PROFILER_STRING(objectStore),
IDB_PROFILER_STRING(mSourceIndex),
IDB_PROFILER_STRING(mDirection),
mObjectStore->HasValidKeyPath() ? "" :
IDB_PROFILER_STRING(primaryKey));
}
if (mType == Type_ObjectStore) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).update(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).update(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mSourceIndex),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
}
#endif
return request.forget();
}
@ -658,44 +675,42 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
return nullptr;
}
nsRefPtr<IDBRequest> request = objectStore->Delete(aCx, key, aRv);
nsRefPtr<IDBRequest> request =
objectStore->DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
if (aRv.Failed()) {
return nullptr;
}
request->SetSource(this);
#ifdef IDB_PROFILER_USE_MARKS
{
uint64_t requestSerial = request->GetSerialNumber();
if (mType == Type_ObjectStore) {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).delete(%s)",
"IDBRequest[%llu] MT IDBCursor.delete()",
requestSerial,
IDB_PROFILER_STRING(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction),
IDB_PROFILER_STRING(objectStore),
IDB_PROFILER_STRING(mDirection),
mObjectStore->HasValidKeyPath() ? "" :
IDB_PROFILER_STRING(primaryKey));
} else {
IDB_PROFILER_MARK("IndexedDB Request %llu: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).delete(%s)",
"IDBRequest[%llu] MT IDBCursor.delete()",
requestSerial,
IDB_PROFILER_STRING(mTransaction->Database()),
IDB_PROFILER_STRING(mTransaction),
IDB_PROFILER_STRING(objectStore),
IDB_PROFILER_STRING(mSourceIndex),
IDB_PROFILER_STRING(mDirection),
mObjectStore->HasValidKeyPath() ? "" :
IDB_PROFILER_STRING(primaryKey));
}
if (mType == Type_ObjectStore) {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"cursor(%s).delete(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
} else {
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"index(%s).cursor(%s).delete(%s)",
"IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
request->LoggingSerialNumber(),
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(objectStore),
IDB_LOG_STRINGIFY(mSourceIndex),
IDB_LOG_STRINGIFY(mDirection),
IDB_LOG_STRINGIFY(objectStore, primaryKey));
}
#endif
return request.forget();
}

View File

@ -506,12 +506,20 @@ IDBDatabase::CreateObjectStore(
transaction->CreateObjectStore(*newSpec);
MOZ_ASSERT(objectStore);
IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
"database(%s).transaction(%s).createObjectStore(%s)",
"MT IDBDatabase.createObjectStore()",
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(aTransaction),
IDB_PROFILER_STRING(objectStore));
// 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]: "
"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();
}
@ -559,12 +567,20 @@ IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv)
return;
}
IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
"database(%s).transaction(%s).deleteObjectStore(\"%s\")",
"MT IDBDatabase.deleteObjectStore()",
IDB_PROFILER_STRING(this),
IDB_PROFILER_STRING(transaction),
NS_ConvertUTF16toUTF8(aName).get());
// 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]: "
"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>
@ -669,6 +685,14 @@ IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
BackgroundTransactionChild* actor =
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(
mBackgroundActor->SendPBackgroundIDBTransactionConstructor(actor,
sortedStoreNames,
@ -676,11 +700,6 @@ IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
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();
}
@ -722,6 +741,8 @@ IDBDatabase::CreateMutableFile(const nsAString& aName,
type = aType.Value();
}
mFactory->IncrementParentLoggingRequestSerialNumber();
aRv = CreateFileHelper::CreateAndDispatch(this, request, aName, type);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;

View File

@ -6,6 +6,7 @@
#include "IDBFactory.h"
#include "BackgroundChildImpl.h"
#include "IDBRequest.h"
#include "IndexedDatabaseManager.h"
#include "mozilla/ErrorResult.h"
@ -21,7 +22,9 @@
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsILoadContext.h"
#include "nsIPrincipal.h"
#include "nsIUUIDGenerator.h"
#include "nsIWebNavigation.h"
#include "nsServiceManagerUtils.h"
#include "ProfilerHelpers.h"
#include "ReportInternalError.h"
@ -76,10 +79,14 @@ class IDBFactory::BackgroundCreateCallback MOZ_FINAL
: public nsIIPCBackgroundChildCreateCallback
{
nsRefPtr<IDBFactory> mFactory;
LoggingInfo mLoggingInfo;
public:
explicit BackgroundCreateCallback(IDBFactory* aFactory)
: mFactory(aFactory)
explicit
BackgroundCreateCallback(IDBFactory* aFactory,
const LoggingInfo& aLoggingInfo)
: mFactory(aFactory)
, mLoggingInfo(aLoggingInfo)
{
MOZ_ASSERT(aFactory);
}
@ -306,6 +313,15 @@ IDBFactory::SetBackgroundActor(BackgroundFactoryChild* aBackgroundActor)
mBackgroundActor = aBackgroundActor;
}
void
IDBFactory::IncrementParentLoggingRequestSerialNumber()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mBackgroundActor);
mBackgroundActor->SendIncrementLoggingRequestSerialNumber();
}
already_AddRefed<IDBOpenDBRequest>
IDBFactory::Open(const nsAString& aName,
uint64_t aVersion,
@ -501,27 +517,44 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
params = OpenDatabaseRequestParams(commonParams);
}
if (!mBackgroundActor) {
// If another consumer has already created a background actor for this
// thread then we can start this request immediately.
if (PBackgroundChild* bgActor = BackgroundChild::GetForCurrentThread()) {
nsresult rv = BackgroundActorCreated(bgActor);
if (NS_WARN_IF(NS_FAILED(rv))) {
IDB_REPORT_INTERNAL_ERR();
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
}
MOZ_ASSERT(mBackgroundActor);
} else if (mPendingRequests.IsEmpty()) {
// We need to start the sequence to create a background actor for this
// thread.
nsRefPtr<BackgroundCreateCallback> cb =
new BackgroundCreateCallback(this);
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(cb))) {
IDB_REPORT_INTERNAL_ERR();
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
return nullptr;
if (!mBackgroundActor && mPendingRequests.IsEmpty()) {
// We need to start the sequence to create a background actor for this
// thread.
BackgroundChildImpl::ThreadLocal* threadLocal =
BackgroundChildImpl::GetThreadLocalForCurrentThread();
nsAutoPtr<ThreadLocal> newIDBThreadLocal;
ThreadLocal* idbThreadLocal;
if (threadLocal && threadLocal->mIndexedDBThreadLocal) {
idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
} else {
nsCOMPtr<nsIUUIDGenerator> uuidGen =
do_GetService("@mozilla.org/uuid-generator;1");
MOZ_ASSERT(uuidGen);
nsID id;
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(uuidGen->GenerateUUIDInPlace(&id)));
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);
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 (mBackgroundActor) {
nsresult rv = InitiateRequest(request, params);
@ -562,27 +612,12 @@ IDBFactory::OpenInternal(nsIPrincipal* aPrincipal,
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();
}
nsresult
IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor)
IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor,
const LoggingInfo& aLoggingInfo)
{
MOZ_ASSERT(aBackgroundActor);
MOZ_ASSERT(!mBackgroundActor);
@ -595,7 +630,8 @@ IDBFactory::BackgroundActorCreated(PBackgroundChild* aBackgroundActor)
mBackgroundActor =
static_cast<BackgroundFactoryChild*>(
aBackgroundActor->SendPBackgroundIDBFactoryConstructor(actor));
aBackgroundActor->SendPBackgroundIDBFactoryConstructor(actor,
aLoggingInfo));
}
if (NS_WARN_IF(!mBackgroundActor)) {
@ -735,7 +771,7 @@ IDBFactory::BackgroundCreateCallback::ActorCreated(PBackgroundChild* aActor)
nsRefPtr<IDBFactory> factory;
mFactory.swap(factory);
factory->BackgroundActorCreated(aActor);
factory->BackgroundActorCreated(aActor, mLoggingInfo);
}
void

View File

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

View File

@ -264,33 +264,38 @@ IDBIndex::GetInternal(bool aKeyOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}
@ -340,36 +345,40 @@ IDBIndex::GetAllInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}
@ -432,6 +441,37 @@ IDBIndex::OpenCursorInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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 =
new BackgroundCursorChild(request, this, direction);
@ -474,21 +514,23 @@ IDBIndex::Count(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}

View File

@ -1143,10 +1143,12 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
JS::Handle<JS::Value> aValue,
JS::Handle<JS::Value> aKey,
bool aOverwrite,
bool aFromCursor,
ErrorResult& aRv)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aCx);
MOZ_ASSERT_IF(aFromCursor, aOverwrite);
if (!mTransaction->IsOpen()) {
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
@ -1249,6 +1251,32 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
mTransaction->StartRequest(actor, params);
@ -1261,28 +1289,6 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
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();
}
@ -1329,36 +1335,38 @@ IDBObjectStore::GetAllInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}
@ -1383,18 +1391,20 @@ IDBObjectStore::Clear(ErrorResult& aRv)
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}
@ -1579,25 +1589,29 @@ IDBObjectStore::Get(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}
already_AddRefed<IDBRequest>
IDBObjectStore::Delete(JSContext* aCx,
JS::Handle<JS::Value> aKey,
ErrorResult& aRv)
IDBObjectStore::DeleteInternal(JSContext* aCx,
JS::Handle<JS::Value> aKey,
bool aFromCursor,
ErrorResult& aRv)
{
AssertIsOnOwningThread();
@ -1630,18 +1644,23 @@ IDBObjectStore::Delete(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}
@ -1748,13 +1767,20 @@ IDBObjectStore::CreateIndexInternal(
mIndexes.AppendElement(index);
IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
"database(%s).transaction(%s).objectStore(%s)."
"createIndex(%s)",
"MT IDBObjectStore.createIndex()",
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(index));
// 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]: "
"database(%s).transaction(%s).objectStore(%s).createIndex(%s)",
"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();
}
@ -1813,16 +1839,23 @@ IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv)
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: "
"database(%s).transaction(%s).objectStore(%s)."
"deleteIndex(\"%s\")",
"MT IDBObjectStore.deleteIndex()",
IDB_PROFILER_STRING(Transaction()->Database()),
IDB_PROFILER_STRING(Transaction()),
IDB_PROFILER_STRING(this),
NS_ConvertUTF16toUTF8(aName).get());
IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
"database(%s).transaction(%s).objectStore(%s)."
"deleteIndex(\"%s\")",
"IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.deleteIndex()",
IDB_LOG_ID_STRING(),
mTransaction->LoggingSerialNumber(),
requestSerialNumber,
IDB_LOG_STRINGIFY(mTransaction->Database()),
IDB_LOG_STRINGIFY(mTransaction),
IDB_LOG_STRINGIFY(this),
NS_ConvertUTF16toUTF8(aName).get());
transaction->DeleteIndex(this, foundId);
}
already_AddRefed<IDBRequest>
@ -1855,18 +1888,21 @@ IDBObjectStore::Count(JSContext* aCx,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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);
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();
}
@ -1925,34 +1961,40 @@ IDBObjectStore::OpenCursorInternal(bool aKeysOnly,
nsRefPtr<IDBRequest> request = GenerateRequest(this);
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 =
new BackgroundCursorChild(request, this, direction);
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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -32,11 +32,13 @@
#include "mozilla/storage.h"
#include "nsContentUtils.h"
#include "nsThreadUtils.h"
#include "prlog.h"
#include "IDBEvents.h"
#include "IDBFactory.h"
#include "IDBKeyRange.h"
#include "IDBRequest.h"
#include "ProfilerHelpers.h"
// Bindings for ResolveConstructors
#include "mozilla/dom/IDBCursorBinding.h"
@ -111,7 +113,22 @@ private:
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;
@ -205,6 +222,13 @@ IndexedDatabaseManager::~IndexedDatabaseManager()
bool IndexedDatabaseManager::sIsMainProcess = false;
bool IndexedDatabaseManager::sFullSynchronousMode = false;
PRLogModuleInfo* IndexedDatabaseManager::sLoggingModule;
Atomic<IndexedDatabaseManager::LoggingMode>
IndexedDatabaseManager::sLoggingMode(
IndexedDatabaseManager::Logging_Disabled);
mozilla::Atomic<bool> IndexedDatabaseManager::sLowDiskSpaceMode(false);
// static
@ -221,6 +245,10 @@ IndexedDatabaseManager::GetOrCreate()
if (!gDBManager) {
sIsMainProcess = XRE_GetProcessType() == GeckoProcessType_Default;
if (!sLoggingModule) {
sLoggingModule = PR_NewLogModule("IndexedDB");
}
if (sIsMainProcess && Preferences::GetBool("disk_space_watcher.enabled", false)) {
// See if we're starting up in low disk space conditions.
nsCOMPtr<nsIDiskSpaceWatcher> watcher =
@ -300,6 +328,15 @@ IndexedDatabaseManager::Init()
// hit.
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;
}
@ -314,6 +351,15 @@ IndexedDatabaseManager::Destroy()
Preferences::UnregisterCallback(TestingPrefChangedCallback, kTestingPref);
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingDetails);
#ifdef MOZ_ENABLE_PROFILER_SPS
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingProfiler);
#endif
Preferences::UnregisterCallback(LoggingModePrefChangedCallback,
kPrefLoggingEnabled);
delete this;
}
@ -491,7 +537,30 @@ IndexedDatabaseManager::InLowDiskSpaceMode()
"initialized!");
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
bool
@ -687,6 +756,44 @@ IndexedDatabaseManager::BlockAndGetFileReferences(
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_RELEASE_WITH_DESTROY(IndexedDatabaseManager, Destroy())
NS_IMPL_QUERY_INTERFACE(IndexedDatabaseManager, nsIObserver)

View File

@ -17,6 +17,7 @@
#include "nsHashKeys.h"
class nsPIDOMWindow;
struct PRLogModuleInfo;
namespace mozilla {
@ -36,6 +37,15 @@ class IndexedDatabaseManager MOZ_FINAL : public nsIObserver
typedef mozilla::dom::quota::PersistenceType PersistenceType;
public:
enum LoggingMode
{
Logging_Disabled = 0,
Logging_Concise,
Logging_Detailed,
Logging_ConciseProfilerMarks,
Logging_DetailedProfilerMarks
};
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
@ -76,6 +86,26 @@ public:
static bool
FullSynchronous();
static LoggingMode
GetLoggingMode()
#ifdef DEBUG
;
#else
{
return sLoggingMode;
}
#endif
static PRLogModuleInfo*
GetLoggingModule()
#ifdef DEBUG
;
#else
{
return sLoggingModule;
}
#endif
already_AddRefed<FileManager>
GetFileManager(PersistenceType aPersistenceType,
const nsACString& aOrigin,
@ -143,6 +173,9 @@ private:
void
Destroy();
static void
LoggingModePrefChangedCallback(const char* aPrefName, void* aClosure);
// 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.
nsClassHashtable<nsCStringHashKey, FileManagerInfo> mFileManagerInfos;
@ -154,6 +187,8 @@ private:
static bool sIsMainProcess;
static bool sFullSynchronousMode;
static PRLogModuleInfo* sLoggingModule;
static Atomic<LoggingMode> sLoggingMode;
static mozilla::Atomic<bool> sLowDiskSpaceMode;
};

View File

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

View File

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

View File

@ -7,40 +7,76 @@
#ifndef 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"
// 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 "IDBDatabase.h"
#include "IDBIndex.h"
#include "IDBKeyRange.h"
#include "IDBObjectStore.h"
#include "IDBTransaction.h"
#include "IndexedDatabaseManager.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 dom {
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 kOpenBracket = '[';
@ -50,20 +86,38 @@ class ProfilerString : public nsAutoCString
public:
explicit
ProfilerString(IDBDatabase* aDatabase)
LoggingString(IDBDatabase* aDatabase)
: nsAutoCString(kQuote)
{
MOZ_ASSERT(aDatabase);
Append(kQuote);
AppendUTF16toUTF8(aDatabase->Name(), *this);
Append(kQuote);
}
explicit
ProfilerString(IDBTransaction* aTransaction)
LoggingString(IDBTransaction* aTransaction)
: nsAutoCString(kOpenBracket)
{
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()) {
case IDBTransaction::READ_ONLY:
AppendLiteral("\"readonly\"");
@ -80,128 +134,198 @@ public:
}
explicit
ProfilerString(IDBObjectStore* aObjectStore)
LoggingString(IDBObjectStore* aObjectStore)
: nsAutoCString(kQuote)
{
MOZ_ASSERT(aObjectStore);
Append(kQuote);
AppendUTF16toUTF8(aObjectStore->Name(), *this);
Append(kQuote);
}
explicit
ProfilerString(IDBIndex* aIndex)
LoggingString(IDBIndex* aIndex)
: nsAutoCString(kQuote)
{
MOZ_ASSERT(aIndex);
Append(kQuote);
AppendUTF16toUTF8(aIndex->Name(), *this);
Append(kQuote);
}
explicit
ProfilerString(IDBKeyRange* aKeyRange)
LoggingString(IDBKeyRange* aKeyRange)
{
if (aKeyRange) {
if (aKeyRange->IsOnly()) {
Append(ProfilerString(aKeyRange->Lower()));
}
else {
Append(aKeyRange->IsLowerOpen() ? kOpenParen : kOpenBracket);
Append(ProfilerString(aKeyRange->Lower()));
Assign(LoggingString(aKeyRange->Lower()));
} else {
Assign(aKeyRange->LowerOpen() ? kOpenParen : kOpenBracket);
Append(LoggingString(aKeyRange->Lower()));
AppendLiteral(", ");
Append(ProfilerString(aKeyRange->Upper()));
Append(aKeyRange->IsUpperOpen() ? kCloseParen : kCloseBracket);
Append(LoggingString(aKeyRange->Upper()));
Append(aKeyRange->UpperOpen() ? kCloseParen : kCloseBracket);
}
} else {
AssignLiteral("<undefined>");
}
}
explicit
ProfilerString(const Key& aKey)
LoggingString(const Key& aKey)
{
if (aKey.IsUnset()) {
AssignLiteral("null");
}
else if (aKey.IsFloat()) {
AssignLiteral("<undefined>");
} else if (aKey.IsFloat()) {
AppendPrintf("%g", aKey.ToFloat());
}
else if (aKey.IsDate()) {
} else if (aKey.IsDate()) {
AppendPrintf("<Date %g>", aKey.ToDateMsec());
}
else if (aKey.IsString()) {
} else if (aKey.IsString()) {
nsAutoString str;
aKey.ToString(str);
AppendPrintf("\"%s\"", NS_ConvertUTF16toUTF8(str).get());
}
else {
} else {
MOZ_ASSERT(aKey.IsArray());
AppendLiteral("<Array>");
AssignLiteral("[...]");
}
}
explicit
ProfilerString(const IDBCursor::Direction aDirection)
LoggingString(const IDBCursor::Direction aDirection)
{
switch (aDirection) {
case IDBCursor::NEXT:
AppendLiteral("\"next\"");
AssignLiteral("\"next\"");
break;
case IDBCursor::NEXT_UNIQUE:
AppendLiteral("\"nextunique\"");
AssignLiteral("\"nextunique\"");
break;
case IDBCursor::PREV:
AppendLiteral("\"prev\"");
AssignLiteral("\"prev\"");
break;
case IDBCursor::PREV_UNIQUE:
AppendLiteral("\"prevunique\"");
AssignLiteral("\"prevunique\"");
break;
default:
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 dom
} // namespace mozilla
#define IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, ...) \
#define IDB_LOG_MARK(_detailedFmt, _conciseFmt, ...) \
do { \
nsAutoCString _mark; \
_mark.AppendPrintf(_detailedFmt, ##__VA_ARGS__); \
PROFILER_MARKER(_mark.get()); \
} while (0)
#define IDB_PROFILER_STRING(_arg) \
mozilla::dom::indexedDB::ProfilerString((_arg)).get()
#else // IDB_PROFILER_MARK_DETAILS
#define IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, ...) \
do { \
nsAutoCString _mark; \
_mark.AppendPrintf(_conciseFmt, ##__VA_ARGS__); \
PROFILER_MARKER(_mark.get()); \
} while (0)
#define IDB_PROFILER_STRING(_arg) ""
#endif // IDB_PROFILER_MARK_DETAILS
#define IDB_PROFILER_MARK_IF(_cond, _detailedFmt, _conciseFmt, ...) \
do { \
if (_cond) { \
IDB_PROFILER_MARK(_detailedFmt, _conciseFmt, __VA_ARGS__); \
using namespace mozilla::dom::indexedDB; \
\
const IndexedDatabaseManager::LoggingMode mode = \
IndexedDatabaseManager::GetLoggingMode(); \
\
if (mode != IndexedDatabaseManager::Logging_Disabled) { \
const char* _fmt; \
if (mode == IndexedDatabaseManager::Logging_Concise || \
mode == IndexedDatabaseManager::Logging_ConciseProfilerMarks) { \
_fmt = _conciseFmt; \
} else { \
MOZ_ASSERT( \
mode == IndexedDatabaseManager::Logging_Detailed || \
mode == IndexedDatabaseManager::Logging_DetailedProfilerMarks); \
_fmt = _detailedFmt; \
} \
\
const bool _useProfiler = \
mode == IndexedDatabaseManager::Logging_ConciseProfilerMarks || \
mode == IndexedDatabaseManager::Logging_DetailedProfilerMarks; \
\
LoggingHelper(_useProfiler, _fmt, ##__VA_ARGS__); \
} \
} 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_PROFILER_MARK_IF(_cond, ...) do { } while(0)
#define IDB_PROFILER_MARK2(_detailedFmt, _notdetailedFmt, ...) do { } while(0)
#define IDB_PROFILER_STRING(_arg) ""
#endif // IDB_PROFILER_USE_MARKS
#define IDB_LOG_STRINGIFY(...) \
mozilla::dom::indexedDB::LoggingString(__VA_ARGS__).get()
#endif // mozilla_dom_indexeddb_profilerhelpers_h__

View File

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

View File

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

View File

@ -268,7 +268,7 @@ MediaSourceReader::OnVideoNotDecoded(NotDecodedReason aReason)
// switching to the end of the buffered range.
MOZ_ASSERT(aReason == END_OF_STREAM);
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

View File

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

View File

@ -127,7 +127,12 @@ InputQueue::ReceiveScrollWheelInput(const nsRefPtr<AsyncPanZoomController>& aTar
uint64_t* aOutInputBlockId) {
WheelBlockState* block = nullptr;
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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -32,12 +32,24 @@
namespace mozilla {
// IdealSegmentSize is how big each segment will be in bytes (or as close as is
// possible). It's best to choose a size that's a power-of-two (to avoid slop)
// 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
// segment is not full). Something like 4096 or 8192 is probably good.
template<typename T, size_t IdealSegmentSize,
// |IdealSegmentSize| specifies how big each segment will be in bytes (or as
// close as is possible). Use the following guidelines to choose a size.
//
// - It should be a power-of-two, to avoid slop.
//
// - 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>
class SegmentedVector : private AllocPolicy
{

View File

@ -147,7 +147,7 @@ void TestSegmentCapacitiesAndAlignments()
SegmentedVector<B, 999> v3(999);
SegmentedVector<C, 10> v4(10);
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);
}

View File

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

View File

@ -163,7 +163,7 @@ public class SendTabDeviceListArrayAdapter extends ArrayAdapter<ParcelableClient
showDummyRecord(getContext().getResources().getString(R.string.overlay_share_send_other));
break;
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.
* TODO: turn into regular singleton if Context dependency can be removed. */
public static void createGlobalInstance(Context c) {
if (sInstance != null) {
return;
public static Prefs getInstance(Context c) {
if (sInstance == null) {
sInstance = new Prefs(c);
}
sInstance = new Prefs(c);
return sInstance;
}
/* Only access after CreatePrefsInstance(Context) has been called at startup. */
public static Prefs getInstance() {
assert(sInstance != null);
// Allows code without a context handle to grab the prefs. The caller must null check the return value.
public static Prefs getInstanceWithoutContext() {
return sInstance;
}

View File

@ -4,6 +4,7 @@
package org.mozilla.mozstumbler.service.stumblerthread;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
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.datahandling.DataStorageManager;
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.utils.NetworkUtils;
import org.mozilla.mozstumbler.service.utils.PersistentIntentService;
@ -68,8 +68,8 @@ public class StumblerService extends PersistentIntentService
mScanManager.setWifiBlockList(list);
}
public Prefs getPrefs() {
return Prefs.getInstance();
public Prefs getPrefs(Context c) {
return Prefs.getInstance(c);
}
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.
// Safe to call more than once, ensure added code complies with that intent.
protected void init() {
Prefs.createGlobalInstance(this);
// Ensure Prefs is created, so internal utility code can use getInstanceWithoutContext
Prefs.getInstance(this);
NetworkUtils.createGlobalInstance(this);
DataStorageManager.createGlobalInstance(this, this);
@ -150,7 +151,7 @@ public class StumblerService extends PersistentIntentService
}
if (!sFirefoxStumblingEnabled.get()) {
Prefs.getInstance().setFirefoxScanEnabled(false);
Prefs.getInstance(StumblerService.this).setFirefoxScanEnabled(false);
}
if (DataStorageManager.getInstance() != null) {
@ -182,7 +183,7 @@ public class StumblerService extends PersistentIntentService
return;
}
final boolean isScanEnabledInPrefs = Prefs.getInstance().getFirefoxScanEnabled();
final boolean isScanEnabledInPrefs = Prefs.getInstance(this).getFirefoxScanEnabled();
if (!isScanEnabledInPrefs && intent.getBooleanExtra(ACTION_NOT_FROM_HOST_APP, false)) {
stopSelf();
@ -198,7 +199,7 @@ public class StumblerService extends PersistentIntentService
// 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
// 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();
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.");
}
} 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*/);
}
}
if (!isScanEnabledInPrefs) {
Prefs.getInstance().setFirefoxScanEnabled(true);
Prefs.getInstance(this).setFirefoxScanEnabled(true);
}
String apiKey = intent.getStringExtra(ACTION_EXTRA_MOZ_API_KEY);
if (apiKey != null && !apiKey.equals(Prefs.getInstance().getMozApiKey())) {
Prefs.getInstance().setMozApiKey(apiKey);
if (apiKey != null && !apiKey.equals(Prefs.getInstance(this).getMozApiKey())) {
Prefs.getInstance(this).setMozApiKey(apiKey);
}
String userAgent = intent.getStringExtra(ACTION_EXTRA_USER_AGENT);
if (userAgent != null && !userAgent.equals(Prefs.getInstance().getUserAgent())) {
Prefs.getInstance().setUserAgent(userAgent);
if (userAgent != null && !userAgent.equals(Prefs.getInstance(this).getUserAgent())) {
Prefs.getInstance(this).setUserAgent(userAgent);
}
if (!mScanManager.isScanning()) {

View File

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

View File

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

View File

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

View File

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

View File

@ -48,7 +48,8 @@ public class UploadAlarmReceiver extends BroadcastReceiver {
@Override
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) {
DataStorageManager.createGlobalInstance(this, null);
}
@ -77,9 +78,9 @@ public class UploadAlarmReceiver extends BroadcastReceiver {
!AsyncUploader.isUploading()) {
Log.d(LOG_TAG, "Alarm upload(), call AsyncUploader");
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);
uploader.setNickname(Prefs.getInstance().getNickname());
uploader.setNickname(Prefs.getInstance(this).getNickname());
uploader.execute();
// 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;
}
public AbstractCommunicator(String userAgent) {
mUserAgent = userAgent;
public AbstractCommunicator() {
Prefs prefs = Prefs.getInstanceWithoutContext();
mUserAgent = (prefs != null)? prefs.getUserAgent() : "fennec-stumbler-unset-user-agent";
}
private void openConnectionAndSetHeaders() {
try {
if (sMozApiKey == null) {
sMozApiKey = Prefs.getInstance().getMozApiKey();
Prefs prefs = Prefs.getInstanceWithoutContext();
if (sMozApiKey == null || prefs != null) {
sMozApiKey = prefs.getMozApiKey();
}
URL url = new URL(getUrlString() + "?key=" + sMozApiKey);
mHttpURLConnection = (HttpURLConnection) url.openConnection();

View File

@ -119,6 +119,12 @@ pref("dom.indexedDB.enabled", true);
pref("dom.indexedDB.warningQuota", 50);
// Whether or not indexedDB experimental features are enabled.
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.
pref("dom.workers.enabled", true);

View File

@ -200,13 +200,17 @@ NS_NewFileURI(nsIURI* *result,
inline nsresult
NS_NewChannelInternal(nsIChannel** outChannel,
nsIURI* aUri,
nsILoadInfo* aLoadInfo,
nsINode* aRequestingNode,
nsIPrincipal* aRequestingPrincipal,
nsIPrincipal* aTriggeringPrincipal,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsIURI* aBaseURI = nullptr,
nsILoadGroup* aLoadGroup = nullptr,
nsIInterfaceRequestor* aCallbacks = nullptr,
nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL,
nsIIOService* aIoService = nullptr)
{
NS_ASSERTION(aLoadInfo, "Can not create channel without aLoadInfo!");
NS_ENSURE_ARG_POINTER(outChannel);
nsCOMPtr<nsIIOService> grip;
@ -234,11 +238,31 @@ NS_NewChannelInternal(nsIChannel** outChannel,
rv = channel->SetLoadFlags(aLoadFlags | (normalLoadFlags & nsIChannel::LOAD_REPLACE));
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
// might already have.
if (aLoadInfo->GetLoadingSandboxed()) {
if (loadInfo->GetLoadingSandboxed()) {
channel->SetOwner(nullptr);
}
@ -249,31 +273,27 @@ NS_NewChannelInternal(nsIChannel** outChannel,
inline nsresult
NS_NewChannelInternal(nsIChannel** outChannel,
nsIURI* aUri,
nsINode* aRequestingNode,
nsIPrincipal* aRequestingPrincipal,
nsIPrincipal* aTriggeringPrincipal,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsILoadInfo* aLoadInfo,
nsILoadGroup* aLoadGroup = nullptr,
nsIInterfaceRequestor* aCallbacks = nullptr,
nsLoadFlags aLoadFlags = nsIRequest::LOAD_NORMAL,
nsIIOService* aIoService = nullptr)
{
NS_ASSERTION(aRequestingPrincipal, "Can not create channel without a requesting Principal!");
nsCOMPtr<nsILoadInfo> loadInfo =
new mozilla::LoadInfo(aRequestingPrincipal, aTriggeringPrincipal,
aRequestingNode, aSecurityFlags, aContentPolicyType);
if (!loadInfo) {
return NS_ERROR_UNEXPECTED;
}
return NS_NewChannelInternal(outChannel,
aUri,
loadInfo,
aLoadGroup,
aCallbacks,
aLoadFlags,
aIoService);
MOZ_ASSERT(aLoadInfo, "Can not create a channel without a loadInfo");
nsresult rv = NS_NewChannelInternal(outChannel,
aUri,
aLoadInfo->LoadingNode(),
aLoadInfo->LoadingPrincipal(),
aLoadInfo->TriggeringPrincipal(),
aLoadInfo->GetSecurityFlags(),
aLoadInfo->GetContentPolicyType(),
aLoadInfo->BaseURI(),
aLoadGroup,
aCallbacks,
aLoadFlags,
aIoService);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
inline nsresult /*NS_NewChannelWithNodeAndTriggeringPrincipal */
@ -297,6 +317,7 @@ NS_NewChannelWithTriggeringPrincipal(nsIChannel** outChannel,
aTriggeringPrincipal,
aSecurityFlags,
aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup,
aCallbacks,
aLoadFlags,
@ -323,6 +344,7 @@ NS_NewChannelWithTriggeringPrincipal(nsIChannel** outChannel,
aTriggeringPrincipal,
aSecurityFlags,
aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup,
aCallbacks,
aLoadFlags,
@ -348,6 +370,7 @@ NS_NewChannel(nsIChannel** outChannel,
nullptr, // aTriggeringPrincipal
aSecurityFlags,
aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup,
aCallbacks,
aLoadFlags,
@ -372,6 +395,7 @@ NS_NewChannel(nsIChannel** outChannel,
nullptr, // aTriggeringPrincipal
aSecurityFlags,
aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup,
aCallbacks,
aLoadFlags,
@ -406,6 +430,7 @@ NS_OpenURIInternal(nsIInputStream** outStream,
aTriggeringPrincipal,
aSecurityFlags,
aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup,
aCallbacks,
aLoadFlags,
@ -962,6 +987,7 @@ NS_NewStreamLoaderInternal(nsIStreamLoader** outStream,
nullptr, // aTriggeringPrincipal
aSecurityFlags,
aContentPolicyType,
nullptr, // aBaseURI
aLoadGroup,
aCallbacks,
aLoadFlags);

View File

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

View File

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