Re: [IndexedDB] Bug 14404: What happens when a versionchange transaction is aborted?

On Fri, May 4, 2012 at 2:11 PM, Joshua Bell <jsbell@chromium.org> wrote:
>
>
> On Fri, May 4, 2012 at 2:04 PM, Jonas Sicking <jonas@sicking.cc> wrote:
>>
>> On Fri, May 4, 2012 at 1:19 PM, Israel Hilerio <israelh@microsoft.com>
>> wrote:
>> > On Thursday, May 03, 2012 3:30 PM, Jonas Sicking wrote:
>> >> On Thu, May 3, 2012 at 1:30 AM, Jonas Sicking <jonas@sicking.cc> wrote:
>> >> > Hi All,
>> >> >
>> >> > The issue of bug 14404 came up at the WebApps face-to-face today. I
>> >> > believe it's now the only remaining non-editorial bug. Since we've
>> >> > tried to fix this bug a couple of times in the spec already, but it
>> >> > still remains confusing/ambigious, I wanted to re-iterate what I
>> >> > believe we had decided on the list already to make sure that we're
>> >> > all
>> >> > on the same page:
>> >> >
>> >> > Please note that in all cases where I say "reverted", it means that
>> >> > the properties on the JS-object instances are actually *changed*.
>> >> >
>> >> > When a versionchange transaction is aborted, the following actions
>> >> > will be taken:
>> >> >
>> >> > IDBTransaction.name is not modified at all. I.e. even if is is a
>> >> > transaction used to create a new database, and thus there is no
>> >> > on-disk database, IDBTransaction.name remains as it was.
>> >> >
>> >> > IDBTransaction.version will be reverted to the version the on-disk
>> >> > database had before the transaction was started. If the versionchange
>> >> > transaction was started because the database was newly created, this
>> >> > means reverting it to version 0, if it was started in response to a
>> >> > version upgrade, this means reverting to the version it had before
>> >> > the
>> >> > transaction was started. Incidentally, this is the only time that the
>> >> > IDBTransaction.version property ever changes value on a given
>> >> > IDBTransaction instance.
>> >> >
>> >> > IDBTransaction.objectStoreNames is reverted to the list of names that
>> >> > it had before the transaction was started. If the versionchange
>> >> > transaction was started because the database was newly created, this
>> >> > means reverting it to an empty list, if it was started in response to
>> >> > a version upgrade, this means reverting to the list of object store
>> >> > names it had before the transaction was started.
>> >> >
>> >> > IDBObjectStore.indexNames for each object store is reverted to the
>> >> > list of names that it had before the transaction was started. Note
>> >> > that while you can't get to object stores using the
>> >> > transaction.objectStore function after a transaction is aborted, the
>> >> > page might still have references to objec store instances and so
>> >> > IDBObjectStore.indexNames can still be accessed. This means that for
>> >> > any object store which was created by the transaction, the list is
>> >> > reverted to an empty list. For any object store which existed before
>> >> > the transaction was started, it means reverting to the list of index
>> >> > names it had before the transaction was started. For any object store
>> >> > which was deleted during the transaction, the list of names is still
>> >> > reverted to the list it had before the transaction was started, which
>> >> > potentially is a non-empty list.
>> >> >
>> >> > (We could of course make an exception for deleted objectStore and
>> >> > define that their .indexNames property remains empty. Either way we
>> >> > should explicitly call it out).
>> >> >
>> >> >
>> >> > The alternative is that when a versionchange transaction is aborted,
>> >> > the
>> >> >
>> >> > IDBTransaction.name/IDBTransaction.objectStoreNames/IDBObjectStore.ind
>> >> > exNames properties all remain the value that they have when the
>> >> > transaction is aborted. But last we talked about this Google,
>> >> > Microsoft and Opera preferred the other solution (at least that's how
>> >> > I understood it).
>> >>
>> >> Oh, and I should add that no matter what solution with go with (i.e.
>> >> whether we change the properties back to the values they had before the
>> >> transaction, or if we leave them as they were at the time when the
>> >> transaction is
>> >> aborted), we should *of course* on disk revert any changes that were
>> >> done to
>> >> the database.
>> >>
>> >> The question is only what we should do to the properties of the
>> >> in-memory JS
>> >> objects.
>> >>
>> >> / Jonas
>> >
>> > What you describe at the beginning of your email is what we recall too
>> > and like :-).  In other words, the values of the transacted objects (i.e.
>> > database, objectStores, indexes) will be reverted to their original values
>> > when an upgrade transaction fails to commit, even if it was aborted.  And
>> > when the DB is created for the first time, we will leave the objectStore
>> > names as an empty list and the version as 0.
>>
>> I'll assume that this includes updating IDBObjectStore.indexNames on
>> objectStores that were deleted.
>>
>> Sounds like this is the way we should go then, unless Google is very
>> opposed to it.
>>
>> > We're assuming that instead of
>> > IDBTransaction.name/objectStoreNames/version you meant to write IDBDatabase.
>>
>> Yes. Thanks for catching this.
>>
>> Someone needs to edit this into the spec as the current spec text
>> isn't really sufficient. I believe this is the only thing preventing
>> us from going into Last Call!! (woot!)
>>
>> / Jonas
>
>
> We're not "very opposed" But just to be clear, this implies:
>
> var db1, db2, db3, db4;
>
> function firstOpen() {
>   var req = indexedDB.open("db", 1);
>   req.onupgradeneeded = function () {
>     db1 = req.result;
>     db1.createObjectStore("store1");
>   };
>   req.onsuccess = function () {
>     db1.close();
>     secondOpen();
>   };
> }
>
> function secondOpen() {
>   var req = indexedDB.open("db", 2);
>   req.onupgradeneeded = function () {
>     db2 = req.result;
>     db2.createObjectStore("store2");
>   };
>   req.onsuccess = function () {
>     db2.close();
>     thirdOpen();
>   };
> }
>
> function thirdOpen() {
>   var req = indexedDB.open("db", 3);
>   req.onupgradeneeded = function () {
>     db3 = req.result;
>     db3.createObjectStore("store3");
>     req.transaction.abort();
>     fourthOpen();
>   };
> }
>
> function fourthOpen() {
>   var req = indexedDB.open("db", 4);
>   req.onupgradeneeded = function () {
>     db4 = req.result;
>     db4.createObjectStore("store4");
>   };
>   req.onsuccess = function () {
>     db4.close();
>     checkState();
>   };
> }
>
> function checkState() {
>   assert(db1.version === 1); // snapshot
>   assert(db2.version === 2); // snapshot
>   assert(db3.version === 2); // reverted
>   assert(db4.version === 4); // snapshot
>
>   assert(db1.objectStoreNames.length === 1); // snapshot
>   assert(db2.objectStoreNames.length === 2); // snapshot
>   assert(db3.objectStoreNames.length === 2); // reverted
>   assert(db4.objectStoreNames.length === 3); // snapshot
> }

Yes. This is correct.

> It seems unusual to me that for
> aborted upgrade transactions, which also result in the connection being
> closed, we require implementations to do extra work. If this makes sense to
> everyone else, I don't have objections.

I agree, but I don't really care that much and since more people seem
to want the other behavior I'm ok with that.

/ Jonas

Received on Friday, 4 May 2012 21:18:34 UTC