Closed
Bug 697247
Opened 14 years ago
Closed 14 years ago
IndexedDB: Database opening needs to block other database openings from proceeding
Categories
(Core :: Storage: IndexedDB, defect)
Core
Storage: IndexedDB
Tracking
()
RESOLVED
FIXED
People
(Reporter: khuey, Assigned: khuey)
References
Details
Attachments
(2 files, 1 obsolete file)
16.66 KB,
patch
|
bent.mozilla
:
review+
|
Details | Diff | Splinter Review |
61.70 KB,
patch
|
bent.mozilla
:
review+
|
Details | Diff | Splinter Review |
Right now:
mozIndexedDB.open("foo", 1);
mozIndexedDB.open("foo", 1);
The second opening will start proceeding and when the first opening realizes it needs to do a VERSION_CHANGE transaction things will fall down.
Assignee | ||
Comment 1•14 years ago
|
||
Attachment #569485 -
Flags: review?(bent.mozilla)
Assignee | ||
Comment 2•14 years ago
|
||
Rip out SetVersionRunnable, and maintain a list of OpenDatabaseHelpers instead. We move the delayed runnables/waiting for databases to close stuff to OpenDatabaseHelper. Then we fix everything up and add some tests.
Attachment #569487 -
Flags: review?(bent.mozilla)
Comment on attachment 569485 [details] [diff] [review]
Part 1: Use atoms instead of IDs
Review of attachment 569485 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/indexedDB/OpenDatabaseHelper.cpp
@@ +526,5 @@
> nsresult
> +OpenDatabaseHelper::Init()
> +{
> + nsCString str;
> + str.Append(mASCIIOrigin);
Nit: Pass mASCIIOrigin as the constructor arg.
Attachment #569485 -
Flags: review?(bent.mozilla) → review+
Comment on attachment 569487 [details] [diff] [review]
Part 2: Everything else
Review of attachment 569487 [details] [diff] [review]:
-----------------------------------------------------------------
::: dom/indexedDB/CheckPermissionsHelper.h
@@ +63,5 @@
> NS_DECL_NSIOBSERVER
>
> CheckPermissionsHelper(OpenDatabaseHelper* aHelper,
> nsIDOMWindow* aWindow,
> + nsIAtom* aId,
Hm. Why do you need this here? Looks like you can get rid of it.
::: dom/indexedDB/IndexedDatabaseManager.cpp
@@ +462,3 @@
> "Delayed runnables should have been dispatched already!");
>
> + // Remove this helper from the list. This will allow openings to proceed.
Nit: "allow *other* openings to proceed"
@@ +467,5 @@
> }
> }
>
> nsresult
> +IndexedDatabaseManager::WaitForOpenAllowed(nsIAtom* aId,
Hm, I don't especially like the changes here. We can chat on irc about it a bit maybe.
::: dom/indexedDB/IndexedDatabaseManager.h
@@ +43,5 @@
> #include "mozilla/dom/indexedDB/IndexedDatabase.h"
> #include "mozilla/dom/indexedDB/IDBDatabase.h"
> #include "mozilla/dom/indexedDB/IDBRequest.h"
>
> +#ifdef IMPL_INDEXEDDB
Boo. Let's not do this.
Assignee | ||
Updated•14 years ago
|
Attachment #569487 -
Attachment is obsolete: true
Attachment #569487 -
Flags: review?(bent.mozilla)
Assignee | ||
Comment 5•14 years ago
|
||
This is mostly what we discussed the other day, except that I decided to maintain everything in the list of pending operations.
Attachment #570237 -
Flags: review?(bent.mozilla)
Comment on attachment 570237 [details] [diff] [review]
Part 2 - Everything else
Review of attachment 570237 [details] [diff] [review]:
-----------------------------------------------------------------
This looks good! Mostly nits below.
::: dom/indexedDB/IndexedDatabaseManager.cpp
@@ +321,2 @@
>
> + nsAutoPtr<SynchronizedOp> op = new SynchronizedOp(aOrigin, aId);
nsAutoPtr kinda sucks, I don't think this compiles on GCC. Use the constructor (e.g. | nsAutoPtr<SynchronizedOp> op(new SynchronizedOp(aOrigin, aId)); |).
@@ +345,5 @@
> + return NS_OK;
> +}
> +
> +void
> +IndexedDatabaseManager::AllowOpensToProceed(const nsACString& aOrigin,
Nit: OnSynchronizedOpComplete? AllowNextSynchronizedOp?
@@ +360,5 @@
> + NS_ASSERTION(op->mDatabases.IsEmpty(), "How did this happen?");
> +
> + op->DispatchDelayedRunnables();
> +
> + mSynchronizedOps.RemoveElementAt(index);
Hm. How about you just make this method take a SynchronizedOp* and then have the helpers pass 'this'? Then you could just call IndexOf instead of looping manually.
@@ +375,4 @@
> }
>
> nsresult
> +IndexedDatabaseManager::AcquireExclusiveAccess(const nsACString& aOrigin,
Nit: Leave this impl in the header.
@@ +383,5 @@
> + return AcquireExclusiveAccess(aOrigin, nsnull, aHelper, aCallback, aClosure);
> +}
> +
> +nsresult
> +IndexedDatabaseManager::AcquireExclusiveAccess(IDBDatabase* aDatabase,
Nit: Leave this impl in the header.
@@ +418,4 @@
> }
> }
>
> + NS_ASSERTION(op, "We didn't find a SynchronizedOp?");
This isn't testing what you want it to since you're assigning op every time through the loop. I think you want to set it to null, then only assign if you break.
@@ +422,5 @@
>
> + nsTArray<IDBDatabase*>* array;
> + mLiveDatabases.Get(aDatabase->Origin(), &array);
> +
> + // Otherwise, we need to wait for the databases to go away.
Nit: "Otherwise" doesn't make sense here.
@@ +433,5 @@
> + for (PRUint32 index = 0; index < count; index++) {
> + IDBDatabase*& database = array->ElementAt(index);
> + if (!database->IsClosed() &&
> + database != aDatabase &&
> + (aDatabase && database->Id() == aDatabase->Id())) {
This is icky... How about:
if (aDatabase &&
aDatabase != database &&
aDatabase->Id() == database->Id() &&
!database->IsClosed()) {
...
}
@@ +530,5 @@
> + (op->mId == aDatabase->Id() || !op->mId)) {
> + // This database is in the scope of this SynchronizedOp. Remove it
> + // from the list if necessary.
> + if (!op->mDatabases.IsEmpty() &&
> + op->mDatabases.RemoveElement(aDatabase)) {
Nit: No need for the IsEmpty check, RemoveElement will return false in that case anyway.
@@ +532,5 @@
> + // from the list if necessary.
> + if (!op->mDatabases.IsEmpty() &&
> + op->mDatabases.RemoveElement(aDatabase)) {
> + // Now set up the helper if there are no more live databases.
> + NS_ASSERTION(op->mHelper, "How did we get rid of the helper before"
Nit: need a space after "before"
@@ +540,5 @@
> + // can be started. There may, however, still be outstanding
> + // transactions that have not completed. We need to wait for those
> + // before we dispatch the helper.
> +
> + TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
This can theoretically fail, bail if it does. (I know the old code didn't, but hey, some moron wrote that ;) )
@@ +546,5 @@
> + nsRefPtr<WaitForTransactionsToFinishRunnable> waitRunnable =
> + new WaitForTransactionsToFinishRunnable(op);
> +
> + nsAutoTArray<nsRefPtr<IDBDatabase>, 1> array;
> + if (!array.AppendElement(aDatabase)) {
This is infallible now, no need to check.
@@ +676,5 @@
> return rv;
> }
>
> +void
> +IndexedDatabaseManager::DispatchHelper(AsyncConnectionHelper* aHelper)
Nit: add a comment above to denote static method.
Also, this can fail, so maybe return nsresult and have the callers handle failure.
@@ +685,5 @@
> + if (NS_FAILED(aHelper->DispatchToTransactionPool())) {
> + NS_WARNING("Failed to dispatch to thread pool!");
> + }
> + }
> + // Otherwise, dispatch it to the IO thread.
Nit: Move comment inside else clause
@@ +695,5 @@
> + }
> +}
> +
> +bool
> +IndexedDatabaseManager::HaveClearOriginRunnableForOrigin(const nsACString& origin)
Nit: IsClearOriginPending?
@@ +933,3 @@
> // Tell the IndexedDatabaseManager that we're done.
> IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
> + // XXXkhuey why is this conditional?
Probably should be asserted, not conditional.
@@ +1106,5 @@
> return NS_OK;
> }
> +
> +
> +IndexedDatabaseManager::SynchronizedOp::SynchronizedOp(const nsACString& aOrigin,
Assert main thread on constructor and destructor?
@@ +1134,5 @@
> + if (aRhs.mId == mId) {
> + return true;
> + }
> +
> + // Waiiting is required if either one corresponds to an origin clearing
Nit: "Waiiting"
::: dom/indexedDB/IndexedDatabaseManager.h
@@ +210,5 @@
>
> // Called when AsyncUsageRunnable has finished its Run() method.
> inline void OnUsageCheckComplete(AsyncUsageRunnable* aRunnable);
>
> + // Struct contain
Nit: Unfinished comment
@@ +260,5 @@
> // usage statistics.
> nsAutoTArray<nsRefPtr<AsyncUsageRunnable>, 1> mUsageRunnables;
>
> + // Maintains a list of synchronized operatons that are in progress or queued.
> + nsAutoTArray<nsAutoPtr<SynchronizedOp>, 1> mSynchronizedOps;
I'm feeling generous today, let's make this 5.
::: dom/indexedDB/OpenDatabaseHelper.cpp
@@ +1093,5 @@
> return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase),
> aVal);
> }
>
> +/* static */ void
Nit: Two lines, and use //
::: dom/indexedDB/OpenDatabaseHelper.h
@@ +85,5 @@
>
> nsresult NotifySetVersionFinished();
> void BlockDatabase();
>
> + nsIAtom* Id()
Nit: const
@@ +90,5 @@
> + {
> + return mDatabaseId.get();
> + }
> +
> + IDBDatabase* Database()
Nit: const
Attachment #570237 -
Flags: review?(bent.mozilla) → review+
Assignee | ||
Comment 7•14 years ago
|
||
https://hg.mozilla.org/integration/mozilla-inbound/rev/a64b3abb31c4
https://hg.mozilla.org/integration/mozilla-inbound/rev/572e4723a496
Flags: in-testsuite+
Target Milestone: --- → mozilla10
Comment 8•14 years ago
|
||
https://hg.mozilla.org/mozilla-central/rev/a64b3abb31c4
https://hg.mozilla.org/mozilla-central/rev/572e4723a496
Status: ASSIGNED → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
Comment 9•14 years ago
|
||
Comment on attachment 570237 [details] [diff] [review]
Part 2 - Everything else
>--- a/dom/indexedDB/CheckPermissionsHelper.cpp
>+++ b/dom/indexedDB/CheckPermissionsHelper.cpp
>@@ -201,13 +201,13 @@ CheckPermissionsHelper::Observe(nsISuppo
> IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
> NS_ASSERTION(mgr, "This should never be null!");
>
>- rv = mgr->WaitForOpenAllowed(mName, mASCIIOrigin, this);
>+ rv = NS_DispatchToCurrentThread(this);
And mgr is unused now?
Assignee | ||
Updated•13 years ago
|
Component: DOM → DOM: IndexedDB
Target Milestone: mozilla10 → ---
You need to log in
before you can comment on or make changes to this bug.
Description
•