[whatwg] RFC: Alternatives to storage mutex for cookies and localStorage

Chris Jones cjones at mozilla.com
Wed Sep 9 09:59:23 PDT 2009


Jeremy Orlow wrote:
>         Those who want a queue.  I.e. those who want an asynchronous
>         callback based interface and the UA will only call one callback
>         at a time.  Perhaps on a per-origin basis.  Note that this can
>         never "fail", need to be rolled back, etc.
> 
> 
>     This sounds to me like { traditional transactions, async,
>     unobservable transaction failures } which is the same as your first
>     camp above except async only.  Or are you proposing that the unit of
>     atomicity/consistency is not all operations performed in the
>     callback; i.e., that modifications done in the callback can be
>     partially applied?
> 
> 
> It's just an implementational difference.  A queue means that the event 
> loop can continue processing stuff while waiting for the 'lock' (which 
> maybe is better described as an 'update token' or something).  If you 
> implement it as a lock (which you would for a synchronous interface) 
> then the event loop is blocked.
>  

OK, agreed.  What we describe reduce to the same thing --- the "trylock" 
implementation Rob O'Callahan and I discussed would also never block the 
event loop.  But I better understand now what you have in mind.  (I'm 
not sure which is better, but that's what implementation details are all 
about!)

> 
>         I believe Aaron is in the queue camp with me.  I'm becoming more
>         and more convinced that Chromium should/will not implement the
>         storage mutex at all (even for LocalStorage) unless we can come
>         up with a way for event loops to not be blocked.  And, as far as
>         I can tell, Async interfaces are the only way to accomplish this.
> 
> 
>     In general, agreed.  I still believe that a sync API
> 
> 
> The problem with a sync interface, especially if it's one that can be 
> held after the top level script context, is deadlock issues with 
> WebDatabase (and possibly others).  What's there now doesn't have this 
> issue because you'd never have the lock when calling the database 
> transaction callback.
>  

I didn't think of Web Database, although I had in mind a nonblocking 
implementation of localStorage (i.e., no mutex) that would prevent it 
from participating in deadlocks.

But in general, nesting transactions, both { localStorage { Web DataBase 
} } and { localStorage { localStorage  } }, is something the spec should 
explicitly disallow.  There's not a clearly best way to resolve the 
semantic problems that arise.  (Note that preventing nested transactions 
also eliminates deadlock concerns for mutex implementations.)

> 
>     with exposed transaction failures
> 
> 
> You'll only have transaction failures in an optimistic transaction 
> model, right?  So is that what you're suggesting?
>  
> 
>     (as I proposed in the OP) and the right implementation could do
>     quite well.  But I now think that an async version of that same API
>     could perform even better.  In addition, that API is most flexible
>     in terms of possible UA implementations.
> 
> 
>     IOW, I think that { traditional transactions, async, observable
>     failures } subsumes both { traditional transactions, sync,
>     observable failures } (OP's proposal) *and* { traditional
>     transactions, async, unobservable failures } (your and Aaron's
>     proposal).
> 
> 
>     IMHO there are two remaining questions: first, whether the "ideal"
>     localStorage transactional API should allow observable transaction
>     failures.  I believe that it should, as this allows for the widest
>     variety of efficient implementations without changing ACID (best
>     effort) guarantees given to authors or significantly complicating
>     the localStorage API.
> 
> 
> What failures could there be in a pesimistic/queue model?
> 

I'm trying to think of a "universal failure," something that could arise 
in any implementation of any proposal.  I think that universal failure 
is "exceeded localStorage space quota".  (I believe there are others, 
but one is enough for this discussion.)

So there are really two questions: first, what happens if you detect 
"quota exceeded" in the middle of a localStorage.transaction() callback? 
  Are the modifications made *up to* the quota exceeded error applied to 
backing store?  Or are they rolled back?  This is the 
atomicity/consistency design decision I described: what is the unit of 
atomic modification (all applied or none applied).

And second, can scripts be notified that the transaction failed (or was 
only partially applied) because of quota exceeded?

AFAICT this is irrespective of sync/async/optimistic/pessimistic/queue. 
  Any implementation has to deal with this error somehow.

In the current localStorage spec, if a setItem() fails because space is 
exhausted, it raises QUOTA_EXCEEDED_ERR and does *not* apply any part of 
the change in setItem().  That is, setItem() is atomic --- it either 
applies or not (not partially applied).  But modifications to 
localStorage *before* that failing setItem(), within the same storage 
mutex acquire/release set, *are* applied to backing store.

In the Web Database spec, if executing a SQL statement in a Transaction 
would cause space quota to be exceeded, then *none* of the statements in 
the transaction are executed (i.e. none committed to backing store), and 
the Transaction fails with QUOTA_ERR.  The unit of atomicity for Web 
Database is that Transaction object --- either all statements in 
Transaction successfully execute or none do.

I'm not sure whether you're proposing that modifications within a 
localStorage.transaction() callback are atomic (all applied or none 
applied) in the face of quota exceeded.  (I'm proposing that they 
*should* be atomic.)

It sounds like you're proposing that scripts *cannot* be notified of 
quota exceeded.  If this is true, then there are some semantic issues 
I'd like to discuss.  But I want to make sure we're on the same page 
first :).  (I'm proposing that scripts *should* be able to be notified 
of this.)

>     Second, what is the best way to go forward with transactional
>     localStorage while remaining backwards-compatible with current
>     implementations.  One option would be to deprecate localStorage in
>     favor of a future, transactional window.domainStorage or somesuch.
> 
> 
> If we do this, we might as well just adopt something like the 
> WebSimpleDatabase proposal (which I still haven't gotten around to 
> reading yet) which seems much more powerful in many other ways.
>  

Certainly a matter of taste, but I like localStorage's API, I'd like to 
see it succeed.

>     In addition, for cases like "clear private data", UAs would be
>     allowed to silently break storage-mutex isolation for apps using the
>     non-transactional API.
> 
> 
> I think it'd be better if they waited for the lock to be freed.

Should be clear that this is for users of the deprecated, 
non-transactional API only.  Isolation wouldn't be broken for 
transactional users.

By the storage mutex spec, without the caveat that isolation may be 
sometimes broken, even non-malicious pages that don't exceed the slow 
script timeout might be able to (unknowingly) cooperate to indefinitely 
prevent a MELUA from clearing private data (assuming clear private data 
isn't a blocking operation in the MELUA).  The UA might be able to 
prevent that with some fancy footwork, but I don't see the point in 
doing that for a deprecated API.

Cheers,
Chris



More information about the whatwg mailing list