[whatwg] Structured clone algorithm on LocalStorage

Darin Fisher darin at chromium.org
Fri Oct 2 21:58:33 PDT 2009


On Fri, Oct 2, 2009 at 9:43 PM, Jonas Sicking <jonas at sicking.cc> wrote:

>   >> >> > Moreover, there are other examples which have been discussed on
>>>>> the
>>>>> >> >> > list.  There are some DOM operations that can result in a frame
>>>>> >> >> > receiving
>>>>> >> >> > a DOM event synchronously.  That can result in a nesting of
>>>>> storage
>>>>> >> >> > locks,
>>>>> >> >> > which can force us to have to implicitly unlock the outermost
>>>>> lock to
>>>>> >> >> > avoid
>>>>> >> >> > deadlocks.  Again, the programmer will have very poor
>>>>> visibility into
>>>>> >> >> > when
>>>>> >> >> > these things can happen.
>>>>> >> >>
>>>>> >> >> So far I don't think it has been shown that these events need to
>>>>> be
>>>>> >> >> synchronous. They all appear to be asynchronous in gecko, and in
>>>>> the
>>>>> >> >> case of different-origin frames, I'm not even sure there's a way
>>>>> for
>>>>> >> >> pages to detect if the event was fired asynchronously or not.
>>>>> >> >
>>>>> >> > IE and WebKit dispatch some of them synchronously.  It's hard to
>>>>> say
>>>>> >> > which
>>>>> >> > is correct or if it causes any web compat isues.  I'm also not
>>>>> sure that
>>>>> >> > we
>>>>> >> > have covered all of the cases.
>>>>> >>
>>>>> >> It still seems to me that it's extremely unlikely that pages depend
>>>>> on
>>>>> >> cross origin events to fire synchronously. I can't even think of a
>>>>> way
>>>>> >> to test if a browser dispatches these events synchronously or not.
>>>>> Can
>>>>> >> you?
>>>>> >
>>>>> > i agree that it seems uncommon.  maybe there could be some odd app
>>>>> that
>>>>> > does something after resizing an iframe that could be dependent on
>>>>> the
>>>>> > event handler setting some data field.  this kind of thing is
>>>>> probably even
>>>>> > less common in the cross-origin case.
>>>>>
>>>>> But how would you read that data field in the cross-origin frame? I
>>>>> think it might be possible, but extremely hard.
>>>>>
>>>>>
>>>> Yeah.
>>>>
>>>> My concern is simply that I cannot prove that I don't have to worry
>>>> about this
>>>> problem.  Future web APIs might also inadvertently make matters worse.
>>>>
>>>
>>> I agree it's not ideal, but at the same time I don't think that not
>>> allowing synchronous cross-origin APIs is a huge burden. You campaigned
>>> heavily against that when we were designing postMessage for wholly other
>>> reasons. I would imagine those reasons will hole true no matter what.
>>>
>>
>> Agreed.  That's a good point.  In that case, I was concerned about stack
>> depth.  The same issue might apply here.  Hmm...
>>
>
> As far as I can see it does.
>
>
>
>>
>> ...snip...
>>
>>>
>>>>> >> >> Not quite sure I follow your proposal. How would you for example
>>>>> >> >> increase the value of a property by one without risking race
>>>>> >> >> conditions? Or keep two values in different properties in sync?
>>>>> I.e.
>>>>> >> >> so that if you update one always update the other, so that they
>>>>> never
>>>>> >> >> have different values.
>>>>> >> >>
>>>>> >> >> / Jonas
>>>>> >> >
>>>>> >> >
>>>>> >> > Easy.  Just like with database, the transaction is the storage
>>>>> lock.
>>>>> >> >  Any
>>>>> >> > storage
>>>>> >> > operation performed on that transaction are done atomically.
>>>>>  However,
>>>>> >> > all
>>>>> >> > storage
>>>>> >> > operations are asynchronous.  You basically string together
>>>>> asynchronous
>>>>> >> > storage
>>>>> >> > operations by using the same transaction for each.
>>>>> >> > We could add methods to get/set multiple items at once to simplify
>>>>> life
>>>>> >> > for
>>>>> >> > the coder.
>>>>> >>
>>>>> >> I think I still don't understand your proposal, could you give some
>>>>> >> code examples?
>>>>> >>
>>>>> >
>>>>> >
>>>>> > ripping off database:
>>>>> > interface ValueStorage {
>>>>> >   void transaction(in DOMString namespace, in
>>>>> > ValueStorageTransactionCallback callback);
>>>>> > };
>>>>> > interface ValueStorageTransactionCallback {
>>>>> >   void handleEvent(in ValueStorageTransaction transaction);
>>>>> > };
>>>>> > interface ValueStorageTransaction {
>>>>> >   void readValue(in DOMString name, in ValueStorageReadCallback
>>>>> callback);
>>>>> >   void writeValue(in DOMString name, in DOMString value);
>>>>> > };
>>>>> > interface ValueStorageReadCallback {
>>>>> >   void handleEvent(in ValueStorageTransaction transaction, in
>>>>> DOMString
>>>>> > value);
>>>>> > };
>>>>> > then, to use these interfaces, you could implement thread-safe
>>>>> increment:
>>>>> > window.localStorage.transaction("slice", function(transaction) {
>>>>> >   transaction.readValue("foo", function(transaction, fooValue) {
>>>>> >     transaction.writeValue("foo", ++fooValue);
>>>>> >   })
>>>>> > })
>>>>> > to fetch multiple values, you could do this:
>>>>> > var values = [];
>>>>> > var numValues = 10;
>>>>> > function readNextValue(transaction) {
>>>>> >   if (values.length == numValues)
>>>>> >    return;  // done!
>>>>> >   var index = values.length;
>>>>> >   transaction.readValue("value" + index, function(transaction, value)
>>>>> {
>>>>> >     values.push(value);
>>>>> >     readNextValue(transaction);
>>>>> >   })
>>>>> > }
>>>>> > window.localStorage.transaction("slice", readNextValue);
>>>>> > This has the property that all IO is non-blocking and the "lock" is
>>>>> held
>>>>> > only
>>>>> > for a very limited scope.  The programmer is however free to extend
>>>>> the
>>>>> > life of the lock as needed.
>>>>>
>>>>> What do you mean by that the "lock" is held for only a very limited
>>>>> scope? You still want to prevent modifications for as long as the
>>>>> transaction is being used right? I.e. no modifications can happen
>>>>> between the read and the write in the first example, and between the
>>>>> different reads in the second.
>>>>>
>>>>
>>>> Yes.  I only meant that the programmer doesn't have to call a special
>>>> function to close the transaction.  It closes by virtue of the last
>>>> handleEvent
>>>> call referring to the transaction returning.
>>>>
>>>
>>> So wouldn't you implement this transaction using a lock? To prevent other
>>> pages from accessing the localStorage?
>>>
>>>
>> Yes, but it wouldn't need to be a normal mutex if that's what you mean.
>>  You could just defer callbacks until the transaction completes.  It is
>> purely asynchronous locking.
>>
>
> So how is that then different from from using a Storage API, but only
> letting you get a reference to the Storage object using a asynchronous API?
> And of course not allowing the Storage object to be stored in a variable and
> used outside the callback.
>
>
The difference is that storage IO is fully asynchronous in the API I
proposed.  It doesn't have to block the calling thread for reads.  I think
that is important.

We should never design any APIs that involve synchronous IO (filesystem or
network) from the main UI thread.

-Darin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.whatwg.org/pipermail/whatwg-whatwg.org/attachments/20091002/a2d3764a/attachment-0002.htm>


More information about the whatwg mailing list