Re: [IndexedDB] Current editor's draft

On Tue, Jul 6, 2010 at 9:36 AM, Nikunj Mehta <nikunj@o-micron.com> wrote:
> Hi folks,
>
> There are several unimplemented proposals on strengthening and
> expanding IndexedDB. The reason I have not implemented them yet is
> because I am not convinced they are necessary in toto. Here's my
> attempt at explaining why. I apologize in advance for not responding
> to individual proposals due to personal time constraints. I will
> however respond in detail on individual bug reports, e.g., as I did
> with 9975.
>
> I used the current editor's draft asynchronous API to understand where
> some of the remaining programming difficulties remain. Based on this
> attempt, I find several areas to strengthen, the most prominent of
> which is how we use transactions. Another is to add the concept of a
> catalog as a special kind of object store.

Hi Nikunj,

Thanks for replying! I'm very interested in getting this stuff sorted
out pretty quickly as almost all other proposals in one way or another
are affected by how this stuff develops.

> Here are the main areas I propose to address in the editor's spec:
>
> 1. It is time to separate the dynamic and static scope transaction
> creation so that they are asynchronous and synchronous respectively.

I don't really understand what this means. What are dynamic and static
scope transaction creation? Can you elaborate?

> 2. Provide a catalog object that can be used to atomically add/remove
> object stores and indexes as well as modify version.

It seems to me that a catalog object doesn't really provide any
functionality over the proposal in bug 10052? The advantage that I see
with the syntax proposal in bug 10052 is that it is simpler.

http://www.w3.org/Bugs/Public/show_bug.cgi?id=10052

Can you elaborate on what the advantages are of catalog objects?

> 3.  Cursors may produce a null key or a null value. I don't see how
> this is valid signaling for non-preloaded cursors. I think we need to
> add a new flag on the cursor to find out if the cursor is exhausted.

Our proposal was that IDBEvent.result would normally contain the
cursor object, but once the end is reached it returns null. To be
clear:

When a value is found:
event.result;   // returns cursor object, never null
event.result.key;  // returns key, may be null
event.result.value;  // returns value, may be null

When end is reached:
event.result;  // returns null


> A couple of additional points:
>
> 1. I did not see any significant benefits of preloaded cursors in
> terms of programming ease.

Yes, there seems to be agreement that preloaded cursors should be
removed. I've removed them from our proposal.

> 2. *_NO_DUPLICATE simplifies programming as well as aids in good
> performance. I have shown one example that illustrates this.

I'll have to analyze the examples below. My gut instinct though is
that I agree with you that they are needed.

> 3. Since it seems continue is acceptable to implementers, I am also
> suggesting we use delete instead of remove, for consistency sake.

Agreed.

> ------- IDL --------
>
> [NoInterfaceObject]
> interface IDBDatabase {
>  readonly attribute DOMString     name;
>  readonly attribute DOMString     description;
>  readonly attribute DOMStringList objectStores;
>  /*
>  Open an object store in the specified transaction. The transaction can be
>  dynamic scoped, or the requested object store must be in the static scope.
>  Returns IDBRequest whose success event of IDBTransactionEvent type contains
>  a result with IDBObjectStore and transaction is an IDBTransactionRequest.
>  */
>  IDBRequest openObjectStore(in DOMString name, in IDBTransaction txn,
>  in optional unsigned short mode /* defaults to READ_WRITE */);

I don't understand the advantage of this proposal over mozillas
proposal. One of our main points was to make getting objectStore
objects a synchronous operation as to avoid having to nest multiple
levels of asynchronous calls. Compare

var req = db.openObjectStore("foo", trans);
req.onerror = errorHandler;
req.onsuccess = function(e) {
  var fooStore = e.result;
  var req = fooStore.get(12);
  req.onerror = errorHandler;
  req.onsuccess = resultHandler;
}

to

var fooStore = db.openObjectStore("foo", trans);
var req = fooStore.get(12);
req.onerror = errorHandler;
req.onsuccess = resultHandler;


I also don't understand the advantage of having the transaction as an
argument to openObjectStore rather than having openObjectStore live on
transaction. Compare

db.openObjectStore("foo", trans);

to

trans.openObjectStore("foo");

I also don't understand the meaning of specifying a mode when a
objectStore is opened, rather than specifying the mode when the
transaction is created. Unless we're planning on making all
transactions dynamic (I hope not), locks have to be grabbed when the
transaction is created, right? If a transaction is holding a READ_ONLY
lock for a given objectStore, then attempting to open that objectStore
as READ_WRITE should obviously fail. Consecutively, if a transaction
is holding a READ_WRITE lock for a given objectStore, then opening
that objectStore as READ_ONLY doesn't seem to have any benefit over
opening it as READ_WRITE. In short, I can't see any situation when
you'd want to open an objectStore in a different mode than what was
used when the transaction was created.

Finally, I would stronly prefer to have READ_ONLY be the default
transaction type if none is specified by the author. It is better to
default to what results in higher performance, and have people notice
when they need to switch to the slower mode. This is because people
will very quickly notice if they use READ_ONLY when they need to use
READ_WRITE, since the code will never work. However if people use
READ_WRITE when all they need is READ_ONLY, then the only effect is
likely to be an application that runs somewhat slower, when they will
unlikely detect.

>  /*
>  Open the database catalog in the specified transaction for exclusive access.
>  Returns IDBRequest whose success event of IDBTransactionEvent type contains
>  a result with IDBCatalog and transaction is an IDBTransactionRequest.
>  */
>  IDBRequest openCatalog(in IDBTransaction txn);

See above regarding catalog objects.

>  /*
>  Create a new static scoped transaction asynchronously.
>  Returns IDBRequest whose success event of IDBSuccessEvent type contains a
>  result with IDBTransactionRequest.
>  */
>  IDBRequest openTransaction (in optional DOMStringList storeNames /*
> defaults to mean all object stores */,
>  in optional unsigned short mode /* defaults to READ_WRITE */,
>  in optional IDBTransaction parent /* defaults to null */,
>  in optional unsigned long timeout /* defaults to no timeout*/);
>  /*
>  Create a new dynamic scoped transaction. This returns a transaction handle
>  synchronously.
>  */
>  IDBTransaction transaction (in optional IDBTransaction parent /*
> defaults to null */,
>  in optional unsigned long timeout /* defaults to no timeout*/);

I don't understand this. When would you ever want to use the
asynchronous version?

Why can't you specify a list of objectStores in the synchronous version?

Do we really need nested transactions? I do see that you added them in
latest revision of the editor drafts, but it seems like a fairly
advanced feature that would be nice to leave for a v2. If everyone
else wants them, I can check how much work it would be for us to
implement them, but my vote is to leave it for a later version.

I've left out commenting on the other interfaces for now, as it seems
that the decisions we make for the questions above will likely affect
the other interfaces anyway.

/ Jonas

Received on Wednesday, 7 July 2010 00:28:44 UTC