mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to m-c.
This commit is contained in:
commit
31d6244ff0
@ -161,8 +161,7 @@ CustomizeMode.prototype = {
|
||||
let toolbarVisibilityBtn = document.getElementById(kToolbarVisibilityBtn);
|
||||
let togglableToolbars = window.getTogglableToolbars();
|
||||
let bookmarksToolbar = document.getElementById("PersonalToolbar");
|
||||
if (togglableToolbars.length == 0 ||
|
||||
(togglableToolbars.length == 1 && togglableToolbars[0] == bookmarksToolbar)) {
|
||||
if (togglableToolbars.length == 0) {
|
||||
toolbarVisibilityBtn.setAttribute("hidden", "true");
|
||||
} else {
|
||||
toolbarVisibilityBtn.removeAttribute("hidden");
|
||||
|
@ -97,3 +97,19 @@ function*() {
|
||||
is(elt.textContent, res2[i].value, res2[i].selector + " has the right value after style update.");
|
||||
}
|
||||
});
|
||||
|
||||
addTest("Test that long labels on left/right are rotated 90 degrees",
|
||||
function*() {
|
||||
let viewdoc = view.document;
|
||||
const LONG_TEXT_ROTATE_LIMIT = 3;
|
||||
|
||||
for (let i = 0; i < res1.length; i++) {
|
||||
let elt = viewdoc.querySelector(res1[i].selector);
|
||||
let isLong = elt.textContent.length > LONG_TEXT_ROTATE_LIMIT;
|
||||
let classList = elt.parentNode.classList
|
||||
let canBeRotated = classList.contains("left") || classList.contains("right");
|
||||
let isRotated = classList.contains("rotate");
|
||||
|
||||
is(canBeRotated && isLong, isRotated, res1[i].selector + " correctly rotated.");
|
||||
}
|
||||
});
|
||||
|
@ -174,6 +174,14 @@ body {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.rotate.left:not(.editing) {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.rotate.right:not(.editing) {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
@ -20,6 +20,7 @@ const {InplaceEditor, editableItem} = devtools.require("devtools/shared/inplace-
|
||||
const {parseDeclarations} = devtools.require("devtools/styleinspector/css-parsing-utils");
|
||||
|
||||
const NUMERIC = /^-?[\d\.]+$/;
|
||||
const LONG_TEXT_ROTATE_LIMIT = 3;
|
||||
|
||||
/**
|
||||
* An instance of EditingSession tracks changes that have been made during the
|
||||
@ -223,10 +224,14 @@ LayoutView.prototype = {
|
||||
let session = new EditingSession(document, this.elementRules);
|
||||
let initialValue = session.getProperty(realProperty);
|
||||
|
||||
new InplaceEditor({
|
||||
let editor = new InplaceEditor({
|
||||
element: element,
|
||||
initial: initialValue,
|
||||
|
||||
start: (editor) => {
|
||||
editor.elt.parentNode.classList.add("editing");
|
||||
},
|
||||
|
||||
change: (value) => {
|
||||
if (NUMERIC.test(value))
|
||||
value += "px";
|
||||
@ -245,6 +250,7 @@ LayoutView.prototype = {
|
||||
},
|
||||
|
||||
done: (value, commit) => {
|
||||
editor.elt.parentNode.classList.remove("editing");
|
||||
if (!commit)
|
||||
session.revert();
|
||||
}
|
||||
@ -387,6 +393,7 @@ LayoutView.prototype = {
|
||||
continue;
|
||||
}
|
||||
span.textContent = this.map[i].value;
|
||||
this.manageOverflowingText(span);
|
||||
}
|
||||
|
||||
width -= this.map.borderLeft.value + this.map.borderRight.value +
|
||||
@ -420,6 +427,15 @@ LayoutView.prototype = {
|
||||
|
||||
toolbox.highlighterUtils.unhighlight();
|
||||
},
|
||||
|
||||
manageOverflowingText: function(span) {
|
||||
let classList = span.parentNode.classList;
|
||||
|
||||
if (classList.contains("left") || classList.contains("right")) {
|
||||
let force = span.textContent.length > LONG_TEXT_ROTATE_LIMIT;
|
||||
classList.toggle("rotate", force);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let elts;
|
||||
|
@ -193,13 +193,13 @@ function createAndLoadTemporaryFile(aFile, aFileName, aFileContent)
|
||||
{
|
||||
// Create a temporary file.
|
||||
aFile = FileUtils.getFile("TmpD", [aFileName]);
|
||||
aFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||
aFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
|
||||
|
||||
// Write the temporary file.
|
||||
let fout = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
fout.init(aFile.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20,
|
||||
0644, fout.DEFER_OPEN);
|
||||
0o644, fout.DEFER_OPEN);
|
||||
|
||||
gScratchpad.setFilename(aFile.path);
|
||||
gScratchpad.importFromFile(aFile.QueryInterface(Ci.nsILocalFile), true,
|
||||
|
@ -45,21 +45,21 @@ function runTests()
|
||||
|
||||
// Create a temporary file.
|
||||
gFileA = FileUtils.getFile("TmpD", ["fileAForBug684546.tmp"]);
|
||||
gFileA.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||
gFileA.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
|
||||
|
||||
gFileB = FileUtils.getFile("TmpD", ["fileBForBug684546.tmp"]);
|
||||
gFileB.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||
gFileB.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
|
||||
|
||||
// Write the temporary file.
|
||||
let foutA = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
foutA.init(gFileA.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20,
|
||||
0644, foutA.DEFER_OPEN);
|
||||
0o644, foutA.DEFER_OPEN);
|
||||
|
||||
let foutB = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
foutB.init(gFileB.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20,
|
||||
0644, foutB.DEFER_OPEN);
|
||||
0o644, foutB.DEFER_OPEN);
|
||||
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
|
@ -98,13 +98,13 @@ function createAndLoadTemporaryFile()
|
||||
{
|
||||
// Create a temporary file.
|
||||
gFile = FileUtils.getFile("TmpD", [gFileName]);
|
||||
gFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
|
||||
gFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666);
|
||||
|
||||
// Write the temporary file.
|
||||
let fout = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
fout.init(gFile.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20,
|
||||
0644, fout.DEFER_OPEN);
|
||||
0o644, fout.DEFER_OPEN);
|
||||
|
||||
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
|
||||
createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
|
@ -1336,6 +1336,8 @@ public final class HomeConfig {
|
||||
|
||||
mConfigOrder.remove(panelId);
|
||||
mConfigOrder.add(destIndex, panelId);
|
||||
mHasChanged = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4494,7 +4494,7 @@ Tab.prototype = {
|
||||
// call above does so at the end of the updateViewportSize function. As long
|
||||
// as that is happening, we don't need to do it again here.
|
||||
|
||||
if (contentDocument.mozSyntheticDocument) {
|
||||
if (!this.restoredSessionZoom() && contentDocument.mozSyntheticDocument) {
|
||||
// for images, scale to fit width. this needs to happen *after* the call
|
||||
// to updateMetadata above, because that call sets the CSS viewport which
|
||||
// will affect the page size (i.e. contentDocument.body.scroll*) that we
|
||||
|
@ -70,7 +70,8 @@ interface nsIPrefBranch : nsISupports
|
||||
* @param aPrefName The boolean preference to set the state of.
|
||||
* @param aValue The boolean value to set the preference to.
|
||||
*
|
||||
* @throws Error if setting failed or the value is the wrong type.
|
||||
* @throws Error if setting failed or the preference has a default
|
||||
value of a type other than boolean.
|
||||
*
|
||||
* @see getBoolPref
|
||||
*/
|
||||
@ -106,7 +107,8 @@ interface nsIPrefBranch : nsISupports
|
||||
* @param aPrefName The string preference to set.
|
||||
* @param aValue The string value to set the preference to.
|
||||
*
|
||||
* @throws Error if setting failed or the value is the wrong type.
|
||||
* @throws Error if setting failed or the preference has a default
|
||||
value of a type other than string.
|
||||
*
|
||||
* @see getCharPref
|
||||
*/
|
||||
@ -129,7 +131,8 @@ interface nsIPrefBranch : nsISupports
|
||||
* @param aPrefName The integer preference to set the value of.
|
||||
* @param aValue The integer value to set the preference to.
|
||||
*
|
||||
* @throws Error if setting failed or the value is the wrong type.
|
||||
* @throws Error if setting failed or the preference has a default
|
||||
value of a type other than integer.
|
||||
*
|
||||
* @see getIntPref
|
||||
*/
|
||||
|
@ -706,19 +706,24 @@ static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType t
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void pref_SetValue(PrefValue* oldValue, PrefValue newValue, PrefType type)
|
||||
/*
|
||||
* Overwrite the type and value of an existing preference. Caller must
|
||||
* ensure that they are not changing the type of a preference that has
|
||||
* a default value.
|
||||
*/
|
||||
static void pref_SetValue(PrefValue* existingValue, uint16_t *existingFlags,
|
||||
PrefValue newValue, PrefType newType)
|
||||
{
|
||||
switch (type & PREF_VALUETYPE_MASK)
|
||||
{
|
||||
case PREF_STRING:
|
||||
PR_ASSERT(newValue.stringVal);
|
||||
if (oldValue->stringVal)
|
||||
PL_strfree(oldValue->stringVal);
|
||||
oldValue->stringVal = newValue.stringVal ? PL_strdup(newValue.stringVal) : nullptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
*oldValue = newValue;
|
||||
if ((*existingFlags & PREF_STRING) && existingValue->stringVal) {
|
||||
PL_strfree(existingValue->stringVal);
|
||||
}
|
||||
*existingFlags = (*existingFlags & ~PREF_VALUETYPE_MASK) | newType;
|
||||
if (newType & PREF_STRING) {
|
||||
PR_ASSERT(newValue.stringVal);
|
||||
existingValue->stringVal = newValue.stringVal ? PL_strdup(newValue.stringVal) : nullptr;
|
||||
}
|
||||
else {
|
||||
*existingValue = newValue;
|
||||
}
|
||||
gDirty = true;
|
||||
}
|
||||
@ -752,7 +757,7 @@ nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t
|
||||
if (!pref)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// new entry, better intialize
|
||||
// new entry, better initialize
|
||||
if (!pref->key) {
|
||||
|
||||
// initialize the pref entry
|
||||
@ -761,10 +766,9 @@ nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t
|
||||
memset(&pref->defaultPref, 0, sizeof(pref->defaultPref));
|
||||
memset(&pref->userPref, 0, sizeof(pref->userPref));
|
||||
}
|
||||
else if ((((PrefType)(pref->flags)) & PREF_VALUETYPE_MASK) !=
|
||||
(type & PREF_VALUETYPE_MASK))
|
||||
else if ((pref->flags & PREF_HAS_DEFAULT) && PREF_TYPE(pref) != type)
|
||||
{
|
||||
NS_WARNING(nsPrintfCString("Trying to set pref %s to with the wrong type!", key).get());
|
||||
NS_WARNING(nsPrintfCString("Trying to overwrite value of default pref %s with the wrong type!", key).get());
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
@ -776,7 +780,7 @@ nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t
|
||||
if (pref_ValueChanged(pref->defaultPref, value, type) ||
|
||||
!(pref->flags & PREF_HAS_DEFAULT))
|
||||
{
|
||||
pref_SetValue(&pref->defaultPref, value, type);
|
||||
pref_SetValue(&pref->defaultPref, &pref->flags, value, type);
|
||||
pref->flags |= PREF_HAS_DEFAULT;
|
||||
if (!PREF_HAS_USER_VALUE(pref))
|
||||
valueChanged = true;
|
||||
@ -787,21 +791,23 @@ nsresult pref_HashPref(const char *key, PrefValue value, PrefType type, uint32_t
|
||||
{
|
||||
/* If new value is same as the default value, then un-set the user value.
|
||||
Otherwise, set the user value only if it has changed */
|
||||
if (!pref_ValueChanged(pref->defaultPref, value, type) &&
|
||||
(pref->flags & PREF_HAS_DEFAULT) &&
|
||||
if ((pref->flags & PREF_HAS_DEFAULT) &&
|
||||
!pref_ValueChanged(pref->defaultPref, value, type) &&
|
||||
!(flags & kPrefForceSet))
|
||||
{
|
||||
if (PREF_HAS_USER_VALUE(pref))
|
||||
{
|
||||
/* XXX should we free a user-set string value if there is one? */
|
||||
pref->flags &= ~PREF_USERSET;
|
||||
if (!PREF_IS_LOCKED(pref))
|
||||
valueChanged = true;
|
||||
}
|
||||
}
|
||||
else if ( !PREF_HAS_USER_VALUE(pref) ||
|
||||
pref_ValueChanged(pref->userPref, value, type) )
|
||||
else if (!PREF_HAS_USER_VALUE(pref) ||
|
||||
PREF_TYPE(pref) != type ||
|
||||
pref_ValueChanged(pref->userPref, value, type) )
|
||||
{
|
||||
pref_SetValue(&pref->userPref, value, type);
|
||||
pref_SetValue(&pref->userPref, &pref->flags, value, type);
|
||||
pref->flags |= PREF_USERSET;
|
||||
if (!PREF_IS_LOCKED(pref))
|
||||
valueChanged = true;
|
||||
|
63
modules/libpref/test/unit/test_changeType.js
Normal file
63
modules/libpref/test/unit/test_changeType.js
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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/. */
|
||||
|
||||
/* Tests for changing the type of a preference (bug 985998) */
|
||||
|
||||
const PREF_INVALID = 0;
|
||||
const PREF_BOOL = 128;
|
||||
const PREF_INT = 64;
|
||||
const PREF_STRING = 32;
|
||||
|
||||
function run_test() {
|
||||
|
||||
var ps = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService);
|
||||
|
||||
let defaultBranch = ps.getDefaultBranch("");
|
||||
let userBranch = ps.getBranch("");
|
||||
|
||||
//**************************************************************************//
|
||||
// Can't change the type of prefs that have default values
|
||||
|
||||
defaultBranch.setBoolPref("TypeTest.existing.bool", true);
|
||||
defaultBranch.setIntPref("TypeTest.existing.int", 23);
|
||||
defaultBranch.setCharPref("TypeTest.existing.char", "hey");
|
||||
|
||||
// The user branch reads back the expected default
|
||||
do_check_eq(userBranch.getBoolPref("TypeTest.existing.bool"), true);
|
||||
do_check_eq(userBranch.getIntPref("TypeTest.existing.int"), 23);
|
||||
do_check_eq(userBranch.getCharPref("TypeTest.existing.char"), "hey");
|
||||
|
||||
// All the combinations of attempted type changes
|
||||
do_check_throws(function() {
|
||||
userBranch.setCharPref("TypeTest.existing.bool", "boo"); }, Cr.NS_ERROR_UNEXPECTED);
|
||||
do_check_throws(function() {
|
||||
userBranch.setIntPref("TypeTest.existing.bool", 5); }, Cr.NS_ERROR_UNEXPECTED);
|
||||
do_check_throws(function() {
|
||||
userBranch.setCharPref("TypeTest.existing.int", "boo"); }, Cr.NS_ERROR_UNEXPECTED);
|
||||
do_check_throws(function() {
|
||||
userBranch.setBoolPref("TypeTest.existing.int", true); }, Cr.NS_ERROR_UNEXPECTED);
|
||||
do_check_throws(function() {
|
||||
userBranch.setBoolPref("TypeTest.existing.char", true); }, Cr.NS_ERROR_UNEXPECTED);
|
||||
do_check_throws(function() {
|
||||
userBranch.setIntPref("TypeTest.existing.char", 6); }, Cr.NS_ERROR_UNEXPECTED);
|
||||
|
||||
|
||||
//**************************************************************************//
|
||||
// Prefs that don't have default values can mutate
|
||||
let pref = "TypeTest.user";
|
||||
userBranch.setBoolPref(pref, true);
|
||||
userBranch.setCharPref(pref, "yay");
|
||||
do_check_eq(userBranch.getCharPref(pref), "yay");
|
||||
userBranch.setIntPref(pref, 7);
|
||||
do_check_eq(userBranch.getIntPref(pref), 7);
|
||||
userBranch.setBoolPref(pref, false);
|
||||
do_check_eq(userBranch.getBoolPref(pref), false);
|
||||
userBranch.setIntPref(pref, 8);
|
||||
do_check_eq(userBranch.getIntPref(pref), 8);
|
||||
userBranch.setCharPref(pref, "whee");
|
||||
do_check_eq(userBranch.getCharPref(pref), "whee");
|
||||
userBranch.setBoolPref(pref, true);
|
||||
do_check_eq(userBranch.getBoolPref(pref), true);
|
||||
}
|
@ -10,5 +10,6 @@ support-files =
|
||||
[test_bug506224.js]
|
||||
[test_bug577950.js]
|
||||
[test_bug790374.js]
|
||||
[test_changeType.js]
|
||||
[test_extprefs.js]
|
||||
[test_libPrefs.js]
|
||||
|
@ -194,8 +194,8 @@ StorageBaseStatementInternal::ExecuteAsync(
|
||||
NS_ENSURE_TRUE(stmts.AppendElement(data), NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Dispatch to the background
|
||||
return AsyncExecuteStatements::execute(stmts, mDBConnection, aCallback,
|
||||
_stmt);
|
||||
return AsyncExecuteStatements::execute(stmts, mDBConnection,
|
||||
mNativeConnection, aCallback, _stmt);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
struct sqlite3;
|
||||
struct sqlite3_stmt;
|
||||
class mozIStorageError;
|
||||
class mozIStorageBindingParamsArray;
|
||||
@ -97,6 +98,7 @@ protected: // mix-in bits are protected
|
||||
StorageBaseStatementInternal();
|
||||
|
||||
nsRefPtr<Connection> mDBConnection;
|
||||
sqlite3 *mNativeConnection;
|
||||
|
||||
/**
|
||||
* Our asynchronous statement.
|
||||
|
@ -131,13 +131,15 @@ AsyncStatement::AsyncStatement()
|
||||
|
||||
nsresult
|
||||
AsyncStatement::initialize(Connection *aDBConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
const nsACString &aSQLStatement)
|
||||
{
|
||||
NS_ASSERTION(aDBConnection, "No database connection given!");
|
||||
NS_ASSERTION(aDBConnection->GetNativeConnection(),
|
||||
"We should never be called with a null sqlite3 database!");
|
||||
MOZ_ASSERT(aDBConnection, "No database connection given!");
|
||||
MOZ_ASSERT(!aDBConnection->isClosed(), "Database connection should be valid");
|
||||
MOZ_ASSERT(aNativeConnection, "No native connection given!");
|
||||
|
||||
mDBConnection = aDBConnection;
|
||||
mNativeConnection = aNativeConnection;
|
||||
mSQLString = aSQLStatement;
|
||||
|
||||
PR_LOG(gStorageLog, PR_LOG_NOTICE, ("Inited async statement '%s' (0x%p)",
|
||||
@ -300,11 +302,12 @@ AsyncStatement::getAsyncStatement(sqlite3_stmt **_stmt)
|
||||
#endif
|
||||
|
||||
if (!mAsyncStatement) {
|
||||
int rc = mDBConnection->prepareStatement(mSQLString, &mAsyncStatement);
|
||||
int rc = mDBConnection->prepareStatement(mNativeConnection, mSQLString,
|
||||
&mAsyncStatement);
|
||||
if (rc != SQLITE_OK) {
|
||||
PR_LOG(gStorageLog, PR_LOG_ERROR,
|
||||
("Sqlite statement prepare error: %d '%s'", rc,
|
||||
::sqlite3_errmsg(mDBConnection->GetNativeConnection())));
|
||||
::sqlite3_errmsg(mNativeConnection)));
|
||||
PR_LOG(gStorageLog, PR_LOG_ERROR,
|
||||
("Statement was: '%s'", mSQLString.get()));
|
||||
*_stmt = nullptr;
|
||||
|
@ -45,10 +45,13 @@ public:
|
||||
*
|
||||
* @param aDBConnection
|
||||
* The Connection object this statement is associated with.
|
||||
* @param aNativeConnection
|
||||
* The native Sqlite connection this statement is associated with.
|
||||
* @param aSQLStatement
|
||||
* The SQL statement to prepare that this object will represent.
|
||||
*/
|
||||
nsresult initialize(Connection *aDBConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
const nsACString &aSQLStatement);
|
||||
|
||||
/**
|
||||
|
@ -163,12 +163,14 @@ private:
|
||||
nsresult
|
||||
AsyncExecuteStatements::execute(StatementDataArray &aStatements,
|
||||
Connection *aConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
mozIStorageStatementCallback *aCallback,
|
||||
mozIStoragePendingStatement **_stmt)
|
||||
{
|
||||
// Create our event to run in the background
|
||||
nsRefPtr<AsyncExecuteStatements> event =
|
||||
new AsyncExecuteStatements(aStatements, aConnection, aCallback);
|
||||
new AsyncExecuteStatements(aStatements, aConnection, aNativeConnection,
|
||||
aCallback);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Dispatch it to the background
|
||||
@ -194,9 +196,11 @@ AsyncExecuteStatements::execute(StatementDataArray &aStatements,
|
||||
|
||||
AsyncExecuteStatements::AsyncExecuteStatements(StatementDataArray &aStatements,
|
||||
Connection *aConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
mozIStorageStatementCallback *aCallback)
|
||||
: mConnection(aConnection)
|
||||
, mTransactionManager(nullptr)
|
||||
, mNativeConnection(aNativeConnection)
|
||||
, mHasTransaction(false)
|
||||
, mCallback(aCallback)
|
||||
, mCallingThread(::do_GetCurrentThread())
|
||||
, mMaxWait(TimeDuration::FromMilliseconds(MAX_MILLISECONDS_BETWEEN_RESULTS))
|
||||
@ -212,6 +216,11 @@ AsyncExecuteStatements::AsyncExecuteStatements(StatementDataArray &aStatements,
|
||||
NS_IF_ADDREF(mCallback);
|
||||
}
|
||||
|
||||
AsyncExecuteStatements::~AsyncExecuteStatements()
|
||||
{
|
||||
MOZ_ASSERT(!mHasTransaction, "There should be no transaction at this point");
|
||||
}
|
||||
|
||||
bool
|
||||
AsyncExecuteStatements::shouldNotify()
|
||||
{
|
||||
@ -333,7 +342,7 @@ AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement)
|
||||
// lock the sqlite mutex so sqlite3_errmsg cannot change
|
||||
SQLiteMutexAutoLock lockedScope(mDBMutex);
|
||||
|
||||
int rc = mConnection->stepStatement(aStatement);
|
||||
int rc = mConnection->stepStatement(mNativeConnection, aStatement);
|
||||
// Stop if we have no more results.
|
||||
if (rc == SQLITE_DONE)
|
||||
{
|
||||
@ -364,8 +373,9 @@ AsyncExecuteStatements::executeStatement(sqlite3_stmt *aStatement)
|
||||
|
||||
// Construct the error message before giving up the mutex (which we cannot
|
||||
// hold during the call to notifyError).
|
||||
sqlite3 *db = mConnection->GetNativeConnection();
|
||||
nsCOMPtr<mozIStorageError> errorObj(new Error(rc, ::sqlite3_errmsg(db)));
|
||||
nsCOMPtr<mozIStorageError> errorObj(
|
||||
new Error(rc, ::sqlite3_errmsg(mNativeConnection))
|
||||
);
|
||||
// We cannot hold the DB mutex while calling notifyError.
|
||||
SQLiteMutexAutoUnlock unlockedScope(mDBMutex);
|
||||
(void)notifyError(errorObj);
|
||||
@ -433,9 +443,9 @@ AsyncExecuteStatements::notifyComplete()
|
||||
mStatements.Clear();
|
||||
|
||||
// Handle our transaction, if we have one
|
||||
if (mTransactionManager) {
|
||||
if (mHasTransaction) {
|
||||
if (mState == COMPLETED) {
|
||||
nsresult rv = mTransactionManager->Commit();
|
||||
nsresult rv = mConnection->commitTransactionInternal(mNativeConnection);
|
||||
if (NS_FAILED(rv)) {
|
||||
mState = ERROR;
|
||||
(void)notifyError(mozIStorageError::ERROR,
|
||||
@ -443,10 +453,9 @@ AsyncExecuteStatements::notifyComplete()
|
||||
}
|
||||
}
|
||||
else {
|
||||
(void)mTransactionManager->Rollback();
|
||||
NS_WARN_IF(NS_FAILED(mConnection->rollbackTransactionInternal(mNativeConnection)));
|
||||
}
|
||||
delete mTransactionManager;
|
||||
mTransactionManager = nullptr;
|
||||
mHasTransaction = false;
|
||||
}
|
||||
|
||||
// Always generate a completion notification; it is what guarantees that our
|
||||
@ -563,6 +572,8 @@ AsyncExecuteStatements::Cancel()
|
||||
NS_IMETHODIMP
|
||||
AsyncExecuteStatements::Run()
|
||||
{
|
||||
MOZ_ASSERT(!mConnection->isClosed());
|
||||
|
||||
// Do not run if we have been canceled.
|
||||
{
|
||||
MutexAutoLock lockedScope(mMutex);
|
||||
@ -574,8 +585,15 @@ AsyncExecuteStatements::Run()
|
||||
|
||||
if (statementsNeedTransaction()) {
|
||||
Connection* rawConnection = static_cast<Connection*>(mConnection.get());
|
||||
mTransactionManager = new mozStorageAsyncTransaction(rawConnection, false,
|
||||
mozIStorageConnection::TRANSACTION_IMMEDIATE);
|
||||
if (NS_SUCCEEDED(mConnection->beginTransactionInternal(mNativeConnection,
|
||||
mozIStorageConnection::TRANSACTION_IMMEDIATE))) {
|
||||
mHasTransaction = true;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
NS_WARNING("Unable to create a transaction for async execution.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Execute each statement, giving the callback results if it returns any.
|
||||
@ -592,9 +610,8 @@ AsyncExecuteStatements::Run()
|
||||
mState = ERROR;
|
||||
|
||||
// Build the error object; can't call notifyError with the lock held
|
||||
sqlite3 *db = mConnection->GetNativeConnection();
|
||||
nsCOMPtr<mozIStorageError> errorObj(
|
||||
new Error(rc, ::sqlite3_errmsg(db))
|
||||
new Error(rc, ::sqlite3_errmsg(mNativeConnection))
|
||||
);
|
||||
{
|
||||
// We cannot hold the DB mutex and call notifyError.
|
||||
|
@ -29,14 +29,6 @@ class Connection;
|
||||
class ResultSet;
|
||||
class StatementData;
|
||||
|
||||
/**
|
||||
* An instance of the mozStorageTransaction<> family dedicated
|
||||
* to concrete class |Connection|.
|
||||
*/
|
||||
typedef mozStorageTransactionBase<mozilla::storage::Connection,
|
||||
nsRefPtr<mozilla::storage::Connection> >
|
||||
mozStorageAsyncTransaction;
|
||||
|
||||
class AsyncExecuteStatements MOZ_FINAL : public nsIRunnable
|
||||
, public mozIStoragePendingStatement
|
||||
{
|
||||
@ -66,6 +58,8 @@ public:
|
||||
* Ownership is transfered from the caller.
|
||||
* @param aConnection
|
||||
* The connection that created the statements to execute.
|
||||
* @param aNativeConnection
|
||||
* The native Sqlite connection that created the statements to execute.
|
||||
* @param aCallback
|
||||
* The callback that is notified of results, completion, and errors.
|
||||
* @param _stmt
|
||||
@ -73,6 +67,7 @@ public:
|
||||
*/
|
||||
static nsresult execute(StatementDataArray &aStatements,
|
||||
Connection *aConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
mozIStorageStatementCallback *aCallback,
|
||||
mozIStoragePendingStatement **_stmt);
|
||||
|
||||
@ -90,7 +85,9 @@ public:
|
||||
private:
|
||||
AsyncExecuteStatements(StatementDataArray &aStatements,
|
||||
Connection *aConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
mozIStorageStatementCallback *aCallback);
|
||||
~AsyncExecuteStatements();
|
||||
|
||||
/**
|
||||
* Binds and then executes a given statement until completion, an error
|
||||
@ -187,7 +184,8 @@ private:
|
||||
|
||||
StatementDataArray mStatements;
|
||||
nsRefPtr<Connection> mConnection;
|
||||
mozStorageAsyncTransaction *mTransactionManager;
|
||||
sqlite3 *mNativeConnection;
|
||||
bool mHasTransaction;
|
||||
mozIStorageStatementCallback *mCallback;
|
||||
nsCOMPtr<nsIThread> mCallingThread;
|
||||
nsRefPtr<ResultSet> mResultSet;
|
||||
|
@ -333,9 +333,11 @@ class AsyncCloseConnection MOZ_FINAL: public nsRunnable
|
||||
{
|
||||
public:
|
||||
AsyncCloseConnection(Connection *aConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
nsIRunnable *aCallbackEvent,
|
||||
already_AddRefed<nsIThread> aAsyncExecutionThread)
|
||||
: mConnection(aConnection)
|
||||
, mNativeConnection(aNativeConnection)
|
||||
, mCallbackEvent(aCallbackEvent)
|
||||
, mAsyncExecutionThread(aAsyncExecutionThread)
|
||||
{
|
||||
@ -351,7 +353,7 @@ public:
|
||||
#endif // DEBUG
|
||||
|
||||
// Internal close.
|
||||
(void)mConnection->internalClose();
|
||||
(void)mConnection->internalClose(mNativeConnection);
|
||||
|
||||
// Callback
|
||||
if (mCallbackEvent) {
|
||||
@ -376,6 +378,7 @@ public:
|
||||
}
|
||||
private:
|
||||
nsRefPtr<Connection> mConnection;
|
||||
sqlite3 *mNativeConnection;
|
||||
nsCOMPtr<nsIRunnable> mCallbackEvent;
|
||||
nsCOMPtr<nsIThread> mAsyncExecutionThread;
|
||||
};
|
||||
@ -470,6 +473,7 @@ Connection::Connection(Service *aService,
|
||||
, threadOpenedOn(do_GetCurrentThread())
|
||||
, mDBConn(nullptr)
|
||||
, mAsyncExecutionThreadShuttingDown(false)
|
||||
, mConnectionClosed(false)
|
||||
, mTransactionInProgress(false)
|
||||
, mProgressHandler(nullptr)
|
||||
, mFlags(aFlags)
|
||||
@ -519,6 +523,18 @@ NS_IMETHODIMP_(MozExternalRefCountType) Connection::Release(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
int32_t
|
||||
Connection::getSqliteRuntimeStatus(int32_t aStatusOption, int32_t* aMaxValue)
|
||||
{
|
||||
MOZ_ASSERT(mDBConn, "A connection must exist at this point");
|
||||
int curr = 0, max = 0;
|
||||
DebugOnly<int> rc = ::sqlite3_db_status(mDBConn, aStatusOption, &curr, &max, 0);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(convertResultCode(rc)));
|
||||
if (aMaxValue)
|
||||
*aMaxValue = max;
|
||||
return curr;
|
||||
}
|
||||
|
||||
nsIEventTarget *
|
||||
Connection::getAsyncExecutionTarget()
|
||||
{
|
||||
@ -654,7 +670,7 @@ Connection::initializeInternal(nsIFile* aDatabaseFile)
|
||||
nsAutoCString cacheSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
||||
"PRAGMA cache_size = ");
|
||||
cacheSizeQuery.AppendInt(-MAX_CACHE_SIZE_KIBIBYTES);
|
||||
int srv = executeSql(cacheSizeQuery.get());
|
||||
int srv = executeSql(mDBConn, cacheSizeQuery.get());
|
||||
if (srv != SQLITE_OK) {
|
||||
::sqlite3_close(mDBConn);
|
||||
mDBConn = nullptr;
|
||||
@ -732,11 +748,11 @@ Connection::databaseElementExists(enum DatabaseElementType aElementType,
|
||||
query.Append("'");
|
||||
|
||||
sqlite3_stmt *stmt;
|
||||
int srv = prepareStatement(query, &stmt);
|
||||
int srv = prepareStatement(mDBConn, query, &stmt);
|
||||
if (srv != SQLITE_OK)
|
||||
return convertResultCode(srv);
|
||||
|
||||
srv = stepStatement(stmt);
|
||||
srv = stepStatement(mDBConn, stmt);
|
||||
// we just care about the return value from step
|
||||
(void)::sqlite3_finalize(stmt);
|
||||
|
||||
@ -801,31 +817,50 @@ Connection::setClosedState()
|
||||
mAsyncExecutionThreadShuttingDown = true;
|
||||
}
|
||||
|
||||
// Set the property to null before closing the connection, otherwise the other
|
||||
// functions in the module may try to use the connection after it is closed.
|
||||
mDBConn = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
Connection::isClosing(bool aResultOnClosed) {
|
||||
Connection::connectionReady()
|
||||
{
|
||||
return mDBConn != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
Connection::isClosing()
|
||||
{
|
||||
bool shuttingDown = false;
|
||||
{
|
||||
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
||||
shuttingDown = mAsyncExecutionThreadShuttingDown;
|
||||
}
|
||||
return shuttingDown && !isClosed();
|
||||
}
|
||||
|
||||
bool
|
||||
Connection::isClosed()
|
||||
{
|
||||
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
||||
return mAsyncExecutionThreadShuttingDown &&
|
||||
(aResultOnClosed || ConnectionReady());
|
||||
return mConnectionClosed;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Connection::internalClose()
|
||||
Connection::internalClose(sqlite3 *aNativeConnection)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Sanity checks to make sure we are in the proper state before calling this.
|
||||
NS_ASSERTION(mDBConn, "Database connection is already null!");
|
||||
MOZ_ASSERT(aNativeConnection, "Database connection is invalid!");
|
||||
MOZ_ASSERT(!isClosed());
|
||||
|
||||
#ifdef DEBUG
|
||||
{ // Make sure we have marked our async thread as shutting down.
|
||||
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
||||
NS_ASSERTION(mAsyncExecutionThreadShuttingDown,
|
||||
"Did not call setClosedState!");
|
||||
}
|
||||
|
||||
bool onOpeningThread = false;
|
||||
(void)threadOpenedOn->IsOnCurrentThread(&onOpeningThread);
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
@ -836,25 +871,23 @@ Connection::internalClose()
|
||||
leafName.get()));
|
||||
#endif
|
||||
|
||||
// Set the property to null before closing the connection, otherwise the other
|
||||
// functions in the module may try to use the connection after it is closed.
|
||||
sqlite3 *dbConn = mDBConn;
|
||||
mDBConn = nullptr;
|
||||
|
||||
// At this stage, we may still have statements that need to be
|
||||
// finalized. Attempt to close the database connection. This will
|
||||
// always disconnect any virtual tables and cleanly finalize their
|
||||
// internal statements. Once this is done, closing may fail due to
|
||||
// unfinalized client statements, in which case we need to finalize
|
||||
// these statements and close again.
|
||||
|
||||
int srv = sqlite3_close(dbConn);
|
||||
{
|
||||
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
||||
mConnectionClosed = true;
|
||||
}
|
||||
int srv = sqlite3_close(aNativeConnection);
|
||||
|
||||
if (srv == SQLITE_BUSY) {
|
||||
// We still have non-finalized statements. Finalize them.
|
||||
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
while ((stmt = ::sqlite3_next_stmt(dbConn, stmt))) {
|
||||
while ((stmt = ::sqlite3_next_stmt(aNativeConnection, stmt))) {
|
||||
PR_LOG(gStorageLog, PR_LOG_NOTICE,
|
||||
("Auto-finalizing SQL statement '%s' (%x)",
|
||||
::sqlite3_sql(stmt),
|
||||
@ -889,7 +922,7 @@ Connection::internalClose()
|
||||
|
||||
// Now that all statements have been finalized, we
|
||||
// should be able to close.
|
||||
srv = ::sqlite3_close(dbConn);
|
||||
srv = ::sqlite3_close(aNativeConnection);
|
||||
|
||||
}
|
||||
|
||||
@ -912,23 +945,21 @@ Connection::getFilename()
|
||||
}
|
||||
|
||||
int
|
||||
Connection::stepStatement(sqlite3_stmt *aStatement)
|
||||
Connection::stepStatement(sqlite3 *aNativeConnection, sqlite3_stmt *aStatement)
|
||||
{
|
||||
MOZ_ASSERT(aStatement);
|
||||
bool checkedMainThread = false;
|
||||
TimeStamp startTime = TimeStamp::Now();
|
||||
|
||||
// mDBConn may be null if the executing statement has been created and cached
|
||||
// after a call to asyncClose() but before the connection has been nullified
|
||||
// by internalClose(). In such a case closing the connection fails due to
|
||||
// the existence of prepared statements, but mDBConn is set to null
|
||||
// regardless. This usually happens when other tasks using cached statements
|
||||
// are asynchronously scheduled for execution and any of them ends up after
|
||||
// asyncClose. See bug 728653 for details.
|
||||
if (!mDBConn)
|
||||
// The connection may have been closed if the executing statement has been
|
||||
// created and cached after a call to asyncClose() but before the actual
|
||||
// sqlite3_close(). This usually happens when other tasks using cached
|
||||
// statements are asynchronously scheduled for execution and any of them ends
|
||||
// up after asyncClose. See bug 728653 for details.
|
||||
if (isClosed())
|
||||
return SQLITE_MISUSE;
|
||||
|
||||
(void)::sqlite3_extended_result_codes(mDBConn, 1);
|
||||
(void)::sqlite3_extended_result_codes(aNativeConnection, 1);
|
||||
|
||||
int srv;
|
||||
while ((srv = ::sqlite3_step(aStatement)) == SQLITE_LOCKED_SHAREDCACHE) {
|
||||
@ -940,7 +971,7 @@ Connection::stepStatement(sqlite3_stmt *aStatement)
|
||||
}
|
||||
}
|
||||
|
||||
srv = WaitForUnlockNotify(mDBConn);
|
||||
srv = WaitForUnlockNotify(aNativeConnection);
|
||||
if (srv != SQLITE_OK) {
|
||||
break;
|
||||
}
|
||||
@ -959,21 +990,26 @@ Connection::stepStatement(sqlite3_stmt *aStatement)
|
||||
duration.ToMilliseconds());
|
||||
}
|
||||
|
||||
(void)::sqlite3_extended_result_codes(mDBConn, 0);
|
||||
(void)::sqlite3_extended_result_codes(aNativeConnection, 0);
|
||||
// Drop off the extended result bits of the result code.
|
||||
return srv & 0xFF;
|
||||
}
|
||||
|
||||
int
|
||||
Connection::prepareStatement(const nsCString &aSQL,
|
||||
Connection::prepareStatement(sqlite3 *aNativeConnection, const nsCString &aSQL,
|
||||
sqlite3_stmt **_stmt)
|
||||
{
|
||||
// We should not even try to prepare statements after the connection has
|
||||
// been closed.
|
||||
if (isClosed())
|
||||
return SQLITE_MISUSE;
|
||||
|
||||
bool checkedMainThread = false;
|
||||
|
||||
(void)::sqlite3_extended_result_codes(mDBConn, 1);
|
||||
(void)::sqlite3_extended_result_codes(aNativeConnection, 1);
|
||||
|
||||
int srv;
|
||||
while((srv = ::sqlite3_prepare_v2(mDBConn,
|
||||
while((srv = ::sqlite3_prepare_v2(aNativeConnection,
|
||||
aSQL.get(),
|
||||
-1,
|
||||
_stmt,
|
||||
@ -986,7 +1022,7 @@ Connection::prepareStatement(const nsCString &aSQL,
|
||||
}
|
||||
}
|
||||
|
||||
srv = WaitForUnlockNotify(mDBConn);
|
||||
srv = WaitForUnlockNotify(aNativeConnection);
|
||||
if (srv != SQLITE_OK) {
|
||||
break;
|
||||
}
|
||||
@ -997,7 +1033,7 @@ Connection::prepareStatement(const nsCString &aSQL,
|
||||
warnMsg.AppendLiteral("The SQL statement '");
|
||||
warnMsg.Append(aSQL);
|
||||
warnMsg.AppendLiteral("' could not be compiled due to an error: ");
|
||||
warnMsg.Append(::sqlite3_errmsg(mDBConn));
|
||||
warnMsg.Append(::sqlite3_errmsg(aNativeConnection));
|
||||
|
||||
#ifdef DEBUG
|
||||
NS_WARNING(warnMsg.get());
|
||||
@ -1005,7 +1041,7 @@ Connection::prepareStatement(const nsCString &aSQL,
|
||||
PR_LOG(gStorageLog, PR_LOG_ERROR, ("%s", warnMsg.get()));
|
||||
}
|
||||
|
||||
(void)::sqlite3_extended_result_codes(mDBConn, 0);
|
||||
(void)::sqlite3_extended_result_codes(aNativeConnection, 0);
|
||||
// Drop off the extended result bits of the result code.
|
||||
int rc = srv & 0xFF;
|
||||
// sqlite will return OK on a comment only string and set _stmt to nullptr.
|
||||
@ -1020,13 +1056,14 @@ Connection::prepareStatement(const nsCString &aSQL,
|
||||
|
||||
|
||||
int
|
||||
Connection::executeSql(const char *aSqlString)
|
||||
Connection::executeSql(sqlite3 *aNativeConnection, const char *aSqlString)
|
||||
{
|
||||
if (!mDBConn)
|
||||
if (isClosed())
|
||||
return SQLITE_MISUSE;
|
||||
|
||||
TimeStamp startTime = TimeStamp::Now();
|
||||
int srv = ::sqlite3_exec(mDBConn, aSqlString, nullptr, nullptr, nullptr);
|
||||
int srv = ::sqlite3_exec(aNativeConnection, aSqlString, nullptr, nullptr,
|
||||
nullptr);
|
||||
|
||||
// Report very slow SQL statements to Telemetry
|
||||
TimeDuration duration = TimeStamp::Now() - startTime;
|
||||
@ -1076,10 +1113,13 @@ Connection::Close()
|
||||
NS_ENSURE_TRUE(asyncCloseWasCalled, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
// setClosedState nullifies our connection pointer, so we take a raw pointer
|
||||
// off it, to pass it through the close procedure.
|
||||
sqlite3 *nativeConn = mDBConn;
|
||||
nsresult rv = setClosedState();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return internalClose();
|
||||
return internalClose(nativeConn);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1094,6 +1134,9 @@ Connection::AsyncClose(mozIStorageCompletionCallback *aCallback)
|
||||
nsIEventTarget *asyncThread = getAsyncExecutionTarget();
|
||||
NS_ENSURE_TRUE(asyncThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
// setClosedState nullifies our connection pointer, so we take a raw pointer
|
||||
// off it, to pass it through the close procedure.
|
||||
sqlite3 *nativeConn = mDBConn;
|
||||
nsresult rv = setClosedState();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -1109,6 +1152,7 @@ Connection::AsyncClose(mozIStorageCompletionCallback *aCallback)
|
||||
// We need to lock because we're modifying mAsyncExecutionThread
|
||||
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
||||
closeEvent = new AsyncCloseConnection(this,
|
||||
nativeConn,
|
||||
completeEvent,
|
||||
mAsyncExecutionThread.forget());
|
||||
}
|
||||
@ -1240,7 +1284,7 @@ Connection::GetDefaultPageSize(int32_t *_defaultPageSize)
|
||||
NS_IMETHODIMP
|
||||
Connection::GetConnectionReady(bool *_ready)
|
||||
{
|
||||
*_ready = ConnectionReady();
|
||||
*_ready = connectionReady();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1335,7 +1379,7 @@ Connection::CreateStatement(const nsACString &aSQLStatement,
|
||||
nsRefPtr<Statement> statement(new Statement());
|
||||
NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = statement->initialize(this, aSQLStatement);
|
||||
nsresult rv = statement->initialize(this, mDBConn, aSQLStatement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
Statement *rawPtr;
|
||||
@ -1354,7 +1398,7 @@ Connection::CreateAsyncStatement(const nsACString &aSQLStatement,
|
||||
nsRefPtr<AsyncStatement> statement(new AsyncStatement());
|
||||
NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsresult rv = statement->initialize(this, aSQLStatement);
|
||||
nsresult rv = statement->initialize(this, mDBConn, aSQLStatement);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AsyncStatement *rawPtr;
|
||||
@ -1368,7 +1412,7 @@ Connection::ExecuteSimpleSQL(const nsACString &aSQLStatement)
|
||||
{
|
||||
if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
int srv = executeSql(PromiseFlatCString(aSQLStatement).get());
|
||||
int srv = executeSql(mDBConn, PromiseFlatCString(aSQLStatement).get());
|
||||
return convertResultCode(srv);
|
||||
}
|
||||
|
||||
@ -1396,7 +1440,8 @@ Connection::ExecuteAsync(mozIStorageBaseStatement **aStatements,
|
||||
}
|
||||
|
||||
// Dispatch to the background
|
||||
return AsyncExecuteStatements::execute(stmts, this, aCallback, _handle);
|
||||
return AsyncExecuteStatements::execute(stmts, this, mDBConn, aCallback,
|
||||
_handle);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1459,19 +1504,26 @@ Connection::BeginTransactionAs(int32_t aTransactionType)
|
||||
{
|
||||
if (!mDBConn) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
return beginTransactionInternal(mDBConn, aTransactionType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Connection::beginTransactionInternal(sqlite3 *aNativeConnection,
|
||||
int32_t aTransactionType)
|
||||
{
|
||||
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
||||
if (mTransactionInProgress)
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv;
|
||||
switch(aTransactionType) {
|
||||
case TRANSACTION_DEFERRED:
|
||||
rv = ExecuteSimpleSQL(NS_LITERAL_CSTRING("BEGIN DEFERRED"));
|
||||
rv = convertResultCode(executeSql(aNativeConnection, "BEGIN DEFERRED"));
|
||||
break;
|
||||
case TRANSACTION_IMMEDIATE:
|
||||
rv = ExecuteSimpleSQL(NS_LITERAL_CSTRING("BEGIN IMMEDIATE"));
|
||||
rv = convertResultCode(executeSql(aNativeConnection, "BEGIN IMMEDIATE"));
|
||||
break;
|
||||
case TRANSACTION_EXCLUSIVE:
|
||||
rv = ExecuteSimpleSQL(NS_LITERAL_CSTRING("BEGIN EXCLUSIVE"));
|
||||
rv = convertResultCode(executeSql(aNativeConnection, "BEGIN EXCLUSIVE"));
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
@ -1487,11 +1539,17 @@ Connection::CommitTransaction()
|
||||
if (!mDBConn)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
return commitTransactionInternal(mDBConn);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Connection::commitTransactionInternal(sqlite3 *aNativeConnection)
|
||||
{
|
||||
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
||||
if (!mTransactionInProgress)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsresult rv = ExecuteSimpleSQL(NS_LITERAL_CSTRING("COMMIT TRANSACTION"));
|
||||
nsresult rv =
|
||||
convertResultCode(executeSql(aNativeConnection, "COMMIT TRANSACTION"));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mTransactionInProgress = false;
|
||||
return rv;
|
||||
@ -1503,11 +1561,18 @@ Connection::RollbackTransaction()
|
||||
if (!mDBConn)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
return rollbackTransactionInternal(mDBConn);
|
||||
}
|
||||
|
||||
nsresult
|
||||
Connection::rollbackTransactionInternal(sqlite3 *aNativeConnection)
|
||||
{
|
||||
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
||||
if (!mTransactionInProgress)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsresult rv = ExecuteSimpleSQL(NS_LITERAL_CSTRING("ROLLBACK TRANSACTION"));
|
||||
nsresult rv =
|
||||
convertResultCode(executeSql(aNativeConnection, "ROLLBACK TRANSACTION"));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mTransactionInProgress = false;
|
||||
return rv;
|
||||
@ -1523,7 +1588,7 @@ Connection::CreateTable(const char *aTableName,
|
||||
if (!buf)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
int srv = executeSql(buf);
|
||||
int srv = executeSql(mDBConn, buf);
|
||||
::PR_smprintf_free(buf);
|
||||
|
||||
return convertResultCode(srv);
|
||||
|
@ -96,9 +96,29 @@ public:
|
||||
*/
|
||||
nsresult initialize(nsIFileURL *aFileURL);
|
||||
|
||||
// fetch the native handle
|
||||
sqlite3 *GetNativeConnection() { return mDBConn; }
|
||||
operator sqlite3 *() const { return mDBConn; }
|
||||
/**
|
||||
* Fetches runtime status information for this connection.
|
||||
*
|
||||
* @param aStatusOption One of the SQLITE_DBSTATUS options defined at
|
||||
* http://www.sqlite.org/c3ref/c_dbstatus_options.html
|
||||
* @param [optional] aMaxValue if provided, will be set to the highest
|
||||
* istantaneous value.
|
||||
* @return the current value for the specified option.
|
||||
*/
|
||||
int32_t getSqliteRuntimeStatus(int32_t aStatusOption,
|
||||
int32_t* aMaxValue=nullptr);
|
||||
/**
|
||||
* Registers/unregisters a commit hook callback.
|
||||
*
|
||||
* @param aCallbackFn a callback function to be invoked on transactions
|
||||
* commit. Pass nullptr to unregister the current callback.
|
||||
* @param [optional] aData if provided, will be passed to the callback.
|
||||
* @see http://sqlite.org/c3ref/commit_hook.html
|
||||
*/
|
||||
void setCommitHook(int (*aCallbackFn)(void *) , void *aData=nullptr) {
|
||||
MOZ_ASSERT(mDBConn, "A connection must exist at this point");
|
||||
::sqlite3_commit_hook(mDBConn, aCallbackFn, aData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Lazily creates and returns a background execution thread. In the future,
|
||||
@ -112,8 +132,12 @@ public:
|
||||
/**
|
||||
* Mutex used by asynchronous statements to protect state. The mutex is
|
||||
* declared on the connection object because there is no contention between
|
||||
* asynchronous statements (they are serialized on mAsyncExecutionThread). It
|
||||
* also protects mPendingStatements.
|
||||
* asynchronous statements (they are serialized on mAsyncExecutionThread).
|
||||
* Currently protects:
|
||||
* - Connection.mAsyncExecutionThreadShuttingDown
|
||||
* - Connection.mAsyncExecutionThread
|
||||
* - Connection.mConnectionClosed
|
||||
* - AsyncExecuteStatements.mCancelRequested
|
||||
*/
|
||||
Mutex sharedAsyncExecutionMutex;
|
||||
|
||||
@ -134,7 +158,7 @@ public:
|
||||
/**
|
||||
* Closes the SQLite database, and warns about any non-finalized statements.
|
||||
*/
|
||||
nsresult internalClose();
|
||||
nsresult internalClose(sqlite3 *aDBConn);
|
||||
|
||||
/**
|
||||
* Obtains the filename of the connection. Useful for logging.
|
||||
@ -144,39 +168,52 @@ public:
|
||||
/**
|
||||
* Creates an sqlite3 prepared statement object from an SQL string.
|
||||
*
|
||||
* @param aNativeConnection
|
||||
* The underlying Sqlite connection to prepare the statement with.
|
||||
* @param aSQL
|
||||
* The SQL statement string to compile.
|
||||
* @param _stmt
|
||||
* New sqlite3_stmt object.
|
||||
* @return the result from sqlite3_prepare_v2.
|
||||
*/
|
||||
int prepareStatement(const nsCString &aSQL, sqlite3_stmt **_stmt);
|
||||
int prepareStatement(sqlite3* aNativeConnection,
|
||||
const nsCString &aSQL, sqlite3_stmt **_stmt);
|
||||
|
||||
/**
|
||||
* Performs a sqlite3_step on aStatement, while properly handling SQLITE_LOCKED
|
||||
* when not on the main thread by waiting until we are notified.
|
||||
*
|
||||
* @param aNativeConnection
|
||||
* The underlying Sqlite connection to step the statement with.
|
||||
* @param aStatement
|
||||
* A pointer to a sqlite3_stmt object.
|
||||
* @return the result from sqlite3_step.
|
||||
*/
|
||||
int stepStatement(sqlite3_stmt* aStatement);
|
||||
|
||||
bool ConnectionReady() {
|
||||
return mDBConn != nullptr;
|
||||
}
|
||||
int stepStatement(sqlite3* aNativeConnection, sqlite3_stmt* aStatement);
|
||||
|
||||
/**
|
||||
* True if this connection is currently shutting down.
|
||||
* Raw connection transaction management.
|
||||
*
|
||||
* In particular, if |isClosing(true)| returns |true|, any sqlite3 statement
|
||||
* belonging to this connection must be discarded as its memory has already
|
||||
* been released to sqlite3.
|
||||
*
|
||||
* @param aResultOnceClosed
|
||||
* The value to return if closing has completed.
|
||||
* @see BeginTransactionAs, CommitTransaction, RollbackTransaction.
|
||||
*/
|
||||
bool isClosing(bool aResultOnceClosed = false);
|
||||
nsresult beginTransactionInternal(sqlite3 *aNativeConnection,
|
||||
int32_t aTransactionType=TRANSACTION_DEFERRED);
|
||||
nsresult commitTransactionInternal(sqlite3 *aNativeConnection);
|
||||
nsresult rollbackTransactionInternal(sqlite3 *aNativeConnection);
|
||||
|
||||
bool connectionReady();
|
||||
|
||||
/**
|
||||
* True if this connection is shutting down but not yet closed.
|
||||
*/
|
||||
bool isClosing();
|
||||
|
||||
/**
|
||||
* True if the underlying connection is closed.
|
||||
* Any sqlite resources may be lost when this returns true, so nothing should
|
||||
* try to use them.
|
||||
*/
|
||||
bool isClosed();
|
||||
|
||||
nsresult initializeClone(Connection *aClone, bool aReadOnly);
|
||||
|
||||
@ -195,11 +232,13 @@ private:
|
||||
/**
|
||||
* Helper for calls to sqlite3_exec. Reports long delays to Telemetry.
|
||||
*
|
||||
* @param aNativeConnection
|
||||
* The underlying Sqlite connection to execute the query with.
|
||||
* @param aSqlString
|
||||
* SQL string to execute
|
||||
* @return the result from sqlite3_exec.
|
||||
*/
|
||||
int executeSql(const char *aSqlString);
|
||||
int executeSql(sqlite3 *aNativeConnection, const char *aSqlString);
|
||||
|
||||
/**
|
||||
* Describes a certain primitive type in the database.
|
||||
@ -256,25 +295,34 @@ private:
|
||||
* returns null.
|
||||
*
|
||||
* This variable should be accessed while holding the
|
||||
* mAsyncExecutionMutex.
|
||||
* sharedAsyncExecutionMutex.
|
||||
*/
|
||||
bool mAsyncExecutionThreadShuttingDown;
|
||||
|
||||
/**
|
||||
* Set to true just prior to calling sqlite3_close on the
|
||||
* connection.
|
||||
*
|
||||
* This variable should be accessed while holding the
|
||||
* sharedAsyncExecutionMutex.
|
||||
*/
|
||||
bool mConnectionClosed;
|
||||
|
||||
/**
|
||||
* Tracks if we have a transaction in progress or not. Access protected by
|
||||
* mDBMutex.
|
||||
* sharedDBMutex.
|
||||
*/
|
||||
bool mTransactionInProgress;
|
||||
|
||||
/**
|
||||
* Stores the mapping of a given function by name to its instance. Access is
|
||||
* protected by mDBMutex.
|
||||
* protected by sharedDBMutex.
|
||||
*/
|
||||
nsDataHashtable<nsCStringHashKey, FunctionInfo> mFunctions;
|
||||
|
||||
/**
|
||||
* Stores the registered progress handler for the database connection. Access
|
||||
* is protected by mDBMutex.
|
||||
* is protected by sharedDBMutex.
|
||||
*/
|
||||
nsCOMPtr<mozIStorageProgressHandler> mProgressHandler;
|
||||
|
||||
|
@ -94,28 +94,24 @@ StorageSQLiteDistinguishedAmount()
|
||||
nsresult
|
||||
ReportConn(nsIHandleReportCallback *aHandleReport,
|
||||
nsISupports *aData,
|
||||
sqlite3 *aConn,
|
||||
Connection *aConn,
|
||||
const nsACString &aPathHead,
|
||||
const nsACString &aKind,
|
||||
const nsACString &aDesc,
|
||||
int aOption,
|
||||
int32_t aOption,
|
||||
size_t *aTotal)
|
||||
{
|
||||
nsCString path(aPathHead);
|
||||
path.Append(aKind);
|
||||
path.AppendLiteral("-used");
|
||||
|
||||
int curr = 0, max = 0;
|
||||
int rc = ::sqlite3_db_status(aConn, aOption, &curr, &max, 0);
|
||||
nsresult rv = convertResultCode(rc);
|
||||
int32_t val = aConn->getSqliteRuntimeStatus(aOption);
|
||||
nsresult rv = aHandleReport->Callback(EmptyCString(), path,
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES,
|
||||
int64_t(val), aDesc, aData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aHandleReport->Callback(EmptyCString(), path,
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES, int64_t(curr),
|
||||
aDesc, aData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*aTotal += curr;
|
||||
*aTotal += val;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -155,7 +151,7 @@ Service::CollectReports(nsIHandleReportCallback *aHandleReport,
|
||||
NS_NAMED_LITERAL_CSTRING(stmtDesc,
|
||||
"Memory (approximate) used by all prepared statements used by "
|
||||
"connections to this database.");
|
||||
rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
|
||||
rv = ReportConn(aHandleReport, aData, conn, pathHead,
|
||||
NS_LITERAL_CSTRING("stmt"), stmtDesc,
|
||||
SQLITE_DBSTATUS_STMT_USED, &totalConnSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -163,7 +159,7 @@ Service::CollectReports(nsIHandleReportCallback *aHandleReport,
|
||||
NS_NAMED_LITERAL_CSTRING(cacheDesc,
|
||||
"Memory (approximate) used by all pager caches used by connections "
|
||||
"to this database.");
|
||||
rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
|
||||
rv = ReportConn(aHandleReport, aData, conn, pathHead,
|
||||
NS_LITERAL_CSTRING("cache"), cacheDesc,
|
||||
SQLITE_DBSTATUS_CACHE_USED, &totalConnSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -171,7 +167,7 @@ Service::CollectReports(nsIHandleReportCallback *aHandleReport,
|
||||
NS_NAMED_LITERAL_CSTRING(schemaDesc,
|
||||
"Memory (approximate) used to store the schema for all databases "
|
||||
"associated with connections to this database.");
|
||||
rv = ReportConn(aHandleReport, aData, *conn.get(), pathHead,
|
||||
rv = ReportConn(aHandleReport, aData, conn, pathHead,
|
||||
NS_LITERAL_CSTRING("schema"), schemaDesc,
|
||||
SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -350,7 +346,7 @@ Service::minimizeMemory()
|
||||
|
||||
for (uint32_t i = 0; i < connections.Length(); i++) {
|
||||
nsRefPtr<Connection> conn = connections[i];
|
||||
if (conn->ConnectionReady()) {
|
||||
if (conn->connectionReady()) {
|
||||
NS_NAMED_LITERAL_CSTRING(shrinkPragma, "PRAGMA shrink_memory");
|
||||
nsCOMPtr<mozIStorageConnection> syncConn = do_QueryInterface(
|
||||
NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*, conn));
|
||||
@ -918,9 +914,6 @@ Service::Observe(nsISupports *, const char *aTopic, const char16_t *)
|
||||
anyOpen = false;
|
||||
for (uint32_t i = 0; i < connections.Length(); i++) {
|
||||
nsRefPtr<Connection> &conn = connections[i];
|
||||
|
||||
// While it would be nice to close all connections, we only
|
||||
// check async ones for now.
|
||||
if (conn->isClosing()) {
|
||||
anyOpen = true;
|
||||
break;
|
||||
@ -936,7 +929,7 @@ Service::Observe(nsISupports *, const char *aTopic, const char16_t *)
|
||||
nsTArray<nsRefPtr<Connection> > connections;
|
||||
getConnections(connections);
|
||||
for (uint32_t i = 0, n = connections.Length(); i < n; i++) {
|
||||
if (connections[i]->ConnectionReady()) {
|
||||
if (!connections[i]->isClosed()) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
@ -135,20 +135,21 @@ Statement::Statement()
|
||||
|
||||
nsresult
|
||||
Statement::initialize(Connection *aDBConnection,
|
||||
sqlite3 *aNativeConnection,
|
||||
const nsACString &aSQLStatement)
|
||||
{
|
||||
NS_ASSERTION(aDBConnection, "No database connection given!");
|
||||
NS_ASSERTION(!mDBStatement, "Statement already initialized!");
|
||||
MOZ_ASSERT(aDBConnection, "No database connection given!");
|
||||
MOZ_ASSERT(!aDBConnection->isClosed(), "Database connection should be valid");
|
||||
MOZ_ASSERT(!mDBStatement, "Statement already initialized!");
|
||||
MOZ_ASSERT(aNativeConnection, "No native connection given!");
|
||||
|
||||
DebugOnly<sqlite3 *> db = aDBConnection->GetNativeConnection();
|
||||
NS_ASSERTION(db, "We should never be called with a null sqlite3 database!");
|
||||
|
||||
int srv = aDBConnection->prepareStatement(PromiseFlatCString(aSQLStatement),
|
||||
int srv = aDBConnection->prepareStatement(aNativeConnection,
|
||||
PromiseFlatCString(aSQLStatement),
|
||||
&mDBStatement);
|
||||
if (srv != SQLITE_OK) {
|
||||
PR_LOG(gStorageLog, PR_LOG_ERROR,
|
||||
("Sqlite statement prepare error: %d '%s'", srv,
|
||||
::sqlite3_errmsg(db)));
|
||||
::sqlite3_errmsg(aNativeConnection)));
|
||||
PR_LOG(gStorageLog, PR_LOG_ERROR,
|
||||
("Statement was: '%s'", PromiseFlatCString(aSQLStatement).get()));
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -159,6 +160,7 @@ Statement::initialize(Connection *aDBConnection,
|
||||
mDBStatement));
|
||||
|
||||
mDBConnection = aDBConnection;
|
||||
mNativeConnection = aNativeConnection;
|
||||
mParamCount = ::sqlite3_bind_parameter_count(mDBStatement);
|
||||
mResultColumnCount = ::sqlite3_column_count(mDBStatement);
|
||||
mColumnNames.Clear();
|
||||
@ -284,7 +286,8 @@ Statement::getAsyncStatement(sqlite3_stmt **_stmt)
|
||||
// If we do not yet have a cached async statement, clone our statement now.
|
||||
if (!mAsyncStatement) {
|
||||
nsDependentCString sql(::sqlite3_sql(mDBStatement));
|
||||
int rc = mDBConnection->prepareStatement(sql, &mAsyncStatement);
|
||||
int rc = mDBConnection->prepareStatement(mNativeConnection, sql,
|
||||
&mAsyncStatement);
|
||||
if (rc != SQLITE_OK) {
|
||||
*_stmt = nullptr;
|
||||
return rc;
|
||||
@ -335,7 +338,7 @@ Statement::Clone(mozIStorageStatement **_statement)
|
||||
NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsAutoCString sql(::sqlite3_sql(mDBStatement));
|
||||
nsresult rv = statement->initialize(mDBConnection, sql);
|
||||
nsresult rv = statement->initialize(mDBConnection, mNativeConnection, sql);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
statement.forget(_statement);
|
||||
@ -356,7 +359,7 @@ Statement::internalFinalize(bool aDestructing)
|
||||
|
||||
int srv = SQLITE_OK;
|
||||
|
||||
if (!mDBConnection->isClosing(true)) {
|
||||
if (!mDBConnection->isClosed()) {
|
||||
//
|
||||
// The connection is still open. While statement finalization and
|
||||
// closing may, in some cases, take place in two distinct threads,
|
||||
@ -632,7 +635,7 @@ Statement::ExecuteStep(bool *_moreResults)
|
||||
// We have bound, so now we can clear our array.
|
||||
mParamsArray = nullptr;
|
||||
}
|
||||
int srv = mDBConnection->stepStatement(mDBStatement);
|
||||
int srv = mDBConnection->stepStatement(mNativeConnection, mDBStatement);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
if (srv != SQLITE_ROW && srv != SQLITE_DONE) {
|
||||
|
@ -47,10 +47,13 @@ public:
|
||||
*
|
||||
* @param aDBConnection
|
||||
* The Connection object this statement is associated with.
|
||||
* @param aNativeConnection
|
||||
* The native Sqlite connection this statement is associated with.
|
||||
* @param aSQLStatement
|
||||
* The SQL statement to prepare that this object will represent.
|
||||
*/
|
||||
nsresult initialize(Connection *aDBConnection,
|
||||
sqlite3* aNativeConnection,
|
||||
const nsACString &aSQLStatement);
|
||||
|
||||
|
||||
|
@ -71,15 +71,6 @@ public:
|
||||
|
||||
operator BindingParamsArray *() const { return mParamsArray; }
|
||||
|
||||
/**
|
||||
* Provide the ability to coerce back to a sqlite3 * connection for purposes
|
||||
* of getting an error message out of it.
|
||||
*/
|
||||
operator sqlite3 *() const
|
||||
{
|
||||
return mStatementOwner->getOwner()->GetNativeConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* NULLs out our sqlite3_stmt (it is held by the owner) after reseting it and
|
||||
* clear all bindings to it. This is expected to occur on the async thread.
|
||||
|
@ -48,7 +48,7 @@ check_transaction(mozIStorageConnection *aDB,
|
||||
{
|
||||
// -- install a transaction commit hook.
|
||||
int commit = 0;
|
||||
::sqlite3_commit_hook(*static_cast<Connection *>(aDB), commit_hook, &commit);
|
||||
static_cast<Connection *>(aDB)->setCommitHook(commit_hook, &commit);
|
||||
|
||||
nsRefPtr<AsyncStatementSpinner> asyncSpin(new AsyncStatementSpinner());
|
||||
nsCOMPtr<mozIStoragePendingStatement> asyncPend;
|
||||
@ -60,7 +60,7 @@ check_transaction(mozIStorageConnection *aDB,
|
||||
asyncSpin->SpinUntilCompleted();
|
||||
|
||||
// -- uninstall the transaction commit hook.
|
||||
::sqlite3_commit_hook(*static_cast<Connection *>(aDB), nullptr, nullptr);
|
||||
static_cast<Connection *>(aDB)->setCommitHook(nullptr);
|
||||
|
||||
// -- check transaction
|
||||
do_check_eq(aTransactionExpected, !!commit);
|
||||
|
@ -35,10 +35,6 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Services.prefs.setBoolPref("marionette.contentListener", false);
|
||||
let appName = Services.appinfo.name;
|
||||
|
||||
// dumpn needed/used by dbg-transport.js
|
||||
this.dumpn = function dumpn(str) {
|
||||
logger.trace(str);
|
||||
}
|
||||
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js");
|
||||
this.DevToolsUtils = DevToolsUtils;
|
||||
|
@ -215,18 +215,17 @@ SetJournalMode(nsCOMPtr<mozIStorageConnection>& aDBConn,
|
||||
return JOURNAL_DELETE;
|
||||
}
|
||||
|
||||
class BlockingConnectionCloseCallback MOZ_FINAL : public mozIStorageCompletionCallback {
|
||||
class ConnectionCloseCallback MOZ_FINAL : public mozIStorageCompletionCallback {
|
||||
bool mDone;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
|
||||
BlockingConnectionCloseCallback();
|
||||
void Spin();
|
||||
ConnectionCloseCallback();
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
BlockingConnectionCloseCallback::Complete(nsresult, nsISupports*)
|
||||
ConnectionCloseCallback::Complete(nsresult, nsISupports*)
|
||||
{
|
||||
mDone = true;
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
@ -240,21 +239,14 @@ BlockingConnectionCloseCallback::Complete(nsresult, nsISupports*)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
BlockingConnectionCloseCallback::BlockingConnectionCloseCallback()
|
||||
ConnectionCloseCallback::ConnectionCloseCallback()
|
||||
: mDone(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
void BlockingConnectionCloseCallback::Spin() {
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
while (!mDone) {
|
||||
NS_ProcessNextEvent(thread);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(
|
||||
BlockingConnectionCloseCallback
|
||||
ConnectionCloseCallback
|
||||
, mozIStorageCompletionCallback
|
||||
)
|
||||
|
||||
@ -1939,12 +1931,11 @@ Database::Shutdown()
|
||||
);
|
||||
DispatchToAsyncThread(event);
|
||||
|
||||
nsRefPtr<BlockingConnectionCloseCallback> closeListener =
|
||||
new BlockingConnectionCloseCallback();
|
||||
(void)mMainConn->AsyncClose(closeListener);
|
||||
closeListener->Spin();
|
||||
|
||||
mClosed = true;
|
||||
|
||||
nsRefPtr<ConnectionCloseCallback> closeListener =
|
||||
new ConnectionCloseCallback();
|
||||
(void)mMainConn->AsyncClose(closeListener);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -10,7 +10,7 @@
|
||||
// on the main thread, and false if we are running on a worker thread.
|
||||
var { Ci, Cu } = require("chrome");
|
||||
var Services = require("Services");
|
||||
var setTimeout = Cu.import("resource://gre/modules/Timer.jsm", {}).setTimeout;
|
||||
var { setTimeout } = require("Timer");
|
||||
|
||||
/**
|
||||
* Turn the error |aError| into a string, without fail.
|
||||
|
@ -23,6 +23,7 @@ let Debugger = sandbox.Debugger;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let Timer = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm");
|
||||
@ -63,6 +64,7 @@ BuiltinProvider.prototype = {
|
||||
modules: {
|
||||
"Debugger": Debugger,
|
||||
"Services": Object.create(Services),
|
||||
"Timer": Object.create(Timer),
|
||||
"toolkit/loader": loader,
|
||||
"source-map": SourceMap,
|
||||
},
|
||||
@ -141,6 +143,7 @@ SrcdirProvider.prototype = {
|
||||
modules: {
|
||||
"Debugger": Debugger,
|
||||
"Services": Object.create(Services),
|
||||
"Timer": Object.create(Timer),
|
||||
"toolkit/loader": loader,
|
||||
"source-map": SourceMap,
|
||||
},
|
||||
|
168
toolkit/devtools/server/actors/common.js
Normal file
168
toolkit/devtools/server/actors/common.js
Normal file
@ -0,0 +1,168 @@
|
||||
/* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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";
|
||||
|
||||
/**
|
||||
* Methods shared between RootActor and BrowserTabActor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Populate |this._extraActors| as specified by |aFactories|, reusing whatever
|
||||
* actors are already there. Add all actors in the final extra actors table to
|
||||
* |aPool|.
|
||||
*
|
||||
* The root actor and the tab actor use this to instantiate actors that other
|
||||
* parts of the browser have specified with DebuggerServer.addTabActor antd
|
||||
* DebuggerServer.addGlobalActor.
|
||||
*
|
||||
* @param aFactories
|
||||
* An object whose own property names are the names of properties to add to
|
||||
* some reply packet (say, a tab actor grip or the "listTabs" response
|
||||
* form), and whose own property values are actor constructor functions, as
|
||||
* documented for addTabActor and addGlobalActor.
|
||||
*
|
||||
* @param this
|
||||
* The BrowserRootActor or BrowserTabActor with which the new actors will
|
||||
* be associated. It should support whatever API the |aFactories|
|
||||
* constructor functions might be interested in, as it is passed to them.
|
||||
* For the sake of CommonCreateExtraActors itself, it should have at least
|
||||
* the following properties:
|
||||
*
|
||||
* - _extraActors
|
||||
* An object whose own property names are factory table (and packet)
|
||||
* property names, and whose values are no-argument actor constructors,
|
||||
* of the sort that one can add to an ActorPool.
|
||||
*
|
||||
* - conn
|
||||
* The DebuggerServerConnection in which the new actors will participate.
|
||||
*
|
||||
* - actorID
|
||||
* The actor's name, for use as the new actors' parentID.
|
||||
*/
|
||||
exports.createExtraActors = function createExtraActors(aFactories, aPool) {
|
||||
// Walk over global actors added by extensions.
|
||||
for (let name in aFactories) {
|
||||
let actor = this._extraActors[name];
|
||||
if (!actor) {
|
||||
actor = aFactories[name].bind(null, this.conn, this);
|
||||
actor.prototype = aFactories[name].prototype;
|
||||
actor.parentID = this.actorID;
|
||||
this._extraActors[name] = actor;
|
||||
}
|
||||
aPool.addActor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the extra actors in |this._extraActors|, constructed by a prior call
|
||||
* to CommonCreateExtraActors, to |aObject|.
|
||||
*
|
||||
* @param aObject
|
||||
* The object to which the extra actors should be added, under the
|
||||
* property names given in the |aFactories| table passed to
|
||||
* CommonCreateExtraActors.
|
||||
*
|
||||
* @param this
|
||||
* The BrowserRootActor or BrowserTabActor whose |_extraActors| table we
|
||||
* should use; see above.
|
||||
*/
|
||||
exports.appendExtraActors = function appendExtraActors(aObject) {
|
||||
for (let name in this._extraActors) {
|
||||
let actor = this._extraActors[name];
|
||||
aObject[name] = actor.actorID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an ActorPool.
|
||||
*
|
||||
* ActorPools are actorID -> actor mapping and storage. These are
|
||||
* used to accumulate and quickly dispose of groups of actors that
|
||||
* share a lifetime.
|
||||
*/
|
||||
function ActorPool(aConnection)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this._cleanups = {};
|
||||
this._actors = {};
|
||||
}
|
||||
|
||||
ActorPool.prototype = {
|
||||
/**
|
||||
* Add an actor to the actor pool. If the actor doesn't have an ID,
|
||||
* allocate one from the connection.
|
||||
*
|
||||
* @param aActor object
|
||||
* The actor implementation. If the object has a
|
||||
* 'disconnect' property, it will be called when the actor
|
||||
* pool is cleaned up.
|
||||
*/
|
||||
addActor: function AP_addActor(aActor) {
|
||||
aActor.conn = this.conn;
|
||||
if (!aActor.actorID) {
|
||||
let prefix = aActor.actorPrefix;
|
||||
if (typeof aActor == "function") {
|
||||
// typeName is a convention used with protocol.js-based actors
|
||||
prefix = aActor.prototype.actorPrefix || aActor.prototype.typeName;
|
||||
}
|
||||
aActor.actorID = this.conn.allocID(prefix || undefined);
|
||||
}
|
||||
|
||||
if (aActor.registeredPool) {
|
||||
aActor.registeredPool.removeActor(aActor);
|
||||
}
|
||||
aActor.registeredPool = this;
|
||||
|
||||
this._actors[aActor.actorID] = aActor;
|
||||
if (aActor.disconnect) {
|
||||
this._cleanups[aActor.actorID] = aActor;
|
||||
}
|
||||
},
|
||||
|
||||
get: function AP_get(aActorID) {
|
||||
return this._actors[aActorID];
|
||||
},
|
||||
|
||||
has: function AP_has(aActorID) {
|
||||
return aActorID in this._actors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the pool is empty.
|
||||
*/
|
||||
isEmpty: function AP_isEmpty() {
|
||||
return Object.keys(this._actors).length == 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an actor from the actor pool.
|
||||
*/
|
||||
removeActor: function AP_remove(aActor) {
|
||||
delete this._actors[aActor.actorID];
|
||||
delete this._cleanups[aActor.actorID];
|
||||
},
|
||||
|
||||
/**
|
||||
* Match the api expected by the protocol library.
|
||||
*/
|
||||
unmanage: function(aActor) {
|
||||
return this.removeActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Run all actor cleanups.
|
||||
*/
|
||||
cleanup: function AP_cleanup() {
|
||||
for each (let actor in this._cleanups) {
|
||||
actor.disconnect();
|
||||
}
|
||||
this._cleanups = {};
|
||||
}
|
||||
}
|
||||
|
||||
exports.ActorPool = ActorPool;
|
||||
|
@ -8,9 +8,9 @@ const protocol = require("devtools/server/protocol");
|
||||
const {method, RetVal} = protocol;
|
||||
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
const {LongStringActor} = require("devtools/server/actors/string");
|
||||
const {DebuggerServer} = require("devtools/server/main");
|
||||
|
||||
Cu.import("resource://gre/modules/PermissionsTable.jsm")
|
||||
Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
|
||||
|
||||
const APP_MAP = {
|
||||
'{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'firefox',
|
||||
|
@ -8,7 +8,6 @@ const {Arg, method, RetVal} = protocol;
|
||||
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
|
||||
|
||||
exports.register = function(handle) {
|
||||
handle.addGlobalActor(PreferenceActor, "preferenceActor");
|
||||
|
@ -6,79 +6,11 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
let devtools_ = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
||||
let { createExtraActors, appendExtraActors } = devtools_.require("devtools/server/actors/common");
|
||||
|
||||
/* Root actor for the remote debugging protocol. */
|
||||
|
||||
/**
|
||||
* Methods shared between RootActor and BrowserTabActor.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Populate |this._extraActors| as specified by |aFactories|, reusing whatever
|
||||
* actors are already there. Add all actors in the final extra actors table to
|
||||
* |aPool|.
|
||||
*
|
||||
* The root actor and the tab actor use this to instantiate actors that other
|
||||
* parts of the browser have specified with DebuggerServer.addTabActor antd
|
||||
* DebuggerServer.addGlobalActor.
|
||||
*
|
||||
* @param aFactories
|
||||
* An object whose own property names are the names of properties to add to
|
||||
* some reply packet (say, a tab actor grip or the "listTabs" response
|
||||
* form), and whose own property values are actor constructor functions, as
|
||||
* documented for addTabActor and addGlobalActor.
|
||||
*
|
||||
* @param this
|
||||
* The BrowserRootActor or BrowserTabActor with which the new actors will
|
||||
* be associated. It should support whatever API the |aFactories|
|
||||
* constructor functions might be interested in, as it is passed to them.
|
||||
* For the sake of CommonCreateExtraActors itself, it should have at least
|
||||
* the following properties:
|
||||
*
|
||||
* - _extraActors
|
||||
* An object whose own property names are factory table (and packet)
|
||||
* property names, and whose values are no-argument actor constructors,
|
||||
* of the sort that one can add to an ActorPool.
|
||||
*
|
||||
* - conn
|
||||
* The DebuggerServerConnection in which the new actors will participate.
|
||||
*
|
||||
* - actorID
|
||||
* The actor's name, for use as the new actors' parentID.
|
||||
*/
|
||||
function CommonCreateExtraActors(aFactories, aPool) {
|
||||
// Walk over global actors added by extensions.
|
||||
for (let name in aFactories) {
|
||||
let actor = this._extraActors[name];
|
||||
if (!actor) {
|
||||
actor = aFactories[name].bind(null, this.conn, this);
|
||||
actor.prototype = aFactories[name].prototype;
|
||||
actor.parentID = this.actorID;
|
||||
this._extraActors[name] = actor;
|
||||
}
|
||||
aPool.addActor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the extra actors in |this._extraActors|, constructed by a prior call
|
||||
* to CommonCreateExtraActors, to |aObject|.
|
||||
*
|
||||
* @param aObject
|
||||
* The object to which the extra actors should be added, under the
|
||||
* property names given in the |aFactories| table passed to
|
||||
* CommonCreateExtraActors.
|
||||
*
|
||||
* @param this
|
||||
* The BrowserRootActor or BrowserTabActor whose |_extraActors| table we
|
||||
* should use; see above.
|
||||
*/
|
||||
function CommonAppendExtraActors(aObject) {
|
||||
for (let name in this._extraActors) {
|
||||
let actor = this._extraActors[name];
|
||||
aObject[name] = actor.actorID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a remote debugging protocol root actor.
|
||||
*
|
||||
@ -364,8 +296,8 @@ RootActor.prototype = {
|
||||
},
|
||||
|
||||
/* Support for DebuggerServer.addGlobalActor. */
|
||||
_createExtraActors: CommonCreateExtraActors,
|
||||
_appendExtraActors: CommonAppendExtraActors,
|
||||
_createExtraActors: createExtraActors,
|
||||
_appendExtraActors: appendExtraActors,
|
||||
|
||||
/* ThreadActor hooks. */
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
/* 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";
|
||||
|
||||
let B2G_ID = "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}";
|
||||
@ -554,7 +555,7 @@ ThreadActor.prototype = {
|
||||
this._prettyPrintWorker.addEventListener(
|
||||
"error", this._onPrettyPrintError, false);
|
||||
|
||||
if (wantLogging) {
|
||||
if (dumpn.wantLogging) {
|
||||
this._prettyPrintWorker.addEventListener("message", this._onPrettyPrintMsg, false);
|
||||
|
||||
const postMsg = this._prettyPrintWorker.postMessage;
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
let {Cu} = require("chrome");
|
||||
let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
let {DebuggerServer} = require("devtools/server/main");
|
||||
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
let {Class} = require("sdk/core/heritage");
|
||||
|
@ -5,7 +5,7 @@
|
||||
"use strict";
|
||||
|
||||
const { Cu } = require("chrome");
|
||||
const { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
|
||||
|
||||
Cu.import("resource://gre/modules/jsdebugger.jsm");
|
||||
|
@ -6,8 +6,14 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
let {Cu} = require("chrome");
|
||||
let {Ci,Cu} = require("chrome");
|
||||
let {createExtraActors, appendExtraActors} = require("devtools/server/actors/common");
|
||||
let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
|
||||
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
// Assumptions on events module:
|
||||
@ -17,6 +23,10 @@ XPCOMUtils.defineLazyGetter(this, "events", () => {
|
||||
return devtools.require("sdk/event/core");
|
||||
});
|
||||
|
||||
// Also depends on following symbols, shared by common scope with main.js:
|
||||
// DebuggerServer, CommonCreateExtraActors, CommonAppendExtraActors, ActorPool,
|
||||
// ThreadActor
|
||||
|
||||
/**
|
||||
* Browser-specific actors.
|
||||
*/
|
||||
@ -661,8 +671,8 @@ TabActor.prototype = {
|
||||
},
|
||||
|
||||
/* Support for DebuggerServer.addTabActor. */
|
||||
_createExtraActors: CommonCreateExtraActors,
|
||||
_appendExtraActors: CommonAppendExtraActors,
|
||||
_createExtraActors: createExtraActors,
|
||||
_appendExtraActors: appendExtraActors,
|
||||
|
||||
/**
|
||||
* Does the actual work of attching to a tab.
|
||||
@ -1040,9 +1050,15 @@ TabActor.prototype = {
|
||||
* True if the window.console object is native, or false otherwise.
|
||||
*/
|
||||
hasNativeConsoleAPI: function BTA_hasNativeConsoleAPI(aWindow) {
|
||||
// Do not expose WebConsoleActor function directly as it is always
|
||||
// loaded after the BrowserTabActor
|
||||
return WebConsoleActor.prototype.hasNativeConsoleAPI(aWindow);
|
||||
let isNative = false;
|
||||
try {
|
||||
// We are very explicitly examining the "console" property of
|
||||
// the non-Xrayed object here.
|
||||
let console = aWindow.wrappedJSObject.console;
|
||||
isNative = console instanceof aWindow.Console;
|
||||
}
|
||||
catch (ex) { }
|
||||
return isNative;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -6,28 +6,34 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
let Cu = Components.utils;
|
||||
let {Cc, Ci, Cu} = require("chrome");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
||||
let { DebuggerServer, ActorPool } = require("devtools/server/main");
|
||||
// Symbols from script.js
|
||||
let { ThreadActor, EnvironmentActor, ObjectActor, LongStringActor } = DebuggerServer;
|
||||
|
||||
Cu.import("resource://gre/modules/jsdebugger.jsm");
|
||||
addDebuggerToGlobal(this);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "NetworkMonitor", () => {
|
||||
return devtools.require("devtools/toolkit/webconsole/network-monitor")
|
||||
return require("devtools/toolkit/webconsole/network-monitor")
|
||||
.NetworkMonitor;
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "NetworkMonitorChild", () => {
|
||||
return devtools.require("devtools/toolkit/webconsole/network-monitor")
|
||||
return require("devtools/toolkit/webconsole/network-monitor")
|
||||
.NetworkMonitorChild;
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "ConsoleProgressListener", () => {
|
||||
return devtools.require("devtools/toolkit/webconsole/network-monitor")
|
||||
return require("devtools/toolkit/webconsole/network-monitor")
|
||||
.ConsoleProgressListener;
|
||||
});
|
||||
XPCOMUtils.defineLazyGetter(this, "events", () => {
|
||||
return require("sdk/event/core");
|
||||
});
|
||||
|
||||
for (let name of ["WebConsoleUtils", "ConsoleServiceListener",
|
||||
"ConsoleAPIListener", "JSTermHelpers", "JSPropertyProvider",
|
||||
@ -37,7 +43,7 @@ for (let name of ["WebConsoleUtils", "ConsoleServiceListener",
|
||||
if (prop == "WebConsoleUtils") {
|
||||
prop = "Utils";
|
||||
}
|
||||
return devtools.require("devtools/toolkit/webconsole/utils")[prop];
|
||||
return require("devtools/toolkit/webconsole/utils")[prop];
|
||||
}.bind(null, name),
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
@ -1831,6 +1837,12 @@ NetworkEventActor.prototype.requestTypes =
|
||||
"getEventTimings": NetworkEventActor.prototype.onGetEventTimings,
|
||||
};
|
||||
|
||||
DebuggerServer.addTabActor(WebConsoleActor, "consoleActor");
|
||||
DebuggerServer.addGlobalActor(WebConsoleActor, "consoleActor");
|
||||
exports.register = function(handle) {
|
||||
handle.addGlobalActor(WebConsoleActor, "consoleActor");
|
||||
handle.addTabActor(WebConsoleActor, "consoleActor");
|
||||
};
|
||||
|
||||
exports.unregister = function(handle) {
|
||||
handle.removeGlobalActor(WebConsoleActor, "consoleActor");
|
||||
handle.removeTabActor(WebConsoleActor, "consoleActor");
|
||||
};
|
||||
|
@ -12,7 +12,9 @@
|
||||
let { Ci, Cc, CC, Cu, Cr } = require("chrome");
|
||||
let Debugger = require("Debugger");
|
||||
let Services = require("Services");
|
||||
let DevToolsUtils = require("devtools/toolkit/DevToolsUtils.js");
|
||||
let { ActorPool } = require("devtools/server/actors/common");
|
||||
let { DebuggerTransport, LocalDebuggerTransport, ChildDebuggerTransport } = require("devtools/server/transport");
|
||||
let DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
let { dumpn, dbg_assert } = DevToolsUtils;
|
||||
let Services = require("Services");
|
||||
let EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
@ -30,6 +32,7 @@ this.Cu = Cu;
|
||||
this.Cr = Cr;
|
||||
this.Debugger = Debugger;
|
||||
this.Services = Services;
|
||||
this.ActorPool = ActorPool;
|
||||
this.DevToolsUtils = DevToolsUtils;
|
||||
this.dumpn = dumpn;
|
||||
this.dbg_assert = dbg_assert;
|
||||
@ -45,6 +48,7 @@ const DBG_STRINGS_URI = "chrome://global/locale/devtools/debugger.properties";
|
||||
const nsFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath");
|
||||
Cu.import("resource://gre/modules/reflect.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
dumpn.wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/deprecated-sync-thenables.js");
|
||||
@ -81,8 +85,6 @@ XPCOMUtils.defineLazyGetter(this, "NetworkMonitorManager", () => {
|
||||
return require("devtools/toolkit/webconsole/network-monitor").NetworkMonitorManager;
|
||||
});
|
||||
|
||||
loadSubScript.call(this, "resource://gre/modules/devtools/server/transport.js");
|
||||
|
||||
// XPCOM constructors
|
||||
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
@ -359,7 +361,7 @@ var DebuggerServer = {
|
||||
// In case of apps being loaded in parent process, DebuggerServer is already
|
||||
// initialized and browser actors are already loaded,
|
||||
// but childtab.js hasn't been loaded yet.
|
||||
if (!("WebConsoleActor" in this)) {
|
||||
if (!DebuggerServer.tabActorFactories.hasOwnProperty("consoleActor")) {
|
||||
this.addTabActors();
|
||||
}
|
||||
// But webbrowser.js and childtab.js aren't loaded from shell.js.
|
||||
@ -376,7 +378,7 @@ var DebuggerServer = {
|
||||
*/
|
||||
addTabActors: function() {
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/script.js");
|
||||
this.addActors("resource://gre/modules/devtools/server/actors/webconsole.js");
|
||||
this.registerModule("devtools/server/actors/webconsole");
|
||||
this.registerModule("devtools/server/actors/inspector");
|
||||
this.registerModule("devtools/server/actors/call-watcher");
|
||||
this.registerModule("devtools/server/actors/canvas");
|
||||
@ -822,98 +824,10 @@ if (this.exports) {
|
||||
// Needed on B2G (See header note)
|
||||
this.DebuggerServer = DebuggerServer;
|
||||
|
||||
/**
|
||||
* Construct an ActorPool.
|
||||
*
|
||||
* ActorPools are actorID -> actor mapping and storage. These are
|
||||
* used to accumulate and quickly dispose of groups of actors that
|
||||
* share a lifetime.
|
||||
*/
|
||||
function ActorPool(aConnection)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this._cleanups = {};
|
||||
this._actors = {};
|
||||
}
|
||||
|
||||
// Export ActorPool for requirers of main.js
|
||||
if (this.exports) {
|
||||
exports.ActorPool = ActorPool;
|
||||
}
|
||||
// Needed on B2G (See header note)
|
||||
this.ActorPool = ActorPool;
|
||||
|
||||
ActorPool.prototype = {
|
||||
/**
|
||||
* Add an actor to the actor pool. If the actor doesn't have an ID,
|
||||
* allocate one from the connection.
|
||||
*
|
||||
* @param aActor object
|
||||
* The actor implementation. If the object has a
|
||||
* 'disconnect' property, it will be called when the actor
|
||||
* pool is cleaned up.
|
||||
*/
|
||||
addActor: function AP_addActor(aActor) {
|
||||
aActor.conn = this.conn;
|
||||
if (!aActor.actorID) {
|
||||
let prefix = aActor.actorPrefix;
|
||||
if (typeof aActor == "function") {
|
||||
// typeName is a convention used with protocol.js-based actors
|
||||
prefix = aActor.prototype.actorPrefix || aActor.prototype.typeName;
|
||||
}
|
||||
aActor.actorID = this.conn.allocID(prefix || undefined);
|
||||
}
|
||||
|
||||
if (aActor.registeredPool) {
|
||||
aActor.registeredPool.removeActor(aActor);
|
||||
}
|
||||
aActor.registeredPool = this;
|
||||
|
||||
this._actors[aActor.actorID] = aActor;
|
||||
if (aActor.disconnect) {
|
||||
this._cleanups[aActor.actorID] = aActor;
|
||||
}
|
||||
},
|
||||
|
||||
get: function AP_get(aActorID) {
|
||||
return this._actors[aActorID];
|
||||
},
|
||||
|
||||
has: function AP_has(aActorID) {
|
||||
return aActorID in this._actors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the pool is empty.
|
||||
*/
|
||||
isEmpty: function AP_isEmpty() {
|
||||
return Object.keys(this._actors).length == 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an actor from the actor pool.
|
||||
*/
|
||||
removeActor: function AP_remove(aActor) {
|
||||
delete this._actors[aActor.actorID];
|
||||
delete this._cleanups[aActor.actorID];
|
||||
},
|
||||
|
||||
/**
|
||||
* Match the api expected by the protocol library.
|
||||
*/
|
||||
unmanage: function(aActor) {
|
||||
return this.removeActor(aActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Run all actor cleanups.
|
||||
*/
|
||||
cleanup: function AP_cleanup() {
|
||||
for each (let actor in this._cleanups) {
|
||||
actor.disconnect();
|
||||
}
|
||||
this._cleanups = {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DebuggerServerConnection.
|
||||
|
@ -8,8 +8,9 @@ const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js");
|
||||
const Services = devtools.require("Services");
|
||||
const { ActorPool, createExtraActors, appendExtraActors } = devtools.require("devtools/server/actors/common");
|
||||
const DevToolsUtils = devtools.require("devtools/toolkit/DevToolsUtils.js");
|
||||
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
|
||||
// Always log packets when running tests. runxpcshelltests.py will throw
|
||||
|
@ -107,8 +107,8 @@ TestTabActor.prototype = {
|
||||
},
|
||||
|
||||
/* Support for DebuggerServer.addTabActor. */
|
||||
_createExtraActors: CommonCreateExtraActors,
|
||||
_appendExtraActors: CommonAppendExtraActors
|
||||
_createExtraActors: createExtraActors,
|
||||
_appendExtraActors: appendExtraActors
|
||||
};
|
||||
|
||||
TestTabActor.prototype.requestTypes = {
|
||||
|
@ -4,10 +4,30 @@
|
||||
* 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";
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
// TODO: Get rid of this code once the marionette server loads transport.js as
|
||||
// an SDK module (see bug 1000814)
|
||||
(function (factory) { // Module boilerplate
|
||||
if (this.module && module.id.indexOf("transport") >= 0) { // require
|
||||
factory(require, exports);
|
||||
} else { // loadSubScript
|
||||
if (this.require) {
|
||||
factory(require, this);
|
||||
} else {
|
||||
const Cu = Components.utils;
|
||||
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
factory(devtools.require, this);
|
||||
}
|
||||
}
|
||||
}).call(this, function (require, exports) {
|
||||
|
||||
let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
||||
"use strict";
|
||||
|
||||
const { Cc, Ci, Cr, Cu } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
const { dumpn } = DevToolsUtils;
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
/**
|
||||
* An adapter that handles data transfers between the debugger client and
|
||||
@ -43,7 +63,7 @@ let wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
|
||||
* ([length]:[packet]). The contents of the JSON packet are specified in
|
||||
* the Remote Debugging Protocol specification.
|
||||
*/
|
||||
this.DebuggerTransport = function DebuggerTransport(aInput, aOutput)
|
||||
function DebuggerTransport(aInput, aOutput)
|
||||
{
|
||||
this._input = aInput;
|
||||
this._output = aOutput;
|
||||
@ -98,7 +118,7 @@ DebuggerTransport.prototype = {
|
||||
let written = 0;
|
||||
try {
|
||||
written = aStream.write(this._outgoing, this._outgoing.length);
|
||||
} catch(e if e.result == Components.results.NS_BASE_STREAM_CLOSED) {
|
||||
} catch(e if e.result == Cr.NS_BASE_STREAM_CLOSED) {
|
||||
dumpn("Connection closed.");
|
||||
this.close();
|
||||
return;
|
||||
@ -190,7 +210,7 @@ DebuggerTransport.prototype = {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wantLogging) {
|
||||
if (dumpn.wantLogging) {
|
||||
dumpn("Got: " + JSON.stringify(parsed, null, 2));
|
||||
}
|
||||
let self = this;
|
||||
@ -206,6 +226,7 @@ DebuggerTransport.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
exports.DebuggerTransport = DebuggerTransport;
|
||||
|
||||
/**
|
||||
* An adapter that handles data transfers between the debugger client and
|
||||
@ -218,7 +239,7 @@ DebuggerTransport.prototype = {
|
||||
*
|
||||
* @see DebuggerTransport
|
||||
*/
|
||||
this.LocalDebuggerTransport = function LocalDebuggerTransport(aOther)
|
||||
function LocalDebuggerTransport(aOther)
|
||||
{
|
||||
this.other = aOther;
|
||||
this.hooks = null;
|
||||
@ -238,7 +259,7 @@ LocalDebuggerTransport.prototype = {
|
||||
*/
|
||||
send: function LDT_send(aPacket) {
|
||||
let serial = this._serial.count++;
|
||||
if (wantLogging) {
|
||||
if (dumpn.wantLogging) {
|
||||
/* Check 'from' first, as 'echo' packets have both. */
|
||||
if (aPacket.from) {
|
||||
dumpn("Packet " + serial + " sent from " + uneval(aPacket.from));
|
||||
@ -251,7 +272,7 @@ LocalDebuggerTransport.prototype = {
|
||||
if (other) {
|
||||
Services.tm.currentThread.dispatch(DevToolsUtils.makeInfallible(function() {
|
||||
// Avoid the cost of JSON.stringify() when logging is disabled.
|
||||
if (wantLogging) {
|
||||
if (dumpn.wantLogging) {
|
||||
dumpn("Received packet " + serial + ": " + JSON.stringify(aPacket, null, 2));
|
||||
}
|
||||
if (other.hooks) {
|
||||
@ -276,7 +297,7 @@ LocalDebuggerTransport.prototype = {
|
||||
try {
|
||||
this.hooks.onClosed();
|
||||
} catch(ex) {
|
||||
Components.utils.reportError(ex);
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
this.hooks = null;
|
||||
}
|
||||
@ -305,6 +326,8 @@ LocalDebuggerTransport.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
exports.LocalDebuggerTransport = LocalDebuggerTransport;
|
||||
|
||||
/**
|
||||
* A transport for the debugging protocol that uses nsIMessageSenders to
|
||||
* exchange packets with servers running in child processes.
|
||||
@ -320,7 +343,7 @@ LocalDebuggerTransport.prototype = {
|
||||
* <prefix> is |aPrefix|, whose data is the protocol packet.
|
||||
*/
|
||||
function ChildDebuggerTransport(aSender, aPrefix) {
|
||||
this._sender = aSender.QueryInterface(Components.interfaces.nsIMessageSender);
|
||||
this._sender = aSender.QueryInterface(Ci.nsIMessageSender);
|
||||
this._messageName = "debug:" + aPrefix + ":packet";
|
||||
}
|
||||
|
||||
@ -351,3 +374,7 @@ ChildDebuggerTransport.prototype = {
|
||||
this._sender.sendAsyncMessage(this._messageName, packet);
|
||||
}
|
||||
};
|
||||
|
||||
exports.ChildDebuggerTransport = ChildDebuggerTransport;
|
||||
|
||||
});
|
||||
|
@ -183,7 +183,7 @@ CommonNativeApp.prototype = {
|
||||
// because the app isn't installed yet).
|
||||
if (this.iconURI.scheme == "app") {
|
||||
let zipUrl = OS.Path.toFileURI(OS.Path.join(aTmpDir,
|
||||
"application.zip"));
|
||||
this.zipFile));
|
||||
|
||||
let filePath = this.iconURI.QueryInterface(Ci.nsIURL).filePath;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user