[IndexedDB] New version API checked in

Hi Everyone,

I finally got around to updating the IndexedDB spec to the new version
API! Definitely a non-trivial change, so I'd love for people to have a
look at it to see if I messed anything up.

I decided to go with the name "upgradeneeded" for the event fired when
a version upgrade is needed. I'm not terribly happy with the name, but
it does feel descriptive.

I also went with integers (long long) for the version number. The
reason was that I wanted to avoid people passing strings like "1.10"
to the API since JS will automatically and silently convert that to
the number 1.1. This could lead to confusion since people might think
that "1.10" is a higher version than "1.9".


There were a few issues that came up during editing, mostly related to
edge cases that doesn't matter terribly much:

* What to do if multiple different versions are opened at the same time.
Consider the following scenario. A database with name "mydb" has
version 3. The following two calls happen almost at the same time:

req1 = indexedDB.open("mydb", 4);
and
req2 = indexedDB.open("mydb", 5);

It's clear that we should here fire a "upgradeneeded" event on req2
and let it run a VERSION_CHANGE transaction to upgrade the database to
version 5. There are however two possible things we could do to req1.

A) Immediately fail by firing an "error" event on req1.
B) Wait for req2 to attempt to upgrade the database version to 5. Only
once that succeeds fail req1 by firing an "error" event at it. If req2
failed to upgrade the database (due to a aborted transaction), then
fire a "upgradeneeded" transaction on req1.

This seems like a really rare edge case and I don't think it matters
much what we do. I chose to go with option B since it results in the
least amount of errors and it doesn't seem particularly important to
optimize for failing open calls quickly in this rare situation.

I don't think it matters much what we choose here. I think it's very
unlikely to matter in any real-world scenarios. I might even be fine
with letting implementations choose to go with either solution here.


* What to do if indexedDB.open is called while a VERSION_CHANGE
transaction is pending, but the new call is for a higher version.
Consider the following scenario:

1. A database with name "mydb" and version 1 is currently open in tab 1.
2. Someone calls indexedDB.open("mydb", 2) in tab 2.
3. The indexedDB implementation fires a "versionchange" event on the
open connection in tab 1 and waits for it to close. The newVersion
property of the event is set to 2.
4. Someone calls indexedDB.open("mydb", 3) in tab 3.

At this point there are at least two options:
A) Simply let the call in step 4 wait for the call in step 2 to
finish. Only after it has finished will we fire new events to attempt
an upgrade to version 3
B) Stall the upgrade two version 2 and instead start attempting an
upgrade to version 3. I.e. fire a new "versionchange" event on the
open connection in tab 1 (now with newVersion set to 3), and once that
connection is closed, fire a "upgradeneeded" event and start a
VERSION_CHANGE transaction in tab 3.

Option A basically makes us behave as if the call in step 4 happened
after the VERSION_CHANGE transaction for the call in step 2 had
started. Option B almost makes us behave as if the calls in step 2 and
step 4 had happened at the same time (with the exception that two
"versionchange" events are fired).

As with the previous issue I don't think it matters much what we
choose here. I think it's very unlikely to matter in any real-world
scenarios. I might even be fine with letting implementations choose to
go with either solution here.


* What to do if db.close() is called during the VERSION_CHANGE transaction
Calling db.close() during a VERSION_CHANGE transaction somewhat
similar to calling transaction.abort(). At least in the sense that in
neither case does it make sense for
IDBFactorySync.open/IDBFactory.open to complete successfully. I.e. it
would seem strange to let IDBFactorySync.open return a closed
database, or to fire a "success" event on the request returned by
IDBFactory.open and then deliver a closed database.

We could make db.close() throw an exception in this case, but that
seems like a odd behavior for db.close() compared to how it usually
interacts with running transactions (i.e. it usually lets them
finish).

I'm instead leaning towards letting the VERSION_CHANGE transaction
continue running, but make IDBFactorySync.open throw an exception and
fire an "error" event on the request returned from IDBFactory.open.

In fact, after thinking about this some more I checked in a change to
the spec to make it define that behavior. The main problem was that we
don't have a really good error for this situation. I decided to return
a ABORT_ERR error, but if anyone has other suggestions, or think we
should use should use a dedicated error, I'm fine with that too.

If people feel that we should use another solution, please do speak
up. It's easy to back out my patch :-)

/ Jonas

Received on Sunday, 4 September 2011 10:33:30 UTC