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

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
}

This is per the text in IDBDatabase following the phrase "once the
closePending flag is set on the connection....", where a closing connection
maintains a snapshot of the metadata. 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.

Received on Friday, 4 May 2012 21:11:47 UTC