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)

defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: khuey, Assigned: khuey)

References

Details

Attachments

(2 files, 1 obsolete file)

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.
Attached patch Part 2: Everything else (obsolete) — Splinter Review
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.
Attachment #569487 - Attachment is obsolete: true
Attachment #569487 - Flags: review?(bent.mozilla)
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+
Status: ASSIGNED → RESOLVED
Closed: 14 years ago
Resolution: --- → FIXED
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?
Component: DOM → DOM: IndexedDB
Target Milestone: mozilla10 → ---
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: