Commit a4fcc372 authored by mark.lam@apple.com's avatar mark.lam@apple.com

Split openDatabase() between front and back end work.

https://bugs.webkit.org/show_bug.cgi?id=107475.

Reviewed by Anders Carlsson.

The main work of splitting DatabaseManager::openDatabase() is in
refactoring how DatabaseTracker::canEstablishDatabase() works. It used
to check for adequate space quota, and if the check fails, it would call
back into the client from inside canEstablishDatabase(). The call back
allows the client to update the quota (if appropriate). Thereafter,
canEstablishDatabase() will retry its quota check.

In a webkit2 world, we'll want to minimize the traffic between the
client (script side) and the server (sqlite db side), and ideally, we
don't want the server to call back to the client. Note: the
DatabaseTracker belongs on the server side.

To achieve this, we split canEstablishDatabase() into 2 parts: the
checks before the call back to the client, and the checks after.
The first part will retain the name canEstablishDatabase(), and the
second part will be named retryCanEstablishDatabase().
We also added a DatabaseServer::openDatabase() function that can be
called with a retry flag.

The client side DatabaseManager::openDatabase() will call
DatabaseServer::openDatabase(), which then calls canEstablishDatabase()
to do its quota check. If there is enough quota,
DatabaseServer::openDatabase() will proceed to open the backend database
without return to the client first. The opened database will be returned
to the client.

If DatabaseServer::openDatabase() finds inadequate quota the first time,
it will return with a DatabaseSizeExceededQuota error. The DatabaseManager
(on the client side) will check for this error and call back to its client
for an opportunity to increase the quota. Thereafter, the DatabaseManager
will call DatabaseServer::openDatabase() again. This time,
DatabaseServer::openDatabase() will call retryCanEstablishDatabase() to
check the quota, and then open the backend database if there is enough
quota.

No new tests.

