Re: [whatwg] RFC: Alternatives to storage mutex for cookies and localStorage
Great analysis. I only have a few comments/questions: On Wed, Sep 9, 2009 at 1:41 PM, Chris Jones cjo...@mozilla.com wrote: Jeremy Orlow wrote: On Wed, Sep 9, 2009 at 4:39 AM, Chris Jones cjo...@mozilla.com mailto: cjo...@mozilla.com wrote: Aaron Boodman wrote: On Tue, Sep 8, 2009 at 11:23 AM, Chris Jonescjo...@mozilla.com mailto:cjo...@mozilla.com wrote: In general, I agree with Rob about this proposal. What problem with storage mutex as spec'd today does your proposal solve? The spec requires a single storage mutex for the entire UA. Therefore in a MELUA a web page can become unresponsive while waiting for some other page to give up the lock. This is not good and something we have tried to avoid everywhere else in the spec. Attempts to address this by doing per-origin locks wind up with deadlocks being possible. Aaron Boodman wrote: On Tue, Sep 8, 2009 at 1:41 AM, Robert O'Callahanrob...@ocallahan.org mailto:rob...@ocallahan.org wrote: What is the intended semantics here? Chris' explicit commitTransaction would throw an exception if the transaction was aborted due to data inconsistency, leaving it up to the script to retry --- and making it clear to script authors that non-storage side effects during the transaction are not undone. How would you handle transaction aborts? Calls to transaction() are queued and executed serially per-origin with exclusive access. There is no such thing as a transaction abort because there cannot be consistency problems because of the serialized access. No, transactions can still fail. They can fail in ways immediately hidden from the script that requested them if the UA has to interrupt the conceptually executing transaction in the ways enumerated in a separate branch of this thread. Later script executions can observe inconsistent state unless more is specified by your proposal. Transactions can also fail visibly if write-to-disk fails (probably also in other ways I haven't considered). It's not clear what should happen wrt to your proposal in this case. If so, I agree with roc's responses to them that they could probably be handled without surfacing errors to the developer. OTOH, I'm not really against adding the concept of fallibility here. In fact, I believe that the Synchronous database API describes the same transaction semantics as I proposed in the OP. That spec adds implicit begin/commitTransaction and read-only transactions, but otherwise the semantics are the same. So I'd like to amend my original proposal to be Use Synchronous Web Database API transaction semantics. Except do not offer readTransaction: a transaction is implicitly a read-only transaction if only getItem() is called on localStorage from within localStorage.transaction(). Agree. That is what I was trying to propose, too. I'm not sure where we disagree :). Is it just that my proposal has no concept of errors? I'm not against adding them, mainly I was trying to keep my proposal simple for purposes of discussion. Ay, there's the rub: I think the disagreement is between mutex vs. transaction semantics. So far, I think perhaps mutex has been used as shorthand for transaction. But they aren't the same. I think we all agree that a script may fail to modify localStorage in some situations (irrespective of global mutex vs. per-domain mutex). One camp, wanting mutex semantics, would prefer to pretend that the failures never happen and let scripts clean up the mess (partially-applied changes) if they do occur. This is semantically broken, IMHO. The second camp, wanting transaction semantics, explicitly acknowledge to web authors that localStorage is fallible, guarantee that modifications to localStorage are atomic, and notify scripts when modifications can't be made atomically. This is the same approach taken by Web Database. IMHO, this is much better semantically because (i) it gives web apps stronger guarantees; and (ii) it makes the discussion about global
Re: [whatwg] Surrogate pairs and character references
On 8 Sep 2009, at 23:39, I wrote: UTF-16BE Actually, endianness is immaterial. Please read this as UTF-16 instead. Sorry for the extra message. -- Øistein E. Andersen
Re: [whatwg] Web Address and its escape
On Tue, 08 Sep 2009 21:40:22 +0200, NARUSE, Yui nar...@airemix.jp wrote: First is about 4.10.16.4 URL-encoded form data. http://www.whatwg.org/specs/web-apps/current-work/#application/x-www-form-urlencoded-encoding-algorithm In this algorithm at 6.2.1, SP, *, -, ., 0 .. 9, A .. Z, _, a .. z is not escaped. But many other specs which use application/x-www-form-urlencoded refers Which other specifications? URI's unreserved. And it in RFC3986 is unreserved= ALPHA / DIGIT / - / . / _ / ~ Why ~ is escaped and * is not escaped? What do browsers do? Third is about Web addresses in HTML 5. (this spec is also this ML?) http://www.w3.org/html/wg/href/draft You want public-...@w3.org or public-h...@w3.org for that draft. -- Anne van Kesteren http://annevankesteren.nl/
Re: [whatwg] Web Address and its escape
Anne van Kesteren wrote: On Tue, 08 Sep 2009 21:40:22 +0200, NARUSE, Yui nar...@airemix.jp wrote: First is about 4.10.16.4 URL-encoded form data. http://www.whatwg.org/specs/web-apps/current-work/#application/x-www-form-urlencoded-encoding-algorithm In this algorithm at 6.2.1, SP, *, -, ., 0 .. 9, A .. Z, _, a .. z is not escaped. But many other specs which use application/x-www-form-urlencoded refers Which other specifications? Following specifications. (sorry some of them are earlier RFC) XForms 1.0 http://www.w3.org/TR/xforms/#serialize-urlencode then non-ASCII and reserved characters (as defined by [RFC 2396] as amended by subsequent documents in the IETF track) are escaped - so RFC3986 HTML 4 http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 reserved characters are escaped as described in [RFC1738] RFC1738 http://www.faqs.org/rfcs/rfc1738.html unreserved = alpha | digit | safe | extra safe = $ | - | _ | . | + extra = ! | * | ' | ( | ) | , TAG Finding refer to section 2.1 of [RFC2396]. http://www.w3.org/2001/tag/doc/whenToUseGet.html#i18n RFC2396 http://www.faqs.org/rfcs/rfc2396.html unreserved = alphanum | mark mark= - | _ | . | ! | ~ | * | ' | ( | ) WSDL 2.0 http://www.w3.org/TR/wsdl20-bindings/#_http_x-www-form-urlencoded Replacement values falling outside the range (ALPHA and DIGIT below are defined as per [IETF RFC 4234]): ALPHA | DIGIT | - | . | _ | ~ | ! | $ | | ' | ( | ) | * | + | , | ; | = | : | @, MUST be percent-encoded. URI's unreserved. And it in RFC3986 is unreserved= ALPHA / DIGIT / - / . / _ / ~ Why ~ is escaped and * is not escaped? What do browsers do? IE8 QUERY_STRING: t=+%21%5c%22%5c%23%24%25%26%27%28%29*%2b%2c-.%2f0123456789%3a%3b%3c%3d%3e...@abcdefghijklmnopqrstuvwxyz%5b%5c%5c%5d%5e_%60abcdefghijklmnopqrstuvwxyz%7b%7c%7d%7e not escaped: *...@_ Firefox 3.5 QUERY_STRING: t=+%21%5C%22%5C%23%24%25%26%27%28%29*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E not escaped: *-._ Chrome2 QUERY_STRING: t=+%21%5C%22%5C%23%24%25%26%27%28%29*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E not escaped: *-._ Opera9 QUERY_STRING: t=+%21%5C%22%5C%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E not escaped: -._ Hmm, Firefox and Chrome follow this, IE adds @, Opera removes *. If this spec use safer side, * may be also escaped. Third is about Web addresses in HTML 5. (this spec is also this ML?) http://www.w3.org/html/wg/href/draft You want public-...@w3.org or public-h...@w3.org for that draft. Thanks, I'll send it. -- NARUSE, Yui nar...@airemix.jp
Re: [whatwg] RFC: Alternatives to storage mutex for cookies and localStorage
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
Re: [whatwg] Proposal for local-storage file management
On Sep 4, 2009, at 2:38 PM, Ian Hickson wrote: Right. My point is the site can do that already, since we don't ever _stop_ the site from using the local storage area. It can prompt you for a name directly, without UA involvement. I'm sorry, I don't understand that. We must somehow be talking about completely different things. Sure, the site can call prompt() to get a name, but how can the site then create a file on the user's machine? I'm talking about the user agent responding to the site's request for local storage by putting up a platform Save As dialog to let the user choose where to put it (with a reasonable default location.) You can't store 50MB of data in a cookie. I'm talking about the entire local storage of a site here, not a 40-byte session ID or something. Then that distinction can be what is exposed in the UI to distinguish boring storage from important storage. Size isn't an indicator of importance, if that's what you mean. A 100- byte email draft could be vitally important, while 50MB of downloaded cached textures for a game isn't. Importance is an application- specific property and the UA's not going to be able to guess it. —Jens
[whatwg] Application defined locks
The recent discussion about the storage mutex for Cookies and LocalStorage got me thinking Perhaps instead of trying to build implicit locking into those features, we should give web apps the tools to manage exclusive access to shared resources. I imagine a simple lock API: window.acquireLock(name) window.releaseLock(name) acquireLock works like pthread_mutex_trylock in that it is non-blocking. it returns true if you succeeded in acquiring the lock, else it returns false. releaseLock does as its name suggests: releases the lock so that others may acquire it. Any locks acquired would be automatically released when the DOM window is destroyed or navigated cross origin. This API could also be supported by workers. The name parameter is scoped to the origin of the page. So, this locking API only works between pages in the same origin. We could also extend acquireLock to support an asynchronous callback when the lock becomes available: window.acquireLock(name, function() { /* lock acquired */ }); If the callback function is given, then upon lock acquisition, the callback function would be invoked. In this case, the return value of acquireLock is true if the function was invoked or false if the function will be invoked once the lock can be acquired. Finally, there could be a helper for scoping lock acquisition: window.acquireScopedLock(name, function() { /* lock acquired for this scope only */ }); This lock API would provide developers with the ability to indicate that their instance of the web app is the only one that should play with LocalStorage. Other instances could then know that they don't have exclusive access and could take appropriate action. This API seems like it could be used to allow LocalStorage to be usable from workers. Also, as we start developing other means of local storage (File APIs), it seems like having to again invent a reasonable implicit locking system will be a pain. Perhaps it would just be better to develop something explicit that application developers can use independent of the local storage mechanism :-) It may be the case that we want to only provide acquireScopedLock (or something like it) to enforce fine grained locking, but I think that would only force people to implement long-lived locks by setting a field in LocalStorage. That would then result in the locks not being managed by the UA, which means that they cannot be reliably cleaned up when the page closes. I think it is very important that we provide facilities to guide people away from building such ad-hoc locks on top of LocalStorage. This is why I like the explicit (non-blocking!) acquireLock and releaseLock methods. -Darin
Re: [whatwg] Application defined locks
+1, a nice refactoring of the implied locking gunk in the storage api. On Wed, Sep 9, 2009 at 10:55 AM, Darin Fisher da...@chromium.org wrote: The recent discussion about the storage mutex for Cookies and LocalStorage got me thinking Perhaps instead of trying to build implicit locking into those features, we should give web apps the tools to manage exclusive access to shared resources. I imagine a simple lock API: window.acquireLock(name) window.releaseLock(name) acquireLock works like pthread_mutex_trylock in that it is non-blocking. it returns true if you succeeded in acquiring the lock, else it returns false. releaseLock does as its name suggests: releases the lock so that others may acquire it. Any locks acquired would be automatically released when the DOM window is destroyed or navigated cross origin. This API could also be supported by workers. The name parameter is scoped to the origin of the page. So, this locking API only works between pages in the same origin. We could also extend acquireLock to support an asynchronous callback when the lock becomes available: window.acquireLock(name, function() { /* lock acquired */ }); If the callback function is given, then upon lock acquisition, the callback function would be invoked. In this case, the return value of acquireLock is true if the function was invoked or false if the function will be invoked once the lock can be acquired. Finally, there could be a helper for scoping lock acquisition: window.acquireScopedLock(name, function() { /* lock acquired for this scope only */ }); This lock API would provide developers with the ability to indicate that their instance of the web app is the only one that should play with LocalStorage. Other instances could then know that they don't have exclusive access and could take appropriate action. This API seems like it could be used to allow LocalStorage to be usable from workers. Also, as we start developing other means of local storage (File APIs), it seems like having to again invent a reasonable implicit locking system will be a pain. Perhaps it would just be better to develop something explicit that application developers can use independent of the local storage mechanism :-) It may be the case that we want to only provide acquireScopedLock (or something like it) to enforce fine grained locking, but I think that would only force people to implement long-lived locks by setting a field in LocalStorage. That would then result in the locks not being managed by the UA, which means that they cannot be reliably cleaned up when the page closes. I think it is very important that we provide facilities to guide people away from building such ad-hoc locks on top of LocalStorage. This is why I like the explicit (non-blocking!) acquireLock and releaseLock methods. -Darin
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 10:55 AM, Darin Fisherda...@chromium.org wrote: I imagine a simple lock API: window.acquireLock(name) window.releaseLock(name) I do not think it is a good idea to allow long-lived (past a stack frame) locks on the types of things we've been discussing (local storage, databases, etc). This API seems like it could be used to allow LocalStorage to be usable from workers. Also, as we start developing other means of local storage (File APIs), it seems like having to again invent a reasonable implicit locking system will be a pain. Perhaps it would just be better to develop something explicit that application developers can use independent of the local storage mechanism :-) There would presumably have to be a separate name value for each API, though, right? So we're talking about the difference between: window.acquireLock(localStorage, function() { ... }); and: window.acquireLocalStorage(function() { ... }); It doesn't seem like much of a win for reusability IMO. It may be the case that we want to only provide acquireScopedLock (or something like it) to enforce fine grained locking, but I think that would only force people to implement long-lived locks by setting a field in LocalStorage. Do you have an example of a place where we want to allow long-lived locks? - a
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 11:08 AM, Aaron Boodman a...@google.com wrote: On Wed, Sep 9, 2009 at 10:55 AM, Darin Fisherda...@chromium.org wrote: I imagine a simple lock API: window.acquireLock(name) window.releaseLock(name) I do not think it is a good idea to allow long-lived (past a stack frame) locks on the types of things we've been discussing (local storage, databases, etc). This API seems like it could be used to allow LocalStorage to be usable from workers. Also, as we start developing other means of local storage (File APIs), it seems like having to again invent a reasonable implicit locking system will be a pain. Perhaps it would just be better to develop something explicit that application developers can use independent of the local storage mechanism :-) There would presumably have to be a separate name value for each API, though, right? So we're talking about the difference between: window.acquireLock(localStorage, function() { ... }); and: window.acquireLocalStorage(function() { ... }); It doesn't seem like much of a win for reusability IMO. I wanted to leave it up to the app developer to choose the name so that they could define how the lock is interpreted. For example, they might want to partition the keyspace for local storage and have separate locks for separate keys. Or, they might want to have a single lock that is inclusive of several storage mechanisms: LocalStorage and FileAPI. Besides, once we have an explicit locking API, why not just be generic and give it a name divorced from LocalStorage or any kind of storage features for that matter? Locking can be useful to other applications that do not even use local storage... It may be the case that we want to only provide acquireScopedLock (or something like it) to enforce fine grained locking, but I think that would only force people to implement long-lived locks by setting a field in LocalStorage. Do you have an example of a place where we want to allow long-lived locks? It is important to think of these differently from normal mutexes that you might program with in C++. Maybe I should have used the term flag instead of lock ;-) You might use a long lived lock to indicate that you are the instance responsible for X. I can imagine applications where there could be a master / slave relationships between the instances. One instance is the master and the rest are the slaves. If we only had fine grained locking, then we are saying that we want simulaneous instances of the same web app to be able to stop on each others data in LocalStorage. Instead, a web app developer might want to disable LocalStorage features in all but the first instance of their web app. The problem is that your state is held not just in LocalStorage but also in JS variables, the DOM, and perhaps in session state held by the server. It is easy for LocalStorage to get corrupted even with proper fine-grained locking. You still need a way to have a big flag that says... hey, i'm the one messing with LocalStorage. A good example is the browser's profile directory. Chrome and Firefox both only allow one instance of the app per profile. A long-lived lock is held to support such behavior. I suspect there is some overlap with my proposal and shared workers. Perhaps what I am trying to accomplish here could even be implemented on top of shared workers, although using shared workers to achieve mutual exclusion locks seems rather heavyweight. -Darin
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 11:23 AM, Darin Fisherda...@chromium.org wrote: On Wed, Sep 9, 2009 at 11:08 AM, Aaron Boodman a...@google.com wrote: There would presumably have to be a separate name value for each API, though, right? So we're talking about the difference between: window.acquireLock(localStorage, function() { ... }); and: window.acquireLocalStorage(function() { ... }); It doesn't seem like much of a win for reusability IMO. I wanted to leave it up to the app developer to choose the name so that they could define how the lock is interpreted. For example, they might want to partition the keyspace for local storage and have separate locks for separate keys. Or, they might want to have a single lock that is inclusive of several storage mechanisms: LocalStorage and FileAPI. Besides, once we have an explicit locking API, why not just be generic and give it a name divorced from LocalStorage or any kind of storage features for that matter? Locking can be useful to other applications that do not even use local storage... I see. So you are suggesting the localStorage could have zero concurrency guarantees and it is simply up to the developer to arrange things themselves using this new primitive. That is an interesting idea. You're right that it overlaps with the ideas that inspired shared workers, and the global script proposal. - a
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 11:30 AM, Aaron Boodman a...@google.com wrote: On Wed, Sep 9, 2009 at 11:23 AM, Darin Fisherda...@chromium.org wrote: On Wed, Sep 9, 2009 at 11:08 AM, Aaron Boodman a...@google.com wrote: There would presumably have to be a separate name value for each API, though, right? So we're talking about the difference between: window.acquireLock(localStorage, function() { ... }); and: window.acquireLocalStorage(function() { ... }); It doesn't seem like much of a win for reusability IMO. I wanted to leave it up to the app developer to choose the name so that they could define how the lock is interpreted. For example, they might want to partition the keyspace for local storage and have separate locks for separate keys. Or, they might want to have a single lock that is inclusive of several storage mechanisms: LocalStorage and FileAPI. Besides, once we have an explicit locking API, why not just be generic and give it a name divorced from LocalStorage or any kind of storage features for that matter? Locking can be useful to other applications that do not even use local storage... I see. So you are suggesting the localStorage could have zero concurrency guarantees and it is simply up to the developer to arrange things themselves using this new primitive. Yes, exactly. Sorry for not making this clear. I believe implicit locking for LocalStorage (and the implicit unlocking) is going to yield something very confusing and hard to implement well. The potential for dead locks when you fail to implicitly unlock properly scares me. -Darin That is an interesting idea. You're right that it overlaps with the ideas that inspired shared workers, and the global script proposal. - a
Re: [whatwg] Application defined locks
On Sep 9, 2009, at 10:55 AM, Darin Fisher wrote: The recent discussion about the storage mutex for Cookies and LocalStorage got me thinking Perhaps instead of trying to build implicit locking into those features, we should give web apps the tools to manage exclusive access to shared resources. I'm really hesitant to expose explicit locking to the Web platform. Mutexes are incredibly hard to program with correctly, and we will surely end up with stuck locks, race conditions, livelocks, and so forth. For Workers I was happy that we managed to avoid any locking primitives by using a message-passing model, but explicit mutexes would ruin that. - Maciej I imagine a simple lock API: window.acquireLock(name) window.releaseLock(name) acquireLock works like pthread_mutex_trylock in that it is non- blocking. it returns true if you succeeded in acquiring the lock, else it returns false. releaseLock does as its name suggests: releases the lock so that others may acquire it. Any locks acquired would be automatically released when the DOM window is destroyed or navigated cross origin. This API could also be supported by workers. The name parameter is scoped to the origin of the page. So, this locking API only works between pages in the same origin. We could also extend acquireLock to support an asynchronous callback when the lock becomes available: window.acquireLock(name, function() { /* lock acquired */ }); If the callback function is given, then upon lock acquisition, the callback function would be invoked. In this case, the return value of acquireLock is true if the function was invoked or false if the function will be invoked once the lock can be acquired. Finally, there could be a helper for scoping lock acquisition: window.acquireScopedLock(name, function() { /* lock acquired for this scope only */ }); This lock API would provide developers with the ability to indicate that their instance of the web app is the only one that should play with LocalStorage. Other instances could then know that they don't have exclusive access and could take appropriate action. This API seems like it could be used to allow LocalStorage to be usable from workers. Also, as we start developing other means of local storage (File APIs), it seems like having to again invent a reasonable implicit locking system will be a pain. Perhaps it would just be better to develop something explicit that application developers can use independent of the local storage mechanism :-) It may be the case that we want to only provide acquireScopedLock (or something like it) to enforce fine grained locking, but I think that would only force people to implement long-lived locks by setting a field in LocalStorage. That would then result in the locks not being managed by the UA, which means that they cannot be reliably cleaned up when the page closes. I think it is very important that we provide facilities to guide people away from building such ad-hoc locks on top of LocalStorage. This is why I like the explicit (non-blocking!) acquireLock and releaseLock methods. -Darin
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 3:37 PM, Maciej Stachowiak m...@apple.com wrote: On Sep 9, 2009, at 10:55 AM, Darin Fisher wrote: The recent discussion about the storage mutex for Cookies and LocalStorage got me thinking Perhaps instead of trying to build implicit locking into those features, we should give web apps the tools to manage exclusive access to shared resources. I'm really hesitant to expose explicit locking to the Web platform. Mutexes are incredibly hard to program with correctly, and we will surely end up with stuck locks, race conditions, livelocks, and so forth. For Workers I was happy that we managed to avoid any locking primitives by using a message-passing model, but explicit mutexes would ruin that. - Maciej Note: I probably made a mistake calling these locks since they do not work like normal mutexes. You can only wait for one of these locks asynchronously. There is no synchronous blocking, which avoids most of the problems you mention. Also, the locks are cleared when the page is destroyed or navigated to another domain, so you lose the problem of stuck locks. What motivated this was that I wanted the ability to simulate the database transaction model. Since we support that, we might as well support a similar system that is independent of a particular storage mechanism. Seems reasonable to me. Alternatively, if we had a way to set a value in local storage and read the value that was there, then a web page could implement a flag to indicate mutual exclusion. Someone interested in acquiring a flag could wait for a storage event to indicate that the flag was cleared. However, what is missing is that there isn't a way for the flag to be auto-cleared when the DOM window is closed or navigated to another domain. -Darin I imagine a simple lock API: window.acquireLock(name) window.releaseLock(name) acquireLock works like pthread_mutex_trylock in that it is non-blocking. it returns true if you succeeded in acquiring the lock, else it returns false. releaseLock does as its name suggests: releases the lock so that others may acquire it. Any locks acquired would be automatically released when the DOM window is destroyed or navigated cross origin. This API could also be supported by workers. The name parameter is scoped to the origin of the page. So, this locking API only works between pages in the same origin. We could also extend acquireLock to support an asynchronous callback when the lock becomes available: window.acquireLock(name, function() { /* lock acquired */ }); If the callback function is given, then upon lock acquisition, the callback function would be invoked. In this case, the return value of acquireLock is true if the function was invoked or false if the function will be invoked once the lock can be acquired. Finally, there could be a helper for scoping lock acquisition: window.acquireScopedLock(name, function() { /* lock acquired for this scope only */ }); This lock API would provide developers with the ability to indicate that their instance of the web app is the only one that should play with LocalStorage. Other instances could then know that they don't have exclusive access and could take appropriate action. This API seems like it could be used to allow LocalStorage to be usable from workers. Also, as we start developing other means of local storage (File APIs), it seems like having to again invent a reasonable implicit locking system will be a pain. Perhaps it would just be better to develop something explicit that application developers can use independent of the local storage mechanism :-) It may be the case that we want to only provide acquireScopedLock (or something like it) to enforce fine grained locking, but I think that would only force people to implement long-lived locks by setting a field in LocalStorage. That would then result in the locks not being managed by the UA, which means that they cannot be reliably cleaned up when the page closes. I think it is very important that we provide facilities to guide people away from building such ad-hoc locks on top of LocalStorage. This is why I like the explicit (non-blocking!) acquireLock and releaseLock methods. -Darin
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 6:37 AM, Darin Fisher da...@chromium.org wrote: Yes, exactly. Sorry for not making this clear. I believe implicit locking for LocalStorage (and the implicit unlocking) is going to yield something very confusing and hard to implement well. The potential for dead locks when you fail to implicitly unlock properly scares me You mean when the browser implementation has a bug and fails to implicitly unlock? Giving Web authors the crappy race-prone and deadlock-prone locking programming model scares *me*. Yes, your acquireLock can't get you into a hard deadlock, strictly speaking, but you can still effectively deadlock your application by waiting for a lock to become available that never can. Also, how many authors will forget to test the result of acquireLock (because they're used to other locking APIs that block) and find that things are OK in their testing? I think we should be willing to accept a very high implementation burden on browser vendors in exchange for minimizing the burden on Web authors. Now, if we find that authors are needing to build explicit locks using localStorage, we should figure out their use-cases and see what a better solution for those use-cases might be, instead of giving them a more convenient way to endanger themselves. Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]
Re: [whatwg] Application defined locks
On 9/10/09 2:24 AM, Robert O'Callahan wrote: On Thu, Sep 10, 2009 at 6:37 AM, Darin Fisher da...@chromium.org mailto:da...@chromium.org wrote: Yes, exactly. Sorry for not making this clear. I believe implicit locking for LocalStorage (and the implicit unlocking) is going to yield something very confusing and hard to implement well. The potential for dead locks when you fail to implicitly unlock properly scares me You mean when the browser implementation has a bug and fails to implicitly unlock? Giving Web authors the crappy race-prone and deadlock-prone locking programming model scares *me*. Yes, your acquireLock can't get you into a hard deadlock, strictly speaking, but you can still effectively deadlock your application by waiting for a lock to become available that never can. Also, how many authors will forget to test the result of acquireLock (because they're used to other locking APIs that block) and find that things are OK in their testing? If you're concerned about that, make acquireLock to throw an exception. Authors sure will notice that things aren't quite right, if the flag isn't acquired. And if the acquireLock(flag, callback) approach is used, it is harder to make the mistake to not check whether the flag was really got. As you said on IRC, perhaps there should be a way to acquire many flags at once and then call the callback. -Olli
Re: [whatwg] Application defined locks
In general this seems like a pretty interesting idea. It definitely would be nice to completely abstract away all concepts of concurrency from web developers, but some of our solutions thus far (message passing, async interfaces, etc) have not been terribly appreciated by developers either. The GlobalScript proposal is a good example: to us, shared workers were an adequate solution, but in practice the lack of shared state is very difficult for some developers to work around. Possibly even more difficult than dealing with some levels of concurrency. I think it'd be interesting to introduce this as an experimental API and see what web developers do with it. As for the idea of a sync API: What if some library/framework and the embedding page use these flags/locks? I know you can't actually deadlock with this API, but I worry some developers will just do |while(!acquireLock(flag)) {}| which could lead to deadlocks. Only allowing an async API would fix this, but developers have typically not liked async APIs. Here's another idea that I think is actually kind of cool: What if we kept track of locking precedence (i.e. the graph of which locks have been taken while other locks were held) and threw an exception if any lock was ever taken in a way that violated the graph. In other words, we wouldn't make the developer tell us the locking precedence, and we wouldn't wait until you hit an actual deadlock. Instead we would look for the first call site that _could_ have deadlocked. A long time ago, I was working on a project that had some deadlock problems. We implemented exactly this and it worked pretty well. On Thu, Sep 10, 2009 at 9:22 AM, Olli Pettay olli.pet...@helsinki.fiwrote: On 9/10/09 2:24 AM, Robert O'Callahan wrote: On Thu, Sep 10, 2009 at 6:37 AM, Darin Fisher da...@chromium.org mailto:da...@chromium.org wrote: Yes, exactly. Sorry for not making this clear. I believe implicit locking for LocalStorage (and the implicit unlocking) is going to yield something very confusing and hard to implement well. The potential for dead locks when you fail to implicitly unlock properly scares me You mean when the browser implementation has a bug and fails to implicitly unlock? Giving Web authors the crappy race-prone and deadlock-prone locking programming model scares *me*. Yes, your acquireLock can't get you into a hard deadlock, strictly speaking, but you can still effectively deadlock your application by waiting for a lock to become available that never can. Also, how many authors will forget to test the result of acquireLock (because they're used to other locking APIs that block) and find that things are OK in their testing? If you're concerned about that, make acquireLock to throw an exception. Authors sure will notice that things aren't quite right, if the flag isn't acquired. And if the acquireLock(flag, callback) approach is used, it is harder to make the mistake to not check whether the flag was really got. This seems like a good idea. As you said on IRC, perhaps there should be a way to acquire many flags at once and then call the callback. I like this idea as well.
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 11:30 AM, Aaron Boodmana...@google.com wrote: I see. So you are suggesting the localStorage could have zero concurrency guarantees and it is simply up to the developer to arrange things themselves using this new primitive. That is an interesting idea. You're right that it overlaps with the ideas that inspired shared workers, and the global script proposal. Ok, after thinking about this for a day, I'm going to say I think this is a very cool idea, and a worthwhile addition, but I don't think it should substitute for having the local storage API work correctly by default. The web platform is supposed to work for developers of all experience levels. If we make local storage have no concurrency guarantees, it will seem like it works in the overwhelming majority of cases. It will work in all SELUAs, and it will only NOT work in MELUAs in cases that are basically impossible to test, let alone see during development. We have tried hard with the design of the web platform to avoid these sort of untestable non-deterministic scenarios, and I think it is to the overall value of the platform to continue this. Therefore, my position continues to be that to access local storage, there should be an API that asynchronously acquires exclusive access to storage. - a
Re: [whatwg] RFC: Alternatives to storage mutex for cookies and localStorage
On Thu, Sep 10, 2009 at 1:59 AM, Chris Jones cjo...@mozilla.com wrote: Jeremy Orlow wrote: 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.) The way it works right now is that an exception is thrown and that's it. I think it'd be perfectly acceptable for the behavior to remain, even if it's inside a transaction. In other words, I don't think the transaction necessarily needs to stop or anything. I think most app developers will want to explicitly handle out of space errors (they're not just going to go away on their own), but probably won't want to explicitly deal with transient errors (like what you can see with optimistic transactions). I don't think quota errors should be grouped in with any atomicity guarantees, in other words. Are there any other examples of failures you can have within a pessimistic transaction?
Re: [whatwg] Application defined locks
If this feature existed, we likely would have used it for offline Gmail to coordinate which instance of the app (page with gmail in it) should be responsible for sync'ing the local database with the mail service. In the absence of a feature like this, instead we used the local database itself to register which page was the 'syncagent'. This involved periodically updating the db by the syncagent, and periodic polling by the would be syncagents waiting to possibly take over. Much ugliness. var isSyncAgent = false; window.acquireFlag(syncAgency, function() { isSyncAgent = true; }); Much nicer. On Wed, Sep 9, 2009 at 7:02 PM, Maciej Stachowiak m...@apple.com wrote: On Sep 9, 2009, at 6:33 PM, Jeremy Orlow wrote: In general this seems like a pretty interesting idea. It definitely would be nice to completely abstract away all concepts of concurrency from web developers, but some of our solutions thus far (message passing, async interfaces, etc) have not been terribly appreciated by developers either. The GlobalScript proposal is a good example: to us, shared workers were an adequate solution, but in practice the lack of shared state is very difficult for some developers to work around. Possibly even more difficult than dealing with some levels of concurrency. I think it'd be interesting to introduce this as an experimental API and see what web developers do with it. I think it's predictable that it will be used in badly wrong ways without implementing it. Explicit application-managed locking is a massive failure as a mechanism for managing concurrency. As for the idea of a sync API: What if some library/framework and the embedding page use these flags/locks? I know you can't actually deadlock with this API, but I worry some developers will just do |while(!acquireLock(flag)) {}| which could lead to deadlocks. Only allowing an async API would fix this, but developers have typically not liked async APIs. If we want to go async, then I'd rather have an asynchronous way to acquire an *actual* lock on the resource (as with the LocalStorage async transaction proposal), than an async advisory locking model. Having both asynchronicity *and* advisory locks seems like the worst of both worlds. On the other hand, if we offer only the equivalent of tryLock() and not a blocking lock(), it's almost certain Web apps will build spin locks in the way you describe, leading to wasteful CPU usage, bad performance, and the possibility of deadlocks. Here's another idea that I think is actually kind of cool: What if we kept track of locking precedence (i.e. the graph of which locks have been taken while other locks were held) and threw an exception if any lock was ever taken in a way that violated the graph. In other words, we wouldn't make the developer tell us the locking precedence, and we wouldn't wait until you hit an actual deadlock. Instead we would look for the first call site that _could_ have deadlocked. A long time ago, I was working on a project that had some deadlock problems. We implemented exactly this and it worked pretty well. This seems like a very challenging programming model for little gain. If the locks are purely advisory, they do not prevent race conditions, but a discipline to prevent deadlocks will still make them very hard to use. Note also that the possibility of synchronous cross-site code execution would require a lock precedence graph to be cross-site to really prevent deadlocks, but it would be impossible for a Web application to guarantee anything about lock order with respect to Web apps in different origins. The other possibility is to drop all locks in the case of synchronous cross-origin code execution, but then these advisory locks would not even be useful for preventing race conditions. Locking is broken - just don't do it. Regards, Maciej On Thu, Sep 10, 2009 at 9:22 AM, Olli Pettay olli.pet...@helsinki.fiwrote: On 9/10/09 2:24 AM, Robert O'Callahan wrote: On Thu, Sep 10, 2009 at 6:37 AM, Darin Fisher da...@chromium.org mailto:da...@chromium.org wrote: Yes, exactly. Sorry for not making this clear. I believe implicit locking for LocalStorage (and the implicit unlocking) is going to yield something very confusing and hard to implement well. The potential for dead locks when you fail to implicitly unlock properly scares me You mean when the browser implementation has a bug and fails to implicitly unlock? Giving Web authors the crappy race-prone and deadlock-prone locking programming model scares *me*. Yes, your acquireLock can't get you into a hard deadlock, strictly speaking, but you can still effectively deadlock your application by waiting for a lock to become available that never can. Also, how many authors will forget to test the result of acquireLock (because they're used to other locking APIs that block) and find that things are OK in their testing? If you're
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 1:33 PM, Jeremy Orlow jor...@chromium.org wrote: In general this seems like a pretty interesting idea. It definitely would be nice to completely abstract away all concepts of concurrency from web developers, but some of our solutions thus far (message passing, async interfaces, etc) have not been terribly appreciated by developers either. You have to be careful with developer feedback. Developers inexperienced with pthread-style threads-and-locks typically like the model, since it's a simple abstraction that *superficially* appears to map easily onto their existing sequential code (e.g. because they can carry on using lots of shared state). It's not until you get more experienced with it in a large system that you really feel the pain, and appreciate why an apparently more restrictive model might work better. Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 2:38 PM, Michael Nordman micha...@google.comwrote: If this feature existed, we likely would have used it for offline Gmail to coordinate which instance of the app (page with gmail in it) should be responsible for sync'ing the local database with the mail service. In the absence of a feature like this, instead we used the local database itself to register which page was the 'syncagent'. This involved periodically updating the db by the syncagent, and periodic polling by the would be syncagents waiting to possibly take over. Much ugliness. var isSyncAgent = false; window.acquireFlag(syncAgency, function() { isSyncAgent = true; }); Much nicer. How do you deal with the user closing the syncagent while other app instances remain open? Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 4:24 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 6:37 AM, Darin Fisher da...@chromium.org wrote: Yes, exactly. Sorry for not making this clear. I believe implicit locking for LocalStorage (and the implicit unlocking) is going to yield something very confusing and hard to implement well. The potential for dead locks when you fail to implicitly unlock properly scares me You mean when the browser implementation has a bug and fails to implicitly unlock? What concerns me are the cases where synchronous events (e.g., resizing an iframe) can cause script to execute in another domain. As spec'd, there is a potential dead lock with the storage mutex. We must carefully unlock in situations like this. However, such unlocking will appear quite mysterious to users, so much so that I question the value of the implicit storage mutex. That led me down this path of imagining a more explicit locking mechanism that would give the app control over how local storage is protected. I agree that explicit locking can be a big dangerous hammer, but that's why I tried to soften it by removing blocking behavior. Giving Web authors the crappy race-prone and deadlock-prone locking programming model scares *me*. Me too. I don't believe that I'm proposing such an API. Yes, your acquireLock can't get you into a hard deadlock, strictly speaking, but you can still effectively deadlock your application by waiting for a lock to become available that never can. Sure, but at least the thread of execution isn't blocked, and the user can recover by closing the tab or what have you. By the way, you can already pretty much create my acquireLock / releaseLock API on top of SharedWorkers today, but in a slightly crappier way. Are SharedWorkers problematic because of this? I don't think so. Also, how many authors will forget to test the result of acquireLock (because they're used to other locking APIs that block) and find that things are OK in their testing? Perhaps the API could be different. Perhaps the name lock is part of the problem. I think we should be willing to accept a very high implementation burden on browser vendors in exchange for minimizing the burden on Web authors. Yes, I wholeheartedly agree. Note: my concern is that there is no good implementation for the storage mutex. Implicitly dropping it at weird times is not a good answer. -Darin
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 3:53 PM, Darin Fisher da...@chromium.org wrote: What concerns me are the cases where synchronous events (e.g., resizing an iframe) can cause script to execute in another domain. As spec'd, there is a potential dead lock with the storage mutex. We must carefully unlock in situations like this. However, such unlocking will appear quite mysterious to users, so much so that I question the value of the implicit storage mutex. Right now I'm not sure how big a problem this actually is. The resize event for a document in a frame can surely be dispatched asynchronously so no unlocking is required. I would like to have a much better idea of how many places absolutely must release the storage mutex before deciding that approach is unworkable. Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 9:07 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 3:53 PM, Darin Fisher da...@chromium.org wrote: What concerns me are the cases where synchronous events (e.g., resizing an iframe) can cause script to execute in another domain. As spec'd, there is a potential dead lock with the storage mutex. We must carefully unlock in situations like this. However, such unlocking will appear quite mysterious to users, so much so that I question the value of the implicit storage mutex. Right now I'm not sure how big a problem this actually is. The resize event for a document in a frame can surely be dispatched asynchronously so no unlocking is required. I would like to have a much better idea of how many places absolutely must release the storage mutex before deciding that approach is unworkable. Rob What about navigating an iframe to a reference fragment, which could trigger a scroll event? The scrolling has to be done synchronously for compat with the web. -Darin
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 6:46 PM, Aaron Boodman a...@google.com wrote: On Wed, Sep 9, 2009 at 11:30 AM, Aaron Boodmana...@google.com wrote: I see. So you are suggesting the localStorage could have zero concurrency guarantees and it is simply up to the developer to arrange things themselves using this new primitive. That is an interesting idea. You're right that it overlaps with the ideas that inspired shared workers, and the global script proposal. Ok, after thinking about this for a day, I'm going to say I think this is a very cool idea, and a worthwhile addition, but I don't think it should substitute for having the local storage API work correctly by default. The web platform is supposed to work for developers of all experience levels. If we make local storage have no concurrency guarantees, it will seem like it works in the overwhelming majority of cases. It will work in all SELUAs, and it will only NOT work in MELUAs in cases that are basically impossible to test, let alone see during development. We have tried hard with the design of the web platform to avoid these sort of untestable non-deterministic scenarios, and I think it is to the overall value of the platform to continue this. Therefore, my position continues to be that to access local storage, there should be an API that asynchronously acquires exclusive access to storage. - a Yeah, if you had to call an API that asynchronously acquires exclusive access to storage, then I believe that would nicely address most of the issues. It is the solution we have for database transactions. I say most because I'm not sure that it eliminates the need to drop the storage mutex in the showModalDialog case. If I call showModalDialog from within a database transaction, and then showModalDialog tries to create another database transaction, should I expect that the transaction can be started within the nested run loop of the modal dialog? If not, then it may cause the app to get confused and never allow the dialog to be closed (e.g., perhaps the close action is predicated on a database query.) Nested loops suck. showModalDialog sucks :-) -Darin
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 1:13 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 6:46 PM, Aaron Boodman a...@google.com wrote: On Wed, Sep 9, 2009 at 11:30 AM, Aaron Boodmana...@google.com wrote: I see. So you are suggesting the localStorage could have zero concurrency guarantees and it is simply up to the developer to arrange things themselves using this new primitive. That is an interesting idea. You're right that it overlaps with the ideas that inspired shared workers, and the global script proposal. Ok, after thinking about this for a day, I'm going to say I think this is a very cool idea, and a worthwhile addition, but I don't think it should substitute for having the local storage API work correctly by default. The web platform is supposed to work for developers of all experience levels. If we make local storage have no concurrency guarantees, it will seem like it works in the overwhelming majority of cases. It will work in all SELUAs, and it will only NOT work in MELUAs in cases that are basically impossible to test, let alone see during development. We have tried hard with the design of the web platform to avoid these sort of untestable non-deterministic scenarios, and I think it is to the overall value of the platform to continue this. Therefore, my position continues to be that to access local storage, there should be an API that asynchronously acquires exclusive access to storage. - a Yeah, if you had to call an API that asynchronously acquires exclusive access to storage, then I believe that would nicely address most of the issues. It is the solution we have for database transactions. I say most because I'm not sure that it eliminates the need to drop the storage mutex in the showModalDialog case. If I call showModalDialog from within a database transaction, and then showModalDialog tries to create another database transaction, should I expect that the transaction can be started within the nested run loop of the modal dialog? If not, then it may cause the app to get confused and never allow the dialog to be closed (e.g., perhaps the close action is predicated on a database query.) Nested loops suck. showModalDialog sucks :-) We could just disallow showModalDialog and any other trouble APIs like that during localStorage and database transactions. Doing so seems better than silently dropping transactional semantics.
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 4:11 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 9:07 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 3:53 PM, Darin Fisher da...@chromium.org wrote: What concerns me are the cases where synchronous events (e.g., resizing an iframe) can cause script to execute in another domain. As spec'd, there is a potential dead lock with the storage mutex. We must carefully unlock in situations like this. However, such unlocking will appear quite mysterious to users, so much so that I question the value of the implicit storage mutex. Right now I'm not sure how big a problem this actually is. The resize event for a document in a frame can surely be dispatched asynchronously so no unlocking is required. I would like to have a much better idea of how many places absolutely must release the storage mutex before deciding that approach is unworkable. Rob What about navigating an iframe to a reference fragment, which could trigger a scroll event? The scrolling has to be done synchronously for compat with the web. The scrolling itself may have to be synchronous, at least as far as updating scrollLeft/scrollTop if not visually ... but in this case the script execution in the frame would be an onscroll event handler, right? That's asynchronous in Gecko. Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 9:27 PM, Jeremy Orlow jor...@chromium.org wrote: On Thu, Sep 10, 2009 at 1:13 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 6:46 PM, Aaron Boodman a...@google.com wrote: On Wed, Sep 9, 2009 at 11:30 AM, Aaron Boodmana...@google.com wrote: I see. So you are suggesting the localStorage could have zero concurrency guarantees and it is simply up to the developer to arrange things themselves using this new primitive. That is an interesting idea. You're right that it overlaps with the ideas that inspired shared workers, and the global script proposal. Ok, after thinking about this for a day, I'm going to say I think this is a very cool idea, and a worthwhile addition, but I don't think it should substitute for having the local storage API work correctly by default. The web platform is supposed to work for developers of all experience levels. If we make local storage have no concurrency guarantees, it will seem like it works in the overwhelming majority of cases. It will work in all SELUAs, and it will only NOT work in MELUAs in cases that are basically impossible to test, let alone see during development. We have tried hard with the design of the web platform to avoid these sort of untestable non-deterministic scenarios, and I think it is to the overall value of the platform to continue this. Therefore, my position continues to be that to access local storage, there should be an API that asynchronously acquires exclusive access to storage. - a Yeah, if you had to call an API that asynchronously acquires exclusive access to storage, then I believe that would nicely address most of the issues. It is the solution we have for database transactions. I say most because I'm not sure that it eliminates the need to drop the storage mutex in the showModalDialog case. If I call showModalDialog from within a database transaction, and then showModalDialog tries to create another database transaction, should I expect that the transaction can be started within the nested run loop of the modal dialog? If not, then it may cause the app to get confused and never allow the dialog to be closed (e.g., perhaps the close action is predicated on a database query.) Nested loops suck. showModalDialog sucks :-) We could just disallow showModalDialog and any other trouble APIs like that during localStorage and database transactions. Doing so seems better than silently dropping transactional semantics. It may not be so easy to disallow showModalDialog. Imagine if you script a plugin inside the transaction, and before returning, the plugin scripts another window, where it calls showModalDialog. There could have been a process hop there. -Darin
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 4:37 PM, Darin Fisher da...@chromium.org wrote: Imagine if you script a plugin inside the transaction, and before returning, the plugin scripts another window, I'm curious, how common is that anyway? Can we just tell plugins not to do that, and abort any plugin that tries? Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 1:37 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 9:27 PM, Jeremy Orlow jor...@chromium.org wrote: On Thu, Sep 10, 2009 at 1:13 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 6:46 PM, Aaron Boodman a...@google.com wrote: On Wed, Sep 9, 2009 at 11:30 AM, Aaron Boodmana...@google.com wrote: I see. So you are suggesting the localStorage could have zero concurrency guarantees and it is simply up to the developer to arrange things themselves using this new primitive. That is an interesting idea. You're right that it overlaps with the ideas that inspired shared workers, and the global script proposal. Ok, after thinking about this for a day, I'm going to say I think this is a very cool idea, and a worthwhile addition, but I don't think it should substitute for having the local storage API work correctly by default. The web platform is supposed to work for developers of all experience levels. If we make local storage have no concurrency guarantees, it will seem like it works in the overwhelming majority of cases. It will work in all SELUAs, and it will only NOT work in MELUAs in cases that are basically impossible to test, let alone see during development. We have tried hard with the design of the web platform to avoid these sort of untestable non-deterministic scenarios, and I think it is to the overall value of the platform to continue this. Therefore, my position continues to be that to access local storage, there should be an API that asynchronously acquires exclusive access to storage. - a Yeah, if you had to call an API that asynchronously acquires exclusive access to storage, then I believe that would nicely address most of the issues. It is the solution we have for database transactions. I say most because I'm not sure that it eliminates the need to drop the storage mutex in the showModalDialog case. If I call showModalDialog from within a database transaction, and then showModalDialog tries to create another database transaction, should I expect that the transaction can be started within the nested run loop of the modal dialog? If not, then it may cause the app to get confused and never allow the dialog to be closed (e.g., perhaps the close action is predicated on a database query.) Nested loops suck. showModalDialog sucks :-) We could just disallow showModalDialog and any other trouble APIs like that during localStorage and database transactions. Doing so seems better than silently dropping transactional semantics. It may not be so easy to disallow showModalDialog. Imagine if you script a plugin inside the transaction, and before returning, the plugin scripts another window, where it calls showModalDialog. There could have been a process hop there. I'd count plugins as trouble APIs. :-)
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 9:28 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 4:11 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 9:07 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 3:53 PM, Darin Fisher da...@chromium.orgwrote: What concerns me are the cases where synchronous events (e.g., resizing an iframe) can cause script to execute in another domain. As spec'd, there is a potential dead lock with the storage mutex. We must carefully unlock in situations like this. However, such unlocking will appear quite mysterious to users, so much so that I question the value of the implicit storage mutex. Right now I'm not sure how big a problem this actually is. The resize event for a document in a frame can surely be dispatched asynchronously so no unlocking is required. I would like to have a much better idea of how many places absolutely must release the storage mutex before deciding that approach is unworkable. Rob What about navigating an iframe to a reference fragment, which could trigger a scroll event? The scrolling has to be done synchronously for compat with the web. The scrolling itself may have to be synchronous, at least as far as updating scrollLeft/scrollTop if not visually ... but in this case the script execution in the frame would be an onscroll event handler, right? That's asynchronous in Gecko. Interesting. Gecko seems to be the odd man out there. Both MSHTML and WebKit dispatch the onscroll event handler synchronously. Maybe my assertion about that being important for web compat was overreaching. At any rate, this should at least give us pause. There could be other ways in which script execution across domains could be nested :-/ -Darin
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 9:43 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 4:37 PM, Darin Fisher da...@chromium.org wrote: Imagine if you script a plugin inside the transaction, and before returning, the plugin scripts another window, I'm curious, how common is that anyway? Can we just tell plugins not to do that, and abort any plugin that tries? I don't know. Are you saying that a plugin should not be able to invoke a function that may trigger showModalDialog? The code that calls showModalDialog may be far removed / unrelated to the plugin script. It may just be an unfortunate side effect of invoking a method on a DOM window. -Darin
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 9:13 PM, Darin Fisherda...@chromium.org wrote: If I call showModalDialog from within a database transaction, and then showModalDialog tries to create another database transaction, should I expect that the transaction can be started within the nested run loop of the modal dialog? By definition, in that case, the second transaction would not start until the dialog was closed. If not, then it may cause the app to get confused and never allow the dialog to be closed (e.g., perhaps the close action is predicated on a database query.) That is true, but it is an easily reproducible, deterministic application bug. It also doesn't destabilize the environment -- by making tabs or dialogs unclosable or whatever. Nested loops suck. showModalDialog sucks :-) Fair enough. - a
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 10:01 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 4:57 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 9:43 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 4:37 PM, Darin Fisher da...@chromium.orgwrote: Imagine if you script a plugin inside the transaction, and before returning, the plugin scripts another window, I'm curious, how common is that anyway? Can we just tell plugins not to do that, and abort any plugin that tries? I don't know. Are you saying that a plugin should not be able to invoke a function that may trigger showModalDialog? The code that calls showModalDialog may be far removed / unrelated to the plugin script. It may just be an unfortunate side effect of invoking a method on a DOM window. No, I'm saying when a script in window A calls into a plugin, the plugin should not be allowed to synchronously call back out to script in window B. I realize that is currently allowed (i.e. not forbidden by anything in NPAPI), but do plugins actually do it in practice? Yes, this is something that we have observed real plugins doing. It is easy for a plugin to have references to multiple windows. They also like to script the page in response to random NPP_ calls, like NPP_HandleEvent and NPP_SetWindow, which perhaps is not too surprising. NPP_HandleEvent generally corresponds to input processing and painting for windowless plugins, and NPP_SetWindow corresponds to a resize event. -Darin
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 10:03 PM, Aaron Boodman a...@google.com wrote: On Wed, Sep 9, 2009 at 9:13 PM, Darin Fisherda...@chromium.org wrote: If I call showModalDialog from within a database transaction, and then showModalDialog tries to create another database transaction, should I expect that the transaction can be started within the nested run loop of the modal dialog? By definition, in that case, the second transaction would not start until the dialog was closed. Good, but If not, then it may cause the app to get confused and never allow the dialog to be closed (e.g., perhaps the close action is predicated on a database query.) That is true, but it is an easily reproducible, deterministic application bug. It also doesn't destabilize the environment -- by making tabs or dialogs unclosable or whatever. Well, the problem is that the creator of the transaction and the code associated with the showModalDialog call may not be related. The showModalDialog code might normally be used outside the context of a transaction, in which case the code would normally work fine. However, if triggered from within a transaction, the dialog would be stuck. -Darin
Re: [whatwg] Application defined locks
On Thu, Sep 10, 2009 at 4:57 PM, Darin Fisher da...@chromium.org wrote: On Wed, Sep 9, 2009 at 9:43 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Thu, Sep 10, 2009 at 4:37 PM, Darin Fisher da...@chromium.org wrote: Imagine if you script a plugin inside the transaction, and before returning, the plugin scripts another window, I'm curious, how common is that anyway? Can we just tell plugins not to do that, and abort any plugin that tries? I don't know. Are you saying that a plugin should not be able to invoke a function that may trigger showModalDialog? The code that calls showModalDialog may be far removed / unrelated to the plugin script. It may just be an unfortunate side effect of invoking a method on a DOM window. No, I'm saying when a script in window A calls into a plugin, the plugin should not be allowed to synchronously call back out to script in window B. I realize that is currently allowed (i.e. not forbidden by anything in NPAPI), but do plugins actually do it in practice? Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]
Re: [whatwg] Application defined locks
On Wed, Sep 9, 2009 at 10:07 PM, Darin Fisherda...@chromium.org wrote: Well, the problem is that the creator of the transaction and the code associated with the showModalDialog call may not be related. The showModalDialog code might normally be used outside the context of a transaction, in which case the code would normally work fine. However, if triggered from within a transaction, the dialog would be stuck. I agree that is possible. It at least meets the bar that every time this code path is executed it will behave exactly the same way (we have spec'd things before where we didn't even get this far, because of gc issues). But it would be better to not have weird edge cases like this in uncommon paths. OTOH, it seems like showModalDialog() is just a sharp edge that is likely to hurt you no matter what. Even with your proposal, unless you carefully arranged things in preparation for showModalDialog(), you could get stuck the same way. - a
[whatwg] cloneNode and HTML elements
If you call cloneNode on a media element, the state of the resulting media element seems unspecified. Should it be playing the same media resource at the same current time as the original? Similar questions arise when you clone form elements; is the state that's not visible in the DOM cloned? Who should be responsible for defining this? Rob -- He was pierced for our transgressions, he was crushed for our iniquities; the punishment that brought us peace was upon him, and by his wounds we are healed. We all, like sheep, have gone astray, each of us has turned to his own way; and the LORD has laid on him the iniquity of us all. [Isaiah 53:5-6]