Bug 1031407 - DataStoreService doesn't need to use IDBCursor to know if a revision exists., r=janv

This commit is contained in:
Andrea Marchesini 2014-08-03 15:48:19 +01:00
parent 2225187162
commit a5d394f802
4 changed files with 59 additions and 84 deletions

View File

@ -20,7 +20,13 @@ public:
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
virtual void Run(DataStoreDB* aDb, bool aSuccess) = 0;
enum RunStatus {
Success,
CreatedSchema,
Error
};
virtual void Run(DataStoreDB* aDb, RunStatus aStatus) = 0;
protected:
virtual ~DataStoreDBCallback()

View File

@ -78,6 +78,7 @@ NS_IMPL_ISUPPORTS(DataStoreDB, nsIDOMEventListener)
DataStoreDB::DataStoreDB(const nsAString& aManifestURL, const nsAString& aName)
: mState(Inactive)
, mCreatedSchema(false)
{
mDatabaseName.Assign(aName);
mDatabaseName.Append('|');
@ -145,9 +146,11 @@ DataStoreDB::HandleEvent(nsIDOMEvent* aEvent)
rv = DatabaseOpened();
if (NS_WARN_IF(NS_FAILED(rv))) {
mCallback->Run(this, false);
mCallback->Run(this, DataStoreDBCallback::Error);
} else {
mCallback->Run(this, true);
mCallback->Run(this, mCreatedSchema
? DataStoreDBCallback::CreatedSchema :
DataStoreDBCallback::Success);
}
mRequest = nullptr;
@ -155,13 +158,13 @@ DataStoreDB::HandleEvent(nsIDOMEvent* aEvent)
}
if (type.EqualsASCII("upgradeneeded")) {
return UpgradeSchema();
return UpgradeSchema(aEvent);
}
if (type.EqualsASCII("error") || type.EqualsASCII("blocked")) {
RemoveEventListeners();
mState = Inactive;
mCallback->Run(this, false);
mCallback->Run(this, DataStoreDBCallback::Error);
mRequest = nullptr;
return NS_OK;
}
@ -170,10 +173,23 @@ DataStoreDB::HandleEvent(nsIDOMEvent* aEvent)
}
nsresult
DataStoreDB::UpgradeSchema()
DataStoreDB::UpgradeSchema(nsIDOMEvent* aEvent)
{
MOZ_ASSERT(NS_IsMainThread());
// This DB has been just created and we have to inform the callback about
// this.
mCreatedSchema = true;
#ifdef DEBUG
nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
MOZ_ASSERT(event);
Nullable<uint64_t> version = event->GetNewVersion();
MOZ_ASSERT(!version.IsNull());
MOZ_ASSERT(version.Value() == DATASTOREDB_VERSION);
#endif
AutoSafeJSContext cx;
ErrorResult error;

View File

@ -50,7 +50,7 @@ private:
nsresult CreateFactoryIfNeeded();
nsresult UpgradeSchema();
nsresult UpgradeSchema(nsIDOMEvent* aEvent);
nsresult DatabaseOpened();
@ -75,6 +75,7 @@ private:
IDBTransactionMode mTransactionMode;
Sequence<nsString> mObjectStores;
bool mCreatedSchema;
};
} // namespace dom

View File