* Modules/webdatabase/AbstractDatabaseServer.h:
* Modules/webdatabase/DOMWindowWebDatabase.cpp:
(WebCore::DOMWindowWebDatabase::openDatabase):
* Modules/webdatabase/Database.cpp:
(WebCore::Database::create):
* Modules/webdatabase/Database.h:
(Database):
* Modules/webdatabase/DatabaseBackend.cpp:
(WebCore::DatabaseBackend::performOpenAndVerify):
* Modules/webdatabase/DatabaseBackend.h:
(DatabaseBackend):
* Modules/webdatabase/DatabaseBackendAsync.cpp:
(WebCore::DatabaseBackendAsync::openAndVerifyVersion):
(WebCore::DatabaseBackendAsync::performOpenAndVerify):
* Modules/webdatabase/DatabaseBackendAsync.h:
(DatabaseBackendAsync):
* Modules/webdatabase/DatabaseBackendSync.cpp:
(WebCore::DatabaseBackendSync::openAndVerifyVersion):
* Modules/webdatabase/DatabaseBackendSync.h:
(DatabaseBackendSync):
* Modules/webdatabase/DatabaseError.h:
(WebCore::ENUM_CLASS):
* Modules/webdatabase/DatabaseManager.cpp:
(WebCore::DatabaseManager::exceptionCodeForDatabaseError):
(WebCore::DatabaseManager::openDatabaseBackend):
(WebCore::DatabaseManager::openDatabase):
(WebCore::DatabaseManager::openDatabaseSync):
* Modules/webdatabase/DatabaseManager.h:
(DatabaseManager):
* Modules/webdatabase/DatabaseServer.cpp:
(WebCore::DatabaseServer::openDatabase):
(WebCore::DatabaseServer::createDatabase):
* Modules/webdatabase/DatabaseServer.h:
* Modules/webdatabase/DatabaseSync.cpp:
(WebCore::DatabaseSync::create):
* Modules/webdatabase/DatabaseSync.h:
(DatabaseSync):
* Modules/webdatabase/DatabaseTracker.cpp:
(WebCore::DatabaseTracker::hasAdequateQuotaForOrigin):
(WebCore::DatabaseTracker::canEstablishDatabase):
(WebCore::DatabaseTracker::retryCanEstablishDatabase):
* Modules/webdatabase/DatabaseTracker.h:
(DatabaseTracker):
* Modules/webdatabase/WorkerContextWebDatabase.cpp:
(WebCore::WorkerContextWebDatabase::openDatabase):
(WebCore::WorkerContextWebDatabase::openDatabaseSync):
* Modules/webdatabase/chromium/DatabaseTrackerChromium.cpp:
(WebCore::DatabaseTracker::canEstablishDatabase):
(WebCore::DatabaseTracker::retryCanEstablishDatabase):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@142030 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 43f42cf2
2013-02-06 Mark Lam <mark.lam@apple.com>
Split openDatabase() between front and back end work.
https://bugs.webkit.org/show_bug.cgi?id=107475.
Reviewed by Anders Carlsson.
The main work of splitting DatabaseManager::openDatabase() is in
refactoring how DatabaseTracker::canEstablishDatabase() works. It used
to check for adequate space quota, and if the check fails, it would call
back into the client from inside canEstablishDatabase(). The call back
allows the client to update the quota (if appropriate). Thereafter,
canEstablishDatabase() will retry its quota check.
In a webkit2 world, we'll want to minimize the traffic between the
client (script side) and the server (sqlite db side), and ideally, we
don't want the server to call back to the client. Note: the
DatabaseTracker belongs on the server side.
To achieve this, we split canEstablishDatabase() into 2 parts: the
checks before the call back to the client, and the checks after.
The first part will retain the name canEstablishDatabase(), and the
second part will be named retryCanEstablishDatabase().
We also added a DatabaseServer::openDatabase() function that can be
called with a retry flag.
The client side DatabaseManager::openDatabase() will call
DatabaseServer::openDatabase(), which then calls canEstablishDatabase()
to do its quota check. If there is enough quota,
DatabaseServer::openDatabase() will proceed to open the backend database
without return to the client first. The opened database will be returned
to the client.
If DatabaseServer::openDatabase() finds inadequate quota the first time,
it will return with a DatabaseSizeExceededQuota error. The DatabaseManager
(on the client side) will check for this error and call back to its client
for an opportunity to increase the quota. Thereafter, the DatabaseManager
will call DatabaseServer::openDatabase() again. This time,
DatabaseServer::openDatabase() will call retryCanEstablishDatabase() to
check the quota, and then open the backend database if there is enough
quota.
No new tests.
* Modules/webdatabase/AbstractDatabaseServer.h:
* Modules/webdatabase/DOMWindowWebDatabase.cpp:
(WebCore::DOMWindowWebDatabase::openDatabase):
* Modules/webdatabase/Database.cpp:
(WebCore::Database::create):
* Modules/webdatabase/Database.h:
(Database):
* Modules/webdatabase/DatabaseBackend.cpp:
(WebCore::DatabaseBackend::performOpenAndVerify):
* Modules/webdatabase/DatabaseBackend.h:
(DatabaseBackend):
* Modules/webdatabase/DatabaseBackendAsync.cpp:
(WebCore::DatabaseBackendAsync::openAndVerifyVersion):
(WebCore::DatabaseBackendAsync::performOpenAndVerify):
* Modules/webdatabase/DatabaseBackendAsync.h:
(DatabaseBackendAsync):
* Modules/webdatabase/DatabaseBackendSync.cpp:
(WebCore::DatabaseBackendSync::openAndVerifyVersion):
* Modules/webdatabase/DatabaseBackendSync.h:
(DatabaseBackendSync):
* Modules/webdatabase/DatabaseError.h:
(WebCore::ENUM_CLASS):
* Modules/webdatabase/DatabaseManager.cpp:
(WebCore::DatabaseManager::exceptionCodeForDatabaseError):
(WebCore::DatabaseManager::openDatabaseBackend):
(WebCore::DatabaseManager::openDatabase):
(WebCore::DatabaseManager::openDatabaseSync):
* Modules/webdatabase/DatabaseManager.h:
(DatabaseManager):
* Modules/webdatabase/DatabaseServer.cpp:
(WebCore::DatabaseServer::openDatabase):
(WebCore::DatabaseServer::createDatabase):
* Modules/webdatabase/DatabaseServer.h:
* Modules/webdatabase/DatabaseSync.cpp:
(WebCore::DatabaseSync::create):
* Modules/webdatabase/DatabaseSync.h:
(DatabaseSync):
* Modules/webdatabase/DatabaseTracker.cpp:
(WebCore::DatabaseTracker::hasAdequateQuotaForOrigin):
(WebCore::DatabaseTracker::canEstablishDatabase):
(WebCore::DatabaseTracker::retryCanEstablishDatabase):
* Modules/webdatabase/DatabaseTracker.h:
(DatabaseTracker):
* Modules/webdatabase/WorkerContextWebDatabase.cpp:
(WebCore::WorkerContextWebDatabase::openDatabase):
(WebCore::WorkerContextWebDatabase::openDatabaseSync):
* Modules/webdatabase/chromium/DatabaseTrackerChromium.cpp:
(WebCore::DatabaseTracker::canEstablishDatabase):
(WebCore::DatabaseTracker::retryCanEstablishDatabase):
2013-02-06 Tony Gentilcore <tonyg@chromium.org>
Fix CompactHTMLToken's copy ctor to copy all fields
......@@ -28,7 +28,9 @@
#if ENABLE(SQL_DATABASE)
#include "DatabaseBasicTypes.h"
#include "DatabaseDetails.h"
#include "DatabaseError.h"
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>
......@@ -36,9 +38,7 @@
namespace WebCore {
class DatabaseBackend;
class DatabaseBackendAsync;
class DatabaseBackendContext;
class DatabaseBackendSync;
class DatabaseManagerClient;
class SecurityOrigin;
......@@ -52,6 +52,13 @@ public:
virtual String fullPathForDatabase(SecurityOrigin*, const String& name, bool createIfDoesNotExist = true) = 0;
enum OpenAttempt {
FirstTryToOpenDatabase,
RetryOpenDatabase
};
virtual PassRefPtr<DatabaseBackend> openDatabase(RefPtr<DatabaseBackendContext>&, DatabaseType, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, bool setVersionInNewDatabase, DatabaseError&, String& errorMessage, OpenAttempt = FirstTryToOpenDatabase) = 0;
#if !PLATFORM(CHROMIUM)
virtual bool hasEntryForOrigin(SecurityOrigin*) = 0;
virtual void origins(Vector<RefPtr<SecurityOrigin> >& result) = 0;
......@@ -77,9 +84,6 @@ public:
virtual void interruptAllDatabasesForContext(const DatabaseBackendContext*) = 0;
virtual bool canEstablishDatabase(DatabaseBackendContext*, const String& name, const String& displayName, unsigned long estimatedSize) = 0;
virtual void setDatabaseDetails(SecurityOrigin*, const String& name, const String& displayName, unsigned long estimatedSize) = 0;
virtual unsigned long long getMaxSizeForDatabase(const DatabaseBackend*) = 0;
protected:
......
......@@ -48,13 +48,11 @@ PassRefPtr<Database> DOMWindowWebDatabase::openDatabase(DOMWindow* window, const
RefPtr<Database> database = 0;
DatabaseManager& dbManager = DatabaseManager::manager();
DatabaseError error = DatabaseError::None;
if (dbManager.isAvailable() && window->document()->securityOrigin()->canAccessDatabase(window->document()->topOrigin()))
if (dbManager.isAvailable() && window->document()->securityOrigin()->canAccessDatabase(window->document()->topOrigin())) {
database = dbManager.openDatabase(window->document(), name, version, displayName, estimatedSize, creationCallback, error);
ASSERT(error == DatabaseError::None || error == DatabaseError::CannotOpenDatabase);
if (error == DatabaseError::CannotOpenDatabase)
ec = INVALID_STATE_ERR;
if (!database && !ec)
ASSERT(database || error != DatabaseError::None);
ec = DatabaseManager::exceptionCodeForDatabaseError(error);
} else
ec = SECURITY_ERR;
return database;
......
......@@ -66,6 +66,11 @@
namespace WebCore {
PassRefPtr<Database> Database::create(ScriptExecutionContext*, PassRefPtr<DatabaseBackend> backend)
{
return static_cast<Database*>(backend.get());
}
Database::Database(PassRefPtr<DatabaseBackendContext> databaseContext,
const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
: DatabaseBase(databaseContext->scriptExecutionContext())
......@@ -133,23 +138,6 @@ String Database::version() const
return DatabaseBackend::version();
}
bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
DatabaseTaskSynchronizer synchronizer;
if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
return false;
#if PLATFORM(CHROMIUM)
DatabaseTracker::tracker().prepareToOpenDatabase(this);
#endif
bool success = false;
OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
databaseContext()->databaseThread()->scheduleImmediateTask(task.release());
synchronizer.waitForTaskCompletion();
return success;
}
void Database::markAsDeletedAndClose()
{
if (m_deleted || !databaseContext()->databaseThread())
......@@ -204,18 +192,6 @@ unsigned long long Database::maximumSize() const
return DatabaseManager::manager().getMaxSizeForDatabase(this);
}
bool Database::performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
if (DatabaseBackend::performOpenAndVerify(setVersionInNewDatabase, error, errorMessage)) {
if (databaseContext()->databaseThread())
databaseContext()->databaseThread()->recordDatabaseOpen(this);
return true;
}
return false;
}
void Database::changeVersion(const String& oldVersion, const String& newVersion,
PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
PassRefPtr<VoidCallback> successCallback)
......
......@@ -88,13 +88,11 @@ private:
Database(PassRefPtr<DatabaseBackendContext>, const String& name,
const String& expectedVersion, const String& displayName, unsigned long estimatedSize);
PassRefPtr<DatabaseBackendAsync> backend();
static PassRefPtr<Database> create(ScriptExecutionContext*, PassRefPtr<DatabaseBackend>);
void runTransaction(PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper>, bool readOnly);
bool openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError&, String& errorMessage);
virtual bool performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError&, String& errorMessage);
void inProgressTransactionCompleted();
void scheduleTransaction();
......@@ -110,6 +108,7 @@ private:
bool m_deleted;
friend class DatabaseManager;
friend class DatabaseServer; // FIXME: remove this when the backend has been split out.
friend class DatabaseBackendAsync; // FIXME: remove this when the backend has been split out.
};
......
......@@ -314,7 +314,7 @@ bool DatabaseBackend::performOpenAndVerify(bool shouldSetVersionInNewDatabase, D
DoneCreatingDatabaseOnExitCaller onExitCaller(this);
ASSERT(errorMessage.isEmpty());
ASSERT(error == DatabaseError::None); // Better not have any errors already.
error = DatabaseError::CannotOpenDatabase; // Presumed failure. We'll clear it if we succeed below.
error = DatabaseError::InvalidDatabaseState; // Presumed failure. We'll clear it if we succeed below.
const int maxSqliteBusyWaitTime = 30000;
......
......@@ -103,6 +103,7 @@ protected:
void closeDatabase();
virtual bool openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError&, String& errorMessage) = 0;
virtual bool performOpenAndVerify(bool shouldSetVersionInNewDatabase, DatabaseError&, String& errorMessage);
bool getVersionFromDatabase(String& version, bool shouldCacheVersion = true);
......
......@@ -29,6 +29,9 @@
#if ENABLE(SQL_DATABASE)
#include "DatabaseBackendContext.h"
#include "DatabaseTask.h"
#include "DatabaseThread.h"
#include "DatabaseTracker.h"
namespace WebCore {
......@@ -37,6 +40,34 @@ DatabaseBackendAsync::DatabaseBackendAsync(PassRefPtr<DatabaseBackendContext> da
{
}
bool DatabaseBackendAsync::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
DatabaseTaskSynchronizer synchronizer;
if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
return false;
#if PLATFORM(CHROMIUM)
DatabaseTracker::tracker().prepareToOpenDatabase(this);
#endif
bool success = false;
OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
databaseContext()->databaseThread()->scheduleImmediateTask(task.release());
synchronizer.waitForTaskCompletion();
return success;
}
bool DatabaseBackendAsync::performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
if (DatabaseBackend::performOpenAndVerify(setVersionInNewDatabase, error, errorMessage)) {
if (databaseContext()->databaseThread())
databaseContext()->databaseThread()->recordDatabaseOpen(this);
return true;
}
return false;
}
} // namespace WebCore
......
......@@ -43,11 +43,11 @@ class DatabaseServer;
// available. This should be replaced with the actual implementation later.
class DatabaseBackendAsync : public DatabaseBackend {
protected:
public:
DatabaseBackendAsync(PassRefPtr<DatabaseBackendContext>, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize);
friend class DatabaseManager; // FIXME: remove this once we have isolated this to the backend.
friend class DatabaseServer;
virtual bool openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError&, String& errorMessage);
virtual bool performOpenAndVerify(bool setVersionInNewDatabase, DatabaseError&, String& errorMessage);
private:
class DatabaseOpenTask;
......
......@@ -29,6 +29,7 @@
#if ENABLE(SQL_DATABASE)
#include "DatabaseBackendContext.h"
#include "DatabaseTracker.h"
namespace WebCore {
......@@ -51,6 +52,14 @@ DatabaseBackendSync::~DatabaseBackendSync()
closeDatabase();
}
bool DatabaseBackendSync::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
#if PLATFORM(CHROMIUM)
DatabaseTracker::tracker().prepareToOpenDatabase(this);
#endif
return performOpenAndVerify(setVersionInNewDatabase, error, errorMessage);
}
} // namespace WebCore
#endif // ENABLE(SQL_DATABASE)
......@@ -45,10 +45,11 @@ class DatabaseBackendSync : public DatabaseBackend {
public:
virtual ~DatabaseBackendSync();
virtual bool openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError&, String& errorMessage);
protected:
DatabaseBackendSync(PassRefPtr<DatabaseBackendContext>, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize);
friend class DatabaseManager; // FIXME: remove this once we have isolated this to the backend.
friend class DatabaseServer;
};
......
......@@ -34,10 +34,11 @@ namespace WebCore {
ENUM_CLASS(DatabaseError) {
None = 0,
CannotOpenDatabase,
DatabaseIsBeingDeleted,
DatabaseSizeExceededQuota,
DatabaseSizeOverflowed
DatabaseSizeOverflowed,
GenericSecurityError,
InvalidDatabaseState
} ENUM_CLASS_END(DatabaseError);
} // namespace WebCore
......
......@@ -28,6 +28,7 @@
#if ENABLE(SQL_DATABASE)
#include "AbstractDatabaseServer.h"
#include "Database.h"
#include "DatabaseBackend.h"
#include "DatabaseBackendAsync.h"
......@@ -200,39 +201,116 @@ void DatabaseManager::didDestructDatabaseContext()
}
#endif
ExceptionCode DatabaseManager::exceptionCodeForDatabaseError(DatabaseError error)
{
switch (error) {
case DatabaseError::None:
return 0;
case DatabaseError::DatabaseIsBeingDeleted:
case DatabaseError::DatabaseSizeExceededQuota:
case DatabaseError::DatabaseSizeOverflowed:
case DatabaseError::GenericSecurityError:
return SECURITY_ERR;
case DatabaseError::InvalidDatabaseState:
return INVALID_STATE_ERR;
}
ASSERT_NOT_REACHED();
return 0; // Make some older compilers happy.
}
static void logOpenDatabaseError(ScriptExecutionContext* context, const String& name)
{
LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(),
context->securityOrigin()->toString().ascii().data());
}
PassRefPtr<DatabaseBackend> DatabaseManager::openDatabaseBackend(ScriptExecutionContext* context,
DatabaseType type, const String& name, const String& expectedVersion, const String& displayName,
unsigned long estimatedSize, bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
{
ASSERT(error == DatabaseError::None);
RefPtr<DatabaseContext> databaseContext = databaseContextFor(context);
RefPtr<DatabaseBackendContext> backendContext = databaseContext->backend();
RefPtr<DatabaseBackend> backend = m_server->openDatabase(backendContext, type, name, expectedVersion,
displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage);
if (!backend) {
ASSERT(error != DatabaseError::None);
switch (error) {
case DatabaseError::DatabaseIsBeingDeleted:
case DatabaseError::DatabaseSizeOverflowed:
case DatabaseError::GenericSecurityError:
logOpenDatabaseError(context, name);
return 0;
case DatabaseError::InvalidDatabaseState:
logErrorMessage(context, errorMessage);
return 0;
case DatabaseError::DatabaseSizeExceededQuota:
// Notify the client that we've exceeded the database quota.
// The client may want to increase the quota, and we'll give it
// one more try after if that is the case.
databaseContext->databaseExceededQuota(name,
DatabaseDetails(name.isolatedCopy(), displayName.isolatedCopy(), estimatedSize, 0));
error = DatabaseError::None;
backend = m_server->openDatabase(backendContext, type, name, expectedVersion,
displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage,
AbstractDatabaseServer::RetryOpenDatabase);
break;
default:
ASSERT_NOT_REACHED();
}
if (!backend) {
ASSERT(error != DatabaseError::None);
if (error == DatabaseError::InvalidDatabaseState) {
logErrorMessage(context, errorMessage);
return 0;
}
logOpenDatabaseError(context, name);
return 0;
}
}
return backend.release();
}
PassRefPtr<Database> DatabaseManager::openDatabase(ScriptExecutionContext* context,
const String& name, const String& expectedVersion, const String& displayName,
unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback,
DatabaseError& error)
{
ScriptController::initializeThreading();
RefPtr<DatabaseContext> databaseContext = databaseContextFor(context);
RefPtr<DatabaseBackendContext> backendContext = databaseContext->backend();
ASSERT(error == DatabaseError::None);
if (!m_server->canEstablishDatabase(backendContext.get(), name, displayName, estimatedSize)) {
LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
return 0;
}
bool setVersionInNewDatabase = !creationCallback;
String errorMessage;
RefPtr<Database> database = adoptRef(new Database(backendContext, name, expectedVersion, displayName, estimatedSize));
if (!database->openAndVerifyVersion(!creationCallback, error, errorMessage)) {
logErrorMessage(context, errorMessage);
RefPtr<DatabaseBackend> backend = openDatabaseBackend(context, DatabaseType::Async, name,
expectedVersion, displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage);
if (!backend)
return 0;
}
m_server->setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
databaseContext->setHasOpenDatabases();
RefPtr<Database> database = Database::create(context, backend);
RefPtr<DatabaseContext> databaseContext = databaseContextFor(context);
databaseContext->setHasOpenDatabases();
InspectorInstrumentation::didOpenDatabase(context, database, context->securityOrigin()->host(), name, expectedVersion);
if (database->isNew() && creationCallback.get()) {
if (backend->isNew() && creationCallback.get()) {
LOG(StorageAPI, "Scheduling DatabaseCreationCallbackTask for database %p\n", database.get());
database->m_scriptExecutionContext->postTask(DatabaseCreationCallbackTask::create(database, creationCallback));
}
ASSERT(database);
return database.release();
}
......@@ -240,31 +318,24 @@ PassRefPtr<DatabaseSync> DatabaseManager::openDatabaseSync(ScriptExecutionContex
const String& name, const String& expectedVersion, const String& displayName,
unsigned long estimatedSize, PassRefPtr<DatabaseCallback> creationCallback, DatabaseError& error)
{
RefPtr<DatabaseContext> databaseContext = databaseContextFor(context);
RefPtr<DatabaseBackendContext> backendContext = databaseContext->backend();
ASSERT(context->isContextThread());
ASSERT(error == DatabaseError::None);
if (!m_server->canEstablishDatabase(backendContext.get(), name, displayName, estimatedSize)) {
LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), context->securityOrigin()->toString().ascii().data());
return 0;
}
bool setVersionInNewDatabase = !creationCallback;
String errorMessage;
RefPtr<DatabaseSync> database = adoptRef(new DatabaseSync(backendContext, name, expectedVersion, displayName, estimatedSize));
if (!database->openAndVerifyVersion(!creationCallback, error, errorMessage)) {
logErrorMessage(context, errorMessage);
RefPtr<DatabaseBackend> backend = openDatabaseBackend(context, DatabaseType::Sync, name,
expectedVersion, displayName, estimatedSize, setVersionInNewDatabase, error, errorMessage);
if (!backend)
return 0;
}
m_server->setDatabaseDetails(context->securityOrigin(), name, displayName, estimatedSize);
RefPtr<DatabaseSync> database = DatabaseSync::create(context, backend);
if (database->isNew() && creationCallback.get()) {
if (backend->isNew() && creationCallback.get()) {
LOG(StorageAPI, "Invoking the creation callback for database %p\n", database.get());
creationCallback->handleEvent(database.get());
}
ASSERT(database);
return database.release();
}
......
......@@ -28,7 +28,6 @@
#if ENABLE(SQL_DATABASE)
#include "AbstractDatabaseServer.h"
#include "DatabaseBasicTypes.h"
#include "DatabaseDetails.h"
#include "DatabaseError.h"
......@@ -80,6 +79,8 @@ public:
void didDestructDatabaseContext() { }
#endif
static ExceptionCode exceptionCodeForDatabaseError(DatabaseError);
PassRefPtr<Database> openDatabase(ScriptExecutionContext*, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, DatabaseError&);
PassRefPtr<DatabaseSync> openDatabaseSync(ScriptExecutionContext*, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, PassRefPtr<DatabaseCallback>, DatabaseError&);
......@@ -124,6 +125,10 @@ private:
// it already exist previously. Otherwise, it returns 0.
PassRefPtr<DatabaseContext> existingDatabaseContextFor(ScriptExecutionContext*);
PassRefPtr<DatabaseBackend> openDatabaseBackend(ScriptExecutionContext*,
DatabaseType, const String& name, const String& expectedVersion, const String& displayName,
unsigned long estimatedSize, bool setVersionInNewDatabase, DatabaseError&, String& errorMessage);
static void logErrorMessage(ScriptExecutionContext*, const String& message);
AbstractDatabaseServer* m_server;
......
......@@ -28,9 +28,11 @@
#if ENABLE(SQL_DATABASE)
#include "Database.h"
#include "DatabaseBackendAsync.h"
#include "DatabaseBackendContext.h"
#include "DatabaseBackendSync.h"
#include "DatabaseSync.h"
#include "DatabaseTracker.h"
#include <wtf/UnusedParam.h>
......@@ -149,14 +151,45 @@ void DatabaseServer::interruptAllDatabasesForContext(const DatabaseBackendContex
DatabaseTracker::tracker().interruptAllDatabasesForContext(context);
}
bool DatabaseServer::canEstablishDatabase(DatabaseBackendContext* backendContext, const String& name, const String& displayName, unsigned long estimatedSize)
{
return DatabaseTracker::tracker().canEstablishDatabase(backendContext, name, displayName, estimatedSize);
}
void DatabaseServer::setDatabaseDetails(SecurityOrigin* origin, const String& name, const String& displayName, unsigned long estimatedSize)
{
DatabaseTracker::tracker().setDatabaseDetails(origin, name, displayName, estimatedSize);
PassRefPtr<DatabaseBackend> DatabaseServer::openDatabase(RefPtr<DatabaseBackendContext>& backendContext,
DatabaseType type, const String& name, const String& expectedVersion, const String& displayName,
unsigned long estimatedSize, bool setVersionInNewDatabase, DatabaseError &error, String& errorMessage,
OpenAttempt attempt)
{
RefPtr<DatabaseBackend> database;
bool success = false; // Make some older compilers happy.
switch (attempt) {
case FirstTryToOpenDatabase:
success = DatabaseTracker::tracker().canEstablishDatabase(backendContext.get(), name, displayName, estimatedS