@ -518,12 +518,11 @@ private:
};
// This DataStoreDBCallback is called when DataStoreDB opens the DataStore DB.
// Then the first revision will be created if it doesn't exist yet.
// Then the first revision will be created if it's needed.
class FirstRevisionIdCallback MOZ_FINAL : public DataStoreDBCallback
, public nsIDOMEventListener
{
public:
NS_DECL_ISUPPORTS
NS_INLINE_DECL_REFCOUNTING(FirstRevisionIdCallback)
FirstRevisionIdCallback(uint32_t aAppId, const nsAString& aName,
const nsAString& aManifestURL)
@ -536,113 +535,66 @@ public:
}
void
Run(DataStoreDB* aDb, bool aSuccess)
Run(DataStoreDB* aDb, RunStatus aStatus)
{
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aDb);
if (!aSuccess) {
if (aStatus == Error) {
NS_WARNING("Failed to create the first revision.");
return;
}
mTxn = aDb->Transaction();
ErrorResult rv;
nsRefPtr<IDBObjectStore> store =
mTxn->ObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION), rv);
if (NS_WARN_IF(rv.Failed())) {
return;
}
// a Null JSContext is ok because OpenCursor ignores it if the range is
// undefined.
mRequest = store->OpenCursor(nullptr, JS::UndefinedHandleValue,
IDBCursorDirection::Prev, rv);
if (NS_WARN_IF(rv.Failed())) {
return;
}
nsresult res;
res = mRequest->EventTarget::AddEventListener(NS_LITERAL_STRING("success"),
this, false);
if (NS_WARN_IF(NS_FAILED(res))) {
return;
}
}
// nsIDOMEventListener
NS_IMETHOD
HandleEvent(nsIDOMEvent* aEvent)
{
AssertIsInMainProcess();
MOZ_ASSERT(NS_IsMainThread());
nsString type;
nsresult rv = aEvent->GetType(type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!type.EqualsASCII("success")) {
return NS_ERROR_FAILURE;
}
mRequest->RemoveEventListener(NS_LITERAL_STRING("success"), this, false);
// Note: this cx is only used for rooting and AddRevision, neither of which
// actually care which compartment we're in.
AutoSafeJSContext cx;
ErrorResult error;
JS::Rooted<JS::Value> result(cx);
mRequest->GetResult(cx, &result, error);
if (NS_WARN_IF(error.Failed())) {
return error.ErrorCode();
}
// This means that the content is a IDBCursor, so the first revision already
// exists.
if (result.isObject()) {
if (aStatus == Success) {
nsRefPtr<DataStoreService> service = DataStoreService::Get();
MOZ_ASSERT(service);
return service->EnableDataStore(mAppId, mName, mManifestURL);
nsresult rv = service->EnableDataStore(mAppId, mName, mManifestURL);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to enable a DataStore.");
}
return;
}
MOZ_ASSERT(mTxn);
// The DB has just been created.
ErrorResult error;
nsRefPtr<IDBObjectStore> store =
mTxn->ObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION), error);
if (NS_WARN_IF(error.Failed())) {
return error.ErrorCode();
aDb->Transaction()->ObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION),
error);
if (error.Failed()) {
NS_WARNING("Failed to get an ObjectStore object.");
return;
}
MOZ_ASSERT(store);
nsRefPtr<RevisionAddedEnableStoreCallback> callback =
new RevisionAddedEnableStoreCallback(mAppId, mName, mManifestURL);
// Note: this cx is only used for rooting and AddRevision, neither of which
// actually care which compartment we're in.
AutoSafeJSContext cx;
// If the revision doesn't exist, let's create it.
nsRefPtr<DataStoreRevision> revision = new DataStoreRevision();
return revision->AddRevision(cx, store, 0, DataStoreRevision::RevisionVoid,
callback);
nsresult rv = revision->AddRevision(cx, store, 0,
DataStoreRevision::RevisionVoid,
callback);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to add a revision to a DataStore.");
}
}
private:
~FirstRevisionIdCallback() {}
nsRefPtr<IDBRequest> mRequest;
nsRefPtr<IDBTransaction> mTxn;
nsRefPtr<DataStoreRevision> mRevision;
uint32_t mAppId;
nsString mName;
nsString mManifestURL;
};
NS_IMPL_ISUPPORTS(FirstRevisionIdCallback, nsIDOMEventListener)
// This class calls the 'retrieveRevisionId' method of the DataStore object for
// any DataStore in the 'mResults' array. When all of them are called, the
// promise is resolved with 'mResults'